Merge "Allow std::function<return_type(arg_type)> patterns in cpplint."
diff --git a/Android.mk b/Android.mk
index 1edd543..76c3aa5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,6 +23,7 @@
 #
 
 include $(art_path)/build/Android.common_path.mk
+include $(art_path)/build/Android.oat.mk
 
 # Following the example of build's dont_bother for clean targets.
 art_dont_bother := false
@@ -30,9 +31,9 @@
   art_dont_bother := true
 endif
 
-# Don't bother with tests unless there is a test-art* or build-art* target.
+# Don't bother with tests unless there is a test-art*, build-art*, or related target.
 art_test_bother := false
-ifneq (,$(filter %tests test-art% build-art%,$(MAKECMDGOALS)))
+ifneq (,$(filter %tests test-art% valgrind-test-art% build-art%,$(MAKECMDGOALS)))
   art_test_bother := true
 endif
 
@@ -41,20 +42,14 @@
 
 .PHONY: clean-oat-host
 clean-oat-host:
-	rm -f $(HOST_CORE_IMG_OUT)
-	rm -f $(HOST_CORE_OAT_OUT)
+	rm -f $(HOST_CORE_IMG_OUTS)
+	rm -f $(HOST_CORE_OAT_OUTS)
 	rm -f $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/*.odex
 ifneq ($(HOST_PREFER_32_BIT),true)
-	rm -f $(2ND_HOST_CORE_IMG_OUT)
-	rm -f $(2ND_HOST_CORE_OAT_OUT)
 	rm -f $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/*.odex
 endif
-	rm -f $(TARGET_CORE_IMG_OUT)
-	rm -f $(TARGET_CORE_OAT_OUT)
-ifdef TARGET_2ND_ARCH
-	rm -f $(2ND_TARGET_CORE_IMG_OUT)
-	rm -f $(2ND_TARGET_CORE_OAT_OUT)
-endif
+	rm -f $(TARGET_CORE_IMG_OUTS)
+	rm -f $(TARGET_CORE_OAT_OUTS)
 	rm -rf $(DEXPREOPT_PRODUCT_DIR_FULL_PATH)
 	rm -f $(TARGET_OUT_UNSTRIPPED)/system/framework/*.odex
 	rm -f $(TARGET_OUT_UNSTRIPPED)/system/framework/*/*.oat
@@ -106,10 +101,11 @@
 include $(art_path)/dex2oat/Android.mk
 include $(art_path)/disassembler/Android.mk
 include $(art_path)/oatdump/Android.mk
+include $(art_path)/imgdiag/Android.mk
 include $(art_path)/patchoat/Android.mk
 include $(art_path)/dalvikvm/Android.mk
 include $(art_path)/tools/Android.mk
-include $(art_path)/build/Android.oat.mk
+include $(art_path)/tools/dexfuzz/Android.mk
 include $(art_path)/sigchainlib/Android.mk
 
 
@@ -143,10 +139,17 @@
 
 # Sync test files to the target, depends upon all things that must be pushed to the target.
 .PHONY: test-art-target-sync
+ifeq ($(ART_TEST_ANDROID_ROOT),)
 test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
 	adb root
 	adb wait-for-device remount
 	adb sync
+else
+test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
+	adb root
+	adb wait-for-device push $(ANDROID_PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
+	adb push $(ANDROID_PRODUCT_OUT)/data /data
+endif
 
 # Undefine variable now its served its purpose.
 TEST_ART_TARGET_SYNC_DEPS :=
@@ -312,11 +315,7 @@
 
 # $(1): input jar or apk target location
 define declare-oat-target-target
-ifneq (,$(filter $(1),$(addprefix system/app/,$(addsuffix .apk,$(PRODUCT_DEX_PREOPT_PACKAGES_IN_DATA)))))
-OUT_OAT_FILE := $(call dalvik-cache-out,$(1)/classes.dex)
-else
 OUT_OAT_FILE := $(PRODUCT_OUT)/$(basename $(1)).odex
-endif
 
 ifeq ($(ONE_SHOT_MAKEFILE),)
 # ONE_SHOT_MAKEFILE is empty for a top level build and we don't want
@@ -329,9 +328,9 @@
 .PHONY: oat-target-$(1)
 oat-target-$(1): $$(OUT_OAT_FILE)
 
-$$(OUT_OAT_FILE): $(PRODUCT_OUT)/$(1) $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(DEX2OATD_DEPENDENCY)
+$$(OUT_OAT_FILE): $(PRODUCT_OUT)/$(1) $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(DEX2OAT_DEPENDENCY)
 	@mkdir -p $$(dir $$@)
-	$(DEX2OATD) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
+	$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
 		--boot-image=$(DEFAULT_DEX_PREOPT_BUILT_IMAGE) --dex-file=$(PRODUCT_OUT)/$(1) \
 		--dex-location=/$(1) --oat-file=$$@ \
 		--instruction-set=$(DEX2OAT_TARGET_ARCH) \
@@ -365,10 +364,10 @@
 build-art: build-art-host build-art-target
 
 .PHONY: build-art-host
-build-art-host:   $(HOST_OUT_EXECUTABLES)/art $(ART_HOST_DEPENDENCIES) $(HOST_CORE_IMG_OUT) $(2ND_HOST_CORE_IMG_OUT)
+build-art-host:   $(HOST_OUT_EXECUTABLES)/art $(ART_HOST_DEPENDENCIES) $(HOST_CORE_IMG_OUTS)
 
 .PHONY: build-art-target
-build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUT) $(2ND_TARGET_CORE_IMG_OUT)
+build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUTS)
 
 ########################################################################
 # targets to switch back and forth from libdvm to libart
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 39a734d..1f040d6 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -14,10 +14,10 @@
 # limitations under the License.
 #
 
-ifndef ANDROID_COMMON_MK
-ANDROID_COMMON_MK = true
+ifndef ART_ANDROID_COMMON_MK
+ART_ANDROID_COMMON_MK = true
 
-ART_TARGET_SUPPORTED_ARCH := arm arm64 mips x86 x86_64
+ART_TARGET_SUPPORTED_ARCH := arm arm64 mips mips64 x86 x86_64
 ART_HOST_SUPPORTED_ARCH := x86 x86_64
 
 ifeq (,$(filter $(TARGET_ARCH),$(ART_TARGET_SUPPORTED_ARCH)))
@@ -42,10 +42,17 @@
     $(error Do not know what to do with this multi-target configuration!)
   endif
 else
-  ART_PHONY_TEST_TARGET_SUFFIX := 32
-  2ND_ART_PHONY_TEST_TARGET_SUFFIX :=
-  ART_TARGET_ARCH_32 := $(TARGET_ARCH)
-  ART_TARGET_ARCH_64 :=
+  ifneq ($(filter %64,$(TARGET_ARCH)),)
+    ART_PHONY_TEST_TARGET_SUFFIX := 64
+    2ND_ART_PHONY_TEST_TARGET_SUFFIX :=
+    ART_TARGET_ARCH_32 :=
+    ART_TARGET_ARCH_64 := $(TARGET_ARCH)
+  else
+    ART_PHONY_TEST_TARGET_SUFFIX := 32
+    2ND_ART_PHONY_TEST_TARGET_SUFFIX :=
+    ART_TARGET_ARCH_32 := $(TARGET_ARCH)
+    ART_TARGET_ARCH_64 :=
+  endif
 endif
 
 ART_HOST_SHLIB_EXTENSION := $(HOST_SHLIB_SUFFIX)
@@ -74,4 +81,4 @@
   2ND_ART_HOST_OUT_SHARED_LIBRARIES := $(2ND_HOST_OUT_SHARED_LIBRARIES)
 endif
 
-endif # ANDROID_COMMON_MK
+endif # ART_ANDROID_COMMON_MK
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index e4be21b..cd9ed50 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -14,10 +14,11 @@
 # limitations under the License.
 #
 
-ifndef ANDROID_COMMON_BUILD_MK
-ANDROID_COMMON_BUILD_MK = true
+ifndef ART_ANDROID_COMMON_BUILD_MK
+ART_ANDROID_COMMON_BUILD_MK = true
 
 include art/build/Android.common.mk
+include art/build/Android.common_utils.mk
 
 # These can be overridden via the environment or by editing to
 # enable/disable certain build configuration.
@@ -59,58 +60,13 @@
 endif
 
 #
-# Used to enable SEA mode
-#
-ART_SEA_IR_MODE := false
-ifneq ($(wildcard art/SEA_IR_ART),)
-$(info Enabling ART_SEA_IR_MODE because of existence of art/SEA_IR_ART)
-ART_SEA_IR_MODE := true
-endif
-ifeq ($(WITH_ART_SEA_IR_MODE), true)
-ART_SEA_IR_MODE := true
-endif
-
-#
-# Used to enable portable mode
-#
-ART_USE_PORTABLE_COMPILER := false
-ifneq ($(wildcard art/USE_PORTABLE_COMPILER),)
-$(info Enabling ART_USE_PORTABLE_COMPILER because of existence of art/USE_PORTABLE_COMPILER)
-ART_USE_PORTABLE_COMPILER := true
-endif
-ifeq ($(WITH_ART_USE_PORTABLE_COMPILER),true)
-$(info Enabling ART_USE_PORTABLE_COMPILER because WITH_ART_USE_PORTABLE_COMPILER=true)
-ART_USE_PORTABLE_COMPILER := true
-endif
-
-#
-# Used to enable optimizing compiler
-#
-ART_USE_OPTIMIZING_COMPILER := false
-ifneq ($(wildcard art/USE_OPTIMIZING_COMPILER),)
-$(info Enabling ART_USE_OPTIMIZING_COMPILER because of existence of art/USE_OPTIMIZING_COMPILER)
-ART_USE_OPTIMIZING_COMPILER := true
-endif
-ifeq ($(WITH_ART_USE_OPTIMIZING_COMPILER), true)
-ART_USE_OPTIMIZING_COMPILER := true
-endif
-
-ifeq ($(ART_USE_OPTIMIZING_COMPILER),true)
-DEX2OAT_FLAGS := --compiler-backend=Optimizing
-DALVIKVM_FLAGS += -Xcompiler-option --compiler-backend=Optimizing
-endif
-
-#
 # 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
-  # Don't fail a dalvik minimal host build.
-  -include $(LLVM_ROOT_PATH)/llvm.mk
-endif
+ART_HOST_CFLAGS :=
+ART_TARGET_CFLAGS :=
 
 # Clang build support.
 
@@ -122,10 +78,24 @@
 endif
 
 # Clang on the target. Target builds use GCC by default.
+ifneq ($(USE_CLANG_PLATFORM_BUILD),)
+ART_TARGET_CLANG := $(USE_CLANG_PLATFORM_BUILD)
+else
 ART_TARGET_CLANG := false
+endif
+
+ifeq ($(TARGET_ARCH)|$(ART_TARGET_CLANG),mips|true)
+  # b/18807290, Clang generated mips assembly code for array.cc
+  # cannot be compiled by gas.
+  # b/18789639, Clang assembler cannot compile inlined assembly code in
+  # valgrind_malloc_space-inl.h:192:5: error: used $at without ".set noat"
+  $(warning Clang is disabled for the mips target)
+endif
 ART_TARGET_CLANG_arm :=
 ART_TARGET_CLANG_arm64 :=
-ART_TARGET_CLANG_mips :=
+# TODO: Enable clang mips when b/18807290 and b/18789639 are fixed.
+ART_TARGET_CLANG_mips := false
+ART_TARGET_CLANG_mips64 := false
 ART_TARGET_CLANG_x86 :=
 ART_TARGET_CLANG_x86_64 :=
 
@@ -137,34 +107,11 @@
       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 :=
 ART_TARGET_CLANG_CFLAGS_mips :=
+ART_TARGET_CLANG_CFLAGS_mips64 :=
 ART_TARGET_CLANG_CFLAGS_x86 :=
 ART_TARGET_CLANG_CFLAGS_x86_64 :=
 
@@ -174,49 +121,143 @@
   -DNVALGRIND \
   -Wno-unused-value
 
-ifeq ($(ART_SMALL_MODE),true)
-  art_cflags += -DART_SMALL_MODE=1
-endif
-
-ifeq ($(ART_SEA_IR_MODE),true)
-  art_cflags += -DART_SEA_IR_MODE=1
-endif
-
-art_non_debug_cflags := \
-  -O3
-
-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
-  art_host_non_debug_cflags += -Wframe-larger-than=2600
-  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
 
+# 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
+
+# Enable warning of converting ints to void*.
+art_clang_cflags += -Wint-to-void-pointer-cast
+
+# GCC-only warnings.
+art_gcc_cflags := -Wunused-but-set-parameter
+# Suggest const: too many false positives, but good for a trial run.
+#                  -Wsuggest-attribute=const
+# Useless casts: too many, as we need to be 32/64 agnostic, but the compiler knows.
+#                  -Wuseless-cast
+# Zero-as-null: Have to convert all NULL and "diagnostic ignore" all includes like libnativehelper
+# that are still stuck pre-C++11.
+#                  -Wzero-as-null-pointer-constant \
+# Suggest final: Have to move to a more recent GCC.
+#                  -Wsuggest-final-types
+
+ART_TARGET_CLANG_CFLAGS := $(art_clang_cflags)
+ifeq ($(ART_HOST_CLANG),true)
+  # Bug: 15446488. We don't omit the frame pointer to work around
+  # clang/libunwind bugs that cause SEGVs in run-test-004-ThreadStress.
+  ART_HOST_CFLAGS += $(art_clang_cflags) -fno-omit-frame-pointer
+else
+  ART_HOST_CFLAGS += $(art_gcc_cflags)
+endif
+ifneq ($(ART_TARGET_CLANG),true)
+  ART_TARGET_CFLAGS += $(art_gcc_cflags)
+else
+  # TODO: if we ever want to support GCC/Clang mix for multi-target products, this needs to be
+  #       split up.
+  ifeq ($(ART_TARGET_CLANG_$(TARGET_ARCH)),false)
+    ART_TARGET_CFLAGS += $(art_gcc_cflags)
+  endif
+endif
+
+# Clear local variables now their use has ended.
+art_clang_cflags :=
+art_gcc_cflags :=
+
+ART_CPP_EXTENSION := .cc
+
+ART_C_INCLUDES := \
+  external/gtest/include \
+  external/valgrind/main/include \
+  external/valgrind/main \
+  external/vixl/src \
+  external/zlib \
+
+# Base set of cflags used by all things ART.
+art_cflags := \
+  -fno-rtti \
+  -std=gnu++11 \
+  -ggdb3 \
+  -Wall \
+  -Werror \
+  -Wextra \
+  -Wstrict-aliasing \
+  -fstrict-aliasing \
+  -Wunreachable-code \
+  -Wno-conversion-null \
+  -Wredundant-decls \
+  -Wshadow \
+  -fvisibility=protected \
+  $(art_default_gc_type_cflags)
+
+# Missing declarations: too many at the moment, as we use "extern" quite a bit.
+#  -Wmissing-declarations \
+
+
+
+ifdef ART_IMT_SIZE
+  art_cflags += -DIMT_SIZE=$(ART_IMT_SIZE)
+else
+  # Default is 64
+  art_cflags += -DIMT_SIZE=64
+endif
+
+ifeq ($(ART_SMALL_MODE),true)
+  art_cflags += -DART_SMALL_MODE=1
+endif
+
+ifeq ($(ART_USE_OPTIMIZING_COMPILER),true)
+  art_cflags += -DART_USE_OPTIMIZING_COMPILER=1
+endif
+
+ifeq ($(ART_HEAP_POISONING),true)
+  art_cflags += -DART_HEAP_POISONING=1
+endif
+
+# Cflags for non-debug ART and ART tools.
+art_non_debug_cflags := \
+  -O3
+
+# Cflags for debug ART and ART tools.
 art_debug_cflags := \
-  -O1 \
+  -O2 \
   -DDYNAMIC_ANNOTATIONS_ENABLED=1 \
+  -DVIXL_DEBUG \
   -UNDEBUG
 
+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
+  ifndef SANITIZE_HOST
+    art_host_non_debug_cflags += -Wframe-larger-than=2700
+  endif
+  art_target_non_debug_cflags += -Wframe-larger-than=1728
+endif
+
 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) -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
@@ -236,80 +277,25 @@
 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.
-ifeq ($(ART_HOST_CLANG),true)
-  ART_HOST_CFLAGS += -fcolor-diagnostics
-endif
-ifeq ($(ART_TARGET_CLANG),true)
-  ART_TARGET_CFLAGS += -fcolor-diagnostics
-endif
-
-ART_TARGET_LDFLAGS :=
-ifeq ($(TARGET_CPU_SMP),true)
-  ART_TARGET_CFLAGS += -DANDROID_SMP=1
-else
-  ifeq ($(TARGET_CPU_SMP),false)
-    ART_TARGET_CFLAGS += -DANDROID_SMP=0
-  else
-    $(warning TARGET_CPU_SMP should be (true|false), found $(TARGET_CPU_SMP))
-    # Make sure we emit barriers for the worst case.
-    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
@@ -323,16 +309,15 @@
     LOCAL_CFLAGS += $(ART_TARGET_NON_DEBUG_CFLAGS)
   endif
 
-  # TODO: Also set when ART_TARGET_CLANG_$(arch)!=false and ART_TARGET_CLANG==true
+  LOCAL_CLANG_CFLAGS := $(ART_TARGET_CLANG_CFLAGS)
   $(foreach arch,$(ART_SUPPORTED_ARCH),
-    ifeq ($$(ART_TARGET_CLANG_$(arch)),true)
-      LOCAL_CFLAGS_$(arch) += $$(ART_TARGET_CLANG_CFLAGS_$(arch))
-  endif)
+    LOCAL_CLANG_CFLAGS_$(arch) += $$(ART_TARGET_CLANG_CFLAGS_$(arch)))
 
   # Clear locally used variables.
   art_target_cflags_ndebug_or_debug :=
 endef
 
+# Support for disabling certain builds.
 ART_BUILD_TARGET := false
 ART_BUILD_HOST := false
 ART_BUILD_NDEBUG := false
@@ -354,12 +339,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
+endif # ART_ANDROID_COMMON_BUILD_MK
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 10695b6..e0c0b0c 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -14,8 +14,8 @@
 # limitations under the License.
 #
 
-ifndef ANDROID_COMMON_PATH_MK
-ANDROID_COMMON_PATH_MK := true
+ifndef ART_ANDROID_COMMON_PATH_MK
+ART_ANDROID_COMMON_PATH_MK := true
 
 include art/build/Android.common.mk
 
@@ -47,25 +47,33 @@
 2ND_TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
 endif
 
+CORE_OAT_SUFFIX := .oat
+
 # Core.oat locations under the out directory.
-HOST_CORE_OAT_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.oat
+HOST_CORE_OAT_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core
 ifneq ($(HOST_PREFER_32_BIT),true)
-2ND_HOST_CORE_OAT_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core.oat
+2ND_HOST_CORE_OAT_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core
 endif
-TARGET_CORE_OAT_OUT := $(ART_TARGET_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core.oat
+HOST_CORE_OAT_OUTS :=
+TARGET_CORE_OAT_OUT_BASE := $(ART_TARGET_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core
 ifdef TARGET_2ND_ARCH
-2ND_TARGET_CORE_OAT_OUT := $(ART_TARGET_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
+2ND_TARGET_CORE_OAT_OUT_BASE := $(ART_TARGET_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core
 endif
+TARGET_CORE_OAT_OUTS :=
+
+CORE_IMG_SUFFIX := .art
 
 # Core.art locations under the out directory.
-HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.art
+HOST_CORE_IMG_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core
 ifneq ($(HOST_PREFER_32_BIT),true)
-2ND_HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core.art
+2ND_HOST_CORE_IMG_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core
 endif
-TARGET_CORE_IMG_OUT := $(ART_TARGET_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core.art
+HOST_CORE_IMG_OUTS :=
+TARGET_CORE_IMG_OUT_BASE := $(ART_TARGET_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core
 ifdef TARGET_2ND_ARCH
-2ND_TARGET_CORE_IMG_OUT := $(ART_TARGET_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.art
+2ND_TARGET_CORE_IMG_OUT_BASE := $(ART_TARGET_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core
 endif
+TARGET_CORE_IMG_OUTS :=
 
 # Oat location of core.art.
 HOST_CORE_IMG_LOCATION := $(HOST_OUT_JAVA_LIBRARIES)/core.art
@@ -80,4 +88,4 @@
 
 HOST_CORE_DEX_FILES   := $(foreach jar,$(HOST_CORE_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
 TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
-endif # ANDROID_COMMON_PATH_MK
+endif # ART_ANDROID_COMMON_PATH_MK
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index ee72706..da50d53 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -14,8 +14,8 @@
 # limitations under the License.
 #
 
-ifndef ANDROID_COMMON_TEST_MK
-ANDROID_COMMON_TEST_MK = true
+ifndef ART_ANDROID_COMMON_TEST_MK
+ART_ANDROID_COMMON_TEST_MK = true
 
 include art/build/Android.common_path.mk
 
@@ -25,21 +25,7 @@
 
 # List of known broken tests that we won't attempt to execute. The test name must be the full
 # rule name such as test-art-host-oat-optimizing-HelloWorld64.
-ART_TEST_KNOWN_BROKEN := \
-  test-art-target-run-test-gcstress-optimizing-prebuild-004-SignalTest32 \
-  test-art-target-run-test-gcstress-optimizing-norelocate-004-SignalTest32 \
-  test-art-target-run-test-gcstress-default-prebuild-004-SignalTest32 \
-  test-art-target-run-test-gcstress-default-norelocate-004-SignalTest32 \
-  test-art-target-run-test-gcstress-optimizing-relocate-004-SignalTest32 \
-  test-art-target-run-test-gcstress-default-relocate-004-SignalTest32 \
-  test-art-target-run-test-gcstress-optimizing-no-prebuild-004-SignalTest32 \
-  test-art-target-run-test-gcstress-default-no-prebuild-004-SignalTest32 \
-  test-art-host-run-test-gcstress-default-prebuild-114-ParallelGC32 \
-  test-art-host-run-test-gcstress-interpreter-prebuild-114-ParallelGC32 \
-  test-art-host-run-test-gcstress-optimizing-prebuild-114-ParallelGC32 \
-  test-art-host-run-test-gcstress-default-prebuild-114-ParallelGC64 \
-  test-art-host-run-test-gcstress-interpreter-prebuild-114-ParallelGC64 \
-  test-art-host-run-test-gcstress-optimizing-prebuild-114-ParallelGC64
+ART_TEST_KNOWN_BROKEN :=
 
 # Failing valgrind tests.
 # Note: *all* 64b tests involving the runtime do not work currently. b/15170219.
@@ -63,6 +49,12 @@
 # Do you want optimizing compiler tests run?
 ART_TEST_OPTIMIZING ?= $(ART_TEST_FULL)
 
+# Do we want to test a PIC-compiled core image?
+ART_TEST_PIC_IMAGE ?= $(ART_TEST_FULL)
+
+# Do we want to test PIC-compiled tests ("apps")?
+ART_TEST_PIC_TEST ?= $(ART_TEST_FULL)
+
 # Do you want tracing tests run?
 ART_TEST_TRACE ?= $(ART_TEST_FULL)
 
@@ -78,6 +70,9 @@
 # Do you want run-tests with relocation disabled run?
 ART_TEST_RUN_TEST_NO_RELOCATE ?= $(ART_TEST_FULL)
 
+# Do you want run-tests with prebuilding?
+ART_TEST_RUN_TEST_PREBUILD ?= true
+
 # Do you want run-tests with no prebuilding enabled run?
 ART_TEST_RUN_TEST_NO_PREBUILD ?= $(ART_TEST_FULL)
 
@@ -90,6 +85,15 @@
 # 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 run-tests with the host/target's second arch?
+ART_TEST_RUN_TEST_2ND_ARCH ?= true
+
 # Do you want failed tests to have their artifacts cleaned up?
 ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true
 
@@ -179,4 +183,4 @@
   endif
 endef
 
-endif # ANDROID_COMMON_TEST_MK
+endif # ART_ANDROID_COMMON_TEST_MK
diff --git a/build/Android.common_utils.mk b/build/Android.common_utils.mk
new file mode 100644
index 0000000..8069c3a
--- /dev/null
+++ b/build/Android.common_utils.mk
@@ -0,0 +1,26 @@
+#
+# 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_ANDROID_COMMON_UTILS_MK
+ART_ANDROID_COMMON_UTILS_MK = true
+
+#
+# Convert a string into an uppercase string.
+#
+# $(1): a string which should be made uppercase
+art-string-to-uppercase = $(shell echo $(1) | tr '[:lower:]' '[:upper:]')
+
+endif # ART_ANDROID_COMMON_UTILS_MK
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index d887acd..ef9e7cd 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -20,9 +20,6 @@
 ART_TARGET_EXECUTABLES ?=
 
 ART_EXECUTABLES_CFLAGS :=
-ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-  ART_EXECUTABLES_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
-endif
 
 # $(1): executable ("d" will be appended for debug version)
 # $(2): source
@@ -50,13 +47,15 @@
   art_target_or_host := $(5)
   art_ndebug_or_debug := $(6)
   art_multilib := $(7)
+  art_out_binary_name :=
 
   include $(CLEAR_VARS)
   LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
   LOCAL_MODULE_TAGS := optional
   LOCAL_SRC_FILES := $$(art_source)
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime $$(art_c_includes)
+  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime art/cmdline $$(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 +64,25 @@
   endif
 
   LOCAL_CFLAGS := $(ART_EXECUTABLES_CFLAGS)
+  # Mac OS linker doesn't understand --export-dynamic.
+  ifneq ($$(HOST_OS)-$$(art_target_or_host),darwin-host)
+    LOCAL_LDFLAGS := -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)
@@ -86,21 +92,114 @@
   endif
 
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_utils.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.executable.mk
 
   ifeq ($$(art_target_or_host),target)
     LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
   endif
+
   LOCAL_MULTILIB := $$(art_multilib)
+  art_out_binary_name := $$(LOCAL_MODULE)
+
+  # If multilib=both (potentially building both 32-bit and 64-bit), need to provide stem.
+  ifeq ($$(art_multilib),both)
+    # Set up a 32-bit/64-bit stem if we are building both binaries.
+    # In this case, the 32-bit binary has an additional 32-bit suffix.
+    LOCAL_MODULE_STEM_32 := $$(LOCAL_MODULE)32
+    LOCAL_MODULE_STEM_64 := $$(LOCAL_MODULE)
+
+    # Remember the binary names so we can add them to the global art executables list later.
+    art_out_binary_name := $$(LOCAL_MODULE_STEM_32) $$(LOCAL_MODULE_STEM_64)
+
+    # For single-architecture targets, remove any binary name suffixes.
+    ifeq ($$(art_target_or_host),target)
+      ifeq (,$(TARGET_2ND_ARCH))
+        LOCAL_MODULE_STEM_32 := $$(LOCAL_MODULE)
+        art_out_binary_name := $$(LOCAL_MODULE)
+      endif
+    endif
+
+    # For single-architecture hosts, remove any binary name suffixes.
+    ifeq ($$(art_target_or_host),host)
+      ifeq (,$(HOST_2ND_ARCH))
+        LOCAL_MODULE_STEM_32 := $$(LOCAL_MODULE)
+        art_out_binary_name := $$(LOCAL_MODULE)
+      endif
+    endif
+  endif
 
   include external/libcxx/libcxx.mk
   ifeq ($$(art_target_or_host),target)
     include $(BUILD_EXECUTABLE)
-    ART_TARGET_EXECUTABLES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_EXECUTABLES)/$$(LOCAL_MODULE)
+    ART_TARGET_EXECUTABLES := $(ART_TARGET_EXECUTABLES) $$(foreach name,$$(art_out_binary_name),$(TARGET_OUT_EXECUTABLES)/$$(name))
   else # host
     LOCAL_IS_HOST_MODULE := true
     include $(BUILD_HOST_EXECUTABLE)
-    ART_HOST_EXECUTABLES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_EXECUTABLES)/$$(LOCAL_MODULE)
+    ART_HOST_EXECUTABLES := $(ART_HOST_EXECUTABLES) $$(foreach name,$$(art_out_binary_name),$(HOST_OUT_EXECUTABLES)/$$(name))
   endif
 
+  # Clear out local variables now that we're done with them.
+  art_executable :=
+  art_source :=
+  art_shared_libraries :=
+  art_c_includes :=
+  art_target_or_host :=
+  art_ndebug_or_debug :=
+  art_multilib :=
+  art_out_binary_name :=
+
+endef
+
+#
+# Build many art executables from multiple variations (debug/ndebug, host/target, 32/64bit).
+# By default only either 32-bit or 64-bit is built (but not both -- see multilib arg).
+# All other variations are gated by ANDROID_BUILD_(TARGET|HOST)_[N]DEBUG.
+# The result must be eval-uated.
+#
+# $(1): executable name
+# $(2): source files
+# $(3): library dependencies (common); debug prefix is added on as necessary automatically.
+# $(4): library dependencies (target only)
+# $(5): library dependencies (host only)
+# $(6): extra include directories
+# $(7): multilib (default: empty), valid values: {,32,64,both})
+define build-art-multi-executable
+  $(foreach debug_flavor,ndebug debug,
+    $(foreach target_flavor,host target,
+      art-multi-binary-name := $(1)
+      art-multi-source-files := $(2)
+      art-multi-lib-dependencies := $(3)
+      art-multi-lib-dependencies-target := $(4)
+      art-multi-lib-dependencies-host := $(5)
+      art-multi-include-extra := $(6)
+      art-multi-multilib := $(7)
+
+      # Add either -host or -target specific lib dependencies to the lib dependencies.
+      art-multi-lib-dependencies += $$(art-multi-lib-dependencies-$(target_flavor))
+
+      # Replace libart- prefix with libartd- for debug flavor.
+      ifeq ($(debug_flavor),debug)
+        art-multi-lib-dependencies := $$(subst libart-,libartd-,$$(art-multi-lib-dependencies))
+      endif
+
+      # Build the env guard var name, e.g. ART_BUILD_HOST_NDEBUG.
+      art-multi-env-guard := $$(call art-string-to-uppercase,ART_BUILD_$(target_flavor)_$(debug_flavor))
+
+      # Build the art executable only if the corresponding env guard was set.
+      ifeq ($$($$(art-multi-env-guard)),true)
+        $$(eval $$(call build-art-executable,$$(art-multi-binary-name),$$(art-multi-source-files),$$(art-multi-lib-dependencies),$$(art-multi-include-extra),$(target_flavor),$(debug_flavor),$$(art-multi-multilib)))
+      endif
+
+      # Clear locals now they've served their purpose.
+      art-multi-binary-name :=
+      art-multi-source-files :=
+      art-multi-lib-dependencies :=
+      art-multi-lib-dependencies-target :=
+      art-multi-lib-dependencies-host :=
+      art-multi-include-extra :=
+      art-multi-multilib :=
+      art-multi-env-guard :=
+    )
+  )
 endef
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index af43a3c..efb45c7 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -48,7 +48,7 @@
 # Dex file dependencies for each gtest.
 ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MyClass Nested Statics StaticsFromCode
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod
-ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Nested
+ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
 ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
 ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
 ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods
@@ -59,22 +59,44 @@
 ART_GTEST_transaction_test_DEX_DEPS := Transaction
 
 # The elf writer test has dependencies on core.oat.
-ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT)
-ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_OAT_OUT) $(2ND_TARGET_CORE_OAT_OUT)
-ART_GTEST_jni_internal_test_TARGET_DEPS := $(TARGET_CORE_DEX_FILES)
-ART_GTEST_proxy_test_TARGET_DEPS := $(TARGET_CORE_DEX_FILES)
-ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT)
+ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
+ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_default_no-pic_64) $(TARGET_CORE_IMAGE_default_no-pic_32)
+
+# TODO: document why this is needed.
+ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
+
+# The imgdiag test has dependencies on core.oat since it needs to load it during the test.
+# For the host, also add the installed tool (in the base size, that should suffice). For the
+# target, just the module is fine, the sync will happen late enough.
+ART_GTEST_imgdiag_test_HOST_DEPS := \
+  $(HOST_CORE_IMAGE_default_no-pic_64) \
+  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_OUT_EXECUTABLES)/imgdiagd
+ART_GTEST_imgdiag_test_TARGET_DEPS := \
+  $(TARGET_CORE_IMAGE_default_no-pic_64) \
+  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  imgdiagd
 
 # The path for which all the source files are relative, not actually the current directory.
 LOCAL_PATH := art
 
 RUNTIME_GTEST_COMMON_SRC_FILES := \
+  imgdiag/imgdiag_test.cc \
   runtime/arch/arch_test.cc \
+  runtime/arch/instruction_set_test.cc \
+  runtime/arch/instruction_set_features_test.cc \
   runtime/arch/memcmp16_test.cc \
   runtime/arch/stub_test.cc \
+  runtime/arch/arm/instruction_set_features_arm_test.cc \
+  runtime/arch/arm64/instruction_set_features_arm64_test.cc \
+  runtime/arch/mips/instruction_set_features_mips_test.cc \
+  runtime/arch/mips64/instruction_set_features_mips64_test.cc \
+  runtime/arch/x86/instruction_set_features_x86_test.cc \
+  runtime/arch/x86_64/instruction_set_features_x86_64_test.cc \
   runtime/barrier_test.cc \
   runtime/base/bit_field_test.cc \
   runtime/base/bit_vector_test.cc \
+  runtime/base/hash_set_test.cc \
   runtime/base/hex_dump_test.cc \
   runtime/base/histogram_test.cc \
   runtime/base/mutex_test.cc \
@@ -82,10 +104,6 @@
   runtime/base/stringprintf_test.cc \
   runtime/base/timing_logger_test.cc \
   runtime/base/unix_file/fd_file_test.cc \
-  runtime/base/unix_file/mapped_file_test.cc \
-  runtime/base/unix_file/null_file_test.cc \
-  runtime/base/unix_file/random_access_file_utils_test.cc \
-  runtime/base/unix_file/string_file_test.cc \
   runtime/class_linker_test.cc \
   runtime/dex_file_test.cc \
   runtime/dex_file_verifier_test.cc \
@@ -98,6 +116,7 @@
   runtime/gc/accounting/card_table_test.cc \
   runtime/gc/accounting/space_bitmap_test.cc \
   runtime/gc/heap_test.cc \
+  runtime/gc/reference_queue_test.cc \
   runtime/gc/space/dlmalloc_space_base_test.cc \
   runtime/gc/space/dlmalloc_space_static_test.cc \
   runtime/gc/space/dlmalloc_space_random_test.cc \
@@ -105,12 +124,14 @@
   runtime/gc/space/rosalloc_space_static_test.cc \
   runtime/gc/space/rosalloc_space_random_test.cc \
   runtime/gc/space/large_object_space_test.cc \
+  runtime/gc/task_processor_test.cc \
   runtime/gtest_test.cc \
   runtime/handle_scope_test.cc \
   runtime/indenter_test.cc \
   runtime/indirect_reference_table_test.cc \
-  runtime/instruction_set_test.cc \
   runtime/intern_table_test.cc \
+  runtime/interpreter/safe_math_test.cc \
+  runtime/java_vm_ext_test.cc \
   runtime/leb128_test.cc \
   runtime/mem_map_test.cc \
   runtime/mirror/dex_cache_test.cc \
@@ -139,9 +160,10 @@
   compiler/image_test.cc \
   compiler/jni/jni_compiler_test.cc \
   compiler/oat_test.cc \
+  compiler/optimizing/bounds_check_elimination_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 \
@@ -161,18 +183,11 @@
   compiler/output_stream_test.cc \
   compiler/utils/arena_allocator_test.cc \
   compiler/utils/dedupe_set_test.cc \
+  compiler/utils/swap_space_test.cc \
   compiler/utils/arm/managed_register_arm_test.cc \
   compiler/utils/arm64/managed_register_arm64_test.cc \
   compiler/utils/x86/managed_register_x86_test.cc \
 
-ifeq ($(ART_SEA_IR_MODE),true)
-COMPILER_GTEST_COMMON_SRC_FILES += \
-  compiler/utils/scoped_hashtable_test.cc \
-  compiler/sea_ir/types/type_data_test.cc \
-  compiler/sea_ir/types/type_inference_visitor_test.cc \
-  compiler/sea_ir/ir/regions_test.cc
-endif
-
 RUNTIME_GTEST_TARGET_SRC_FILES := \
   $(RUNTIME_GTEST_COMMON_SRC_FILES)
 
@@ -184,27 +199,26 @@
 
 COMPILER_GTEST_HOST_SRC_FILES := \
   $(COMPILER_GTEST_COMMON_SRC_FILES) \
-  compiler/utils//assembler_thumb_test.cc \
+  compiler/utils/arm/assembler_arm32_test.cc \
+  compiler/utils/arm/assembler_thumb2_test.cc \
+  compiler/utils/assembler_thumb_test.cc \
   compiler/utils/x86/assembler_x86_test.cc \
   compiler/utils/x86_64/assembler_x86_64_test.cc
 
 ART_TEST_CFLAGS :=
-ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-  ART_TEST_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
-endif
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := libart-gtest
 LOCAL_MODULE_TAGS := optional
 LOCAL_CPP_EXTENSION := cc
-LOCAL_CFLAGS := $(ART_TARGET_CFLAGS)
 LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
 LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler
-LOCAL_SHARED_LIBRARIES := libcutils libartd libartd-compiler libdl
-LOCAL_STATIC_LIBRARIES += libgtest_libc++
-LOCAL_CLANG := $(ART_TARGET_CLANG)
+LOCAL_SHARED_LIBRARIES := libartd libartd-compiler libdl
+LOCAL_STATIC_LIBRARIES += libgtest
 LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
 LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
+$(eval $(call set-target-local-clang-vars))
+$(eval $(call set-target-local-cflags-vars,debug))
 include external/libcxx/libcxx.mk
 include $(BUILD_SHARED_LIBRARY)
 
@@ -216,11 +230,7 @@
 LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
 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_host
 LOCAL_LDLIBS += -ldl -lpthread
 LOCAL_MULTILIB := both
 LOCAL_CLANG := $(ART_HOST_CLANG)
@@ -240,9 +250,15 @@
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
 
+ART_GTEST_TARGET_ANDROID_ROOT := '/system'
+ifneq ($(ART_TEST_ANDROID_ROOT),)
+  ART_GTEST_TARGET_ANDROID_ROOT := $(ART_TEST_ANDROID_ROOT)
+endif
+
 # Define a make rule for a target device gtest.
 # $(1): gtest name - the name of the test we're building such as leb128_test.
 # $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+# $(3): LD_LIBRARY_PATH or undefined - used in case libartd.so is not in /system/lib/
 define define-art-gtest-rule-target
   gtest_rule := test-art-target-gtest-$(1)$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
 
@@ -252,7 +268,8 @@
     $$(ART_GTEST_$(1)_TARGET_DEPS) \
     $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_TARGET_GTEST_$(file)_DEX)) \
     $$(ART_TARGET_NATIVETEST_OUT)/$$(TARGET_$(2)ARCH)/$(1) \
-    $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
+    $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \
+    $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar
 
 .PHONY: $$(gtest_rule)
 $$(gtest_rule): test-art-target-sync
@@ -260,11 +277,12 @@
 	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID
 	$(hide) adb shell chmod 755 $(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  (adb shell "$(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID" \
+	  (adb shell "LD_LIBRARY_PATH=$(3) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
+	    $(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID" \
 	  && (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 +305,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 +356,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
@@ -353,17 +372,31 @@
   ifeq ($$(art_target_or_host),target)
     $$(eval $$(call set-target-local-clang-vars))
     $$(eval $$(call set-target-local-cflags-vars,debug))
-    LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils libvixl
+    LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils libvixld
     LOCAL_MODULE_PATH_32 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_32)
     LOCAL_MODULE_PATH_64 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_64)
     LOCAL_MULTILIB := both
     include $$(BUILD_EXECUTABLE)
+    library_path :=
+    2nd_library_path :=
+    ifneq ($$(ART_TEST_ANDROID_ROOT),)
+      ifdef TARGET_2ND_ARCH
+        2nd_library_path := $$(ART_TEST_ANDROID_ROOT)/lib
+        library_path := $$(ART_TEST_ANDROID_ROOT)/lib64
+      else
+        ifneq ($(filter %64,$(TARGET_ARCH)),)
+          library_path := $$(ART_TEST_ANDROID_ROOT)/lib64
+        else
+          library_path := $$(ART_TEST_ANDROID_ROOT)/lib
+        endif
+      endif
+    endif
 
     ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
     ifdef TARGET_2ND_ARCH
-      $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),2ND_))
+      $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),2ND_,$$(2nd_library_path)))
     endif
-    $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),))
+    $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),,$$(library_path)))
 
     # A rule to run the different architecture versions of the gtest.
 .PHONY: test-art-target-gtest-$$(art_gtest_name)
@@ -375,9 +408,8 @@
   else # host
     LOCAL_CLANG := $$(ART_HOST_CLANG)
     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_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libziparchive-host libz-host libvixld
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -lpthread -ldl
     LOCAL_IS_HOST_MODULE := true
     LOCAL_MULTILIB := both
     LOCAL_MODULE_STEM_32 := $$(art_gtest_name)32
@@ -411,6 +443,8 @@
   art_gtest_extra_c_includes :=
   art_gtest_extra_shared_libraries :=
   art_gtest_name :=
+  library_path :=
+  2nd_library_path :=
 endef  # define-art-gtest
 
 ifeq ($(ART_BUILD_TARGET),true)
@@ -502,6 +536,7 @@
 ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
+ART_GTEST_TARGET_ANDROID_ROOT :=
 ART_GTEST_class_linker_test_DEX_DEPS :=
 ART_GTEST_compiler_driver_test_DEX_DEPS :=
 ART_GTEST_dex_file_test_DEX_DEPS :=
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 1c462eb..8d49565 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -21,76 +21,253 @@
 # The main rules to build the default "boot" image are in
 # build/core/dex_preopt_libart.mk
 
-include art/build/Android.common_path.mk
+include art/build/Android.common_build.mk
+
+ifeq ($(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
+  DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
+endif
+ifeq ($($(HOST_2ND_ARCH_VAR_PREFIX)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
+  $(HOST_2ND_ARCH_VAR_PREFIX)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
+endif
 
 # Use dex2oat debug version for better error reporting
-# $(1): 2ND_ or undefined, 2ND_ for 32-bit host builds.
+# $(1): compiler - default, optimizing or interpreter.
+# $(2): pic/no-pic
+# $(3): 2ND_ or undefined, 2ND_ for 32-bit host builds.
+# $(4): wrapper, e.g., valgrind.
+# $(5): dex2oat suffix, e.g, valgrind requires 32 right now.
 # NB depending on HOST_CORE_DEX_LOCATIONS so we are sure to have the dex files in frameworks for
 # run-test --no-image
 define create-core-oat-host-rules
-$$($(1)HOST_CORE_IMG_OUT): $$(HOST_CORE_DEX_LOCATIONS) $$(DEX2OATD_DEPENDENCY)
+  core_compile_options :=
+  core_image_name :=
+  core_oat_name :=
+  core_infix :=
+  core_pic_infix :=
+  core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
+
+  # With the optimizing compiler, we want to rerun dex2oat whenever there is
+  # a dex2oat change to catch regressions early.
+  ifeq ($(ART_USE_OPTIMIZING_COMPILER), true)
+    core_dex2oat_dependency := $(DEX2OAT)
+  endif
+
+  ifeq ($(1),default)
+    core_compile_options += --compiler-backend=Quick
+  endif
+  ifeq ($(1),optimizing)
+    core_compile_options += --compiler-backend=Optimizing
+    core_dex2oat_dependency := $(DEX2OAT)
+    core_infix := -optimizing
+  endif
+  ifeq ($(1),interpreter)
+    core_compile_options += --compiler-filter=interpret-only
+    core_infix := -interpreter
+  endif
+  ifeq ($(1),default)
+    # Default has no infix, no compile options.
+  endif
+  ifneq ($(filter-out default interpreter optimizing,$(1)),)
+    #Technically this test is not precise, but hopefully good enough.
+    $$(error found $(1) expected default, interpreter or optimizing)
+  endif
+
+  ifeq ($(2),pic)
+    core_compile_options += --compile-pic
+    core_pic_infix := -pic
+  endif
+  ifeq ($(2),no-pic)
+    # No change for non-pic
+  endif
+  ifneq ($(filter-out pic no-pic,$(2)),)
+    # Technically this test is not precise, but hopefully good enough.
+    $$(error found $(2) expected pic or no-pic)
+  endif
+
+  core_image_name := $($(3)HOST_CORE_IMG_OUT_BASE)$$(core_infix)$$(core_pic_infix)$(4)$(CORE_IMG_SUFFIX)
+  core_oat_name := $($(3)HOST_CORE_OAT_OUT_BASE)$$(core_infix)$$(core_pic_infix)$(4)$(CORE_OAT_SUFFIX)
+
+  # Using the bitness suffix makes it easier to add as a dependency for the run-test mk.
+  ifeq ($(3),)
+    $(4)HOST_CORE_IMAGE_$(1)_$(2)_64 := $$(core_image_name)
+  else
+    $(4)HOST_CORE_IMAGE_$(1)_$(2)_32 := $$(core_image_name)
+  endif
+  $(4)HOST_CORE_IMG_OUTS += $$(core_image_name)
+  $(4)HOST_CORE_OAT_OUTS += $$(core_oat_name)
+
+  # If we have a wrapper, make the target phony.
+  ifneq ($(4),)
+.PHONY: $$(core_image_name)
+  endif
+$$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
+$$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
+$$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
+$$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
 	@echo "host dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
-	$$(hide) $$(DEX2OATD) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
+	$$(hide) $(4) $$(DEX2OAT)$(5) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
+	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
 	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(HOST_CORE_DEX_FILES)) \
-	  $$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$($(1)HOST_CORE_OAT_OUT) \
-	  --oat-location=$$($(1)HOST_CORE_OAT) --image=$$($(1)HOST_CORE_IMG_OUT) \
-	  --base=$$(LIBART_IMG_HOST_BASE_ADDRESS) --instruction-set=$$($(1)ART_HOST_ARCH) \
-	  --instruction-set-features=$$($(1)HOST_INSTRUCTION_SET_FEATURES) \
-	  --host --android-root=$$(HOST_OUT) --include-patch-information
+	  $$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
+	  --oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
+	  --base=$$(LIBART_IMG_HOST_BASE_ADDRESS) --instruction-set=$$($(3)ART_HOST_ARCH) \
+	  --instruction-set-features=$$($(3)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES) \
+	  --host --android-root=$$(HOST_OUT) --include-patch-information \
+	  $$(PRIVATE_CORE_COMPILE_OPTIONS)
 
-# This "renaming" eases declaration in art/Android.mk
-HOST_CORE_IMG_OUT$($(1)ART_PHONY_TEST_HOST_SUFFIX) := $($(1)HOST_CORE_IMG_OUT)
+$$(core_oat_name): $$(core_image_name)
 
-$$($(1)HOST_CORE_OAT_OUT): $$($(1)HOST_CORE_IMG_OUT)
+  # Clean up locally used variables.
+  core_dex2oat_dependency :=
+  core_compile_options :=
+  core_image_name :=
+  core_oat_name :=
+  core_infix :=
+  core_pic_infix :=
 endef  # create-core-oat-host-rules
 
-$(eval $(call create-core-oat-host-rules,))
-ifneq ($(HOST_PREFER_32_BIT),true)
-$(eval $(call create-core-oat-host-rules,2ND_))
-endif
+# $(1): compiler - default, optimizing or interpreter.
+# $(2): wrapper.
+# $(3): dex2oat suffix.
+define create-core-oat-host-rule-combination
+  $(call create-core-oat-host-rules,$(1),no-pic,,$(2),$(3))
+  $(call create-core-oat-host-rules,$(1),pic,,$(2),$(3))
+
+  ifneq ($(HOST_PREFER_32_BIT),true)
+    $(call create-core-oat-host-rules,$(1),no-pic,2ND_,$(2),$(3))
+    $(call create-core-oat-host-rules,$(1),pic,2ND_,$(2),$(3))
+  endif
+endef
+
+$(eval $(call create-core-oat-host-rule-combination,default,,))
+$(eval $(call create-core-oat-host-rule-combination,optimizing,,))
+$(eval $(call create-core-oat-host-rule-combination,interpreter,,))
+
+valgrindHOST_CORE_IMG_OUTS :=
+valgrindHOST_CORE_OAT_OUTS :=
+$(eval $(call create-core-oat-host-rule-combination,default,valgrind,32))
+$(eval $(call create-core-oat-host-rule-combination,optimizing,valgrind,32))
+$(eval $(call create-core-oat-host-rule-combination,interpreter,valgrind,32))
+
+valgrind-test-art-host-dex2oat-host: $(valgrindHOST_CORE_IMG_OUTS)
 
 define create-core-oat-target-rules
-$$($(1)TARGET_CORE_IMG_OUT): $$($(1)TARGET_CORE_DEX_FILES) $$(DEX2OATD_DEPENDENCY)
+  core_compile_options :=
+  core_image_name :=
+  core_oat_name :=
+  core_infix :=
+  core_pic_infix :=
+  core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
+
+  # With the optimizing compiler, we want to rerun dex2oat whenever there is
+  # a dex2oat change to catch regressions early.
+  ifeq ($(ART_USE_OPTIMIZING_COMPILER), true)
+    core_dex2oat_dependency := $(DEX2OAT)
+  endif
+
+  ifeq ($(1),default)
+    core_compile_options += --compiler-backend=Quick
+  endif
+  ifeq ($(1),optimizing)
+    core_compile_options += --compiler-backend=Optimizing
+    core_dex2oat_dependency := $(DEX2OAT)
+    core_infix := -optimizing
+  endif
+  ifeq ($(1),interpreter)
+    core_compile_options += --compiler-filter=interpret-only
+    core_infix := -interpreter
+  endif
+  ifeq ($(1),default)
+    # Default has no infix, no compile options.
+  endif
+  ifneq ($(filter-out default interpreter optimizing,$(1)),)
+    # Technically this test is not precise, but hopefully good enough.
+    $$(error found $(1) expected default, interpreter or optimizing)
+  endif
+
+  ifeq ($(2),pic)
+    core_compile_options += --compile-pic
+    core_pic_infix := -pic
+  endif
+  ifeq ($(2),no-pic)
+    # No change for non-pic
+  endif
+  ifneq ($(filter-out pic no-pic,$(2)),)
+    #Technically this test is not precise, but hopefully good enough.
+    $$(error found $(2) expected pic or no-pic)
+  endif
+
+  core_image_name := $($(3)TARGET_CORE_IMG_OUT_BASE)$$(core_infix)$$(core_pic_infix)$(4)$(CORE_IMG_SUFFIX)
+  core_oat_name := $($(3)TARGET_CORE_OAT_OUT_BASE)$$(core_infix)$$(core_pic_infix)$(4)$(CORE_OAT_SUFFIX)
+
+  # Using the bitness suffix makes it easier to add as a dependency for the run-test mk.
+  ifeq ($(3),)
+    ifdef TARGET_2ND_ARCH
+      $(4)TARGET_CORE_IMAGE_$(1)_$(2)_64 := $$(core_image_name)
+    else
+      $(4)TARGET_CORE_IMAGE_$(1)_$(2)_32 := $$(core_image_name)
+    endif
+  else
+    $(4)TARGET_CORE_IMAGE_$(1)_$(2)_32 := $$(core_image_name)
+  endif
+  $(4)TARGET_CORE_IMG_OUTS += $$(core_image_name)
+  $(4)TARGET_CORE_OAT_OUTS += $$(core_oat_name)
+
+  # If we have a wrapper, make the target phony.
+  ifneq ($(4),)
+.PHONY: $$(core_image_name)
+  endif
+$$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
+$$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
+$$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
+$$(core_image_name): $$(TARGET_CORE_DEX_FILES) $$(core_dex2oat_dependency)
 	@echo "target dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
-	$$(hide) $$(DEX2OATD) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
+	$$(hide) $(4) $$(DEX2OAT)$(5) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
+	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
 	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(TARGET_CORE_DEX_FILES)) \
-	  $$(addprefix --dex-location=,$$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$$($(1)TARGET_CORE_OAT_OUT) \
-	  --oat-location=$$($(1)TARGET_CORE_OAT) --image=$$($(1)TARGET_CORE_IMG_OUT) \
-	  --base=$$(LIBART_IMG_TARGET_BASE_ADDRESS) --instruction-set=$$($(1)TARGET_ARCH) \
-	  --instruction-set-features=$$($(1)TARGET_INSTRUCTION_SET_FEATURES) \
-	  --android-root=$$(PRODUCT_OUT)/system --include-patch-information
+	  $$(addprefix --dex-location=,$$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
+	  --oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
+	  --base=$$(LIBART_IMG_TARGET_BASE_ADDRESS) --instruction-set=$$($(3)TARGET_ARCH) \
+	  --instruction-set-features=$$($(3)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
+	  --android-root=$$(PRODUCT_OUT)/system --include-patch-information \
+	  $$(PRIVATE_CORE_COMPILE_OPTIONS) || (rm $$(PRIVATE_CORE_OAT_NAME); exit 1)
 
-# This "renaming" eases declaration in art/Android.mk
-TARGET_CORE_IMG_OUT$($(1)ART_PHONY_TEST_TARGET_SUFFIX) := $($(1)TARGET_CORE_IMG_OUT)
+$$(core_oat_name): $$(core_image_name)
 
-$$($(1)TARGET_CORE_OAT_OUT): $$($(1)TARGET_CORE_IMG_OUT)
+  # Clean up locally used variables.
+  core_dex2oat_dependency :=
+  core_compile_options :=
+  core_image_name :=
+  core_oat_name :=
+  core_infix :=
+  core_pic_infix :=
 endef  # create-core-oat-target-rules
 
-ifdef TARGET_2ND_ARCH
-$(eval $(call create-core-oat-target-rules,2ND_))
-endif
-$(eval $(call create-core-oat-target-rules,))
+# $(1): compiler - default, optimizing or interpreter.
+# $(2): wrapper.
+# $(3): dex2oat suffix.
+define create-core-oat-target-rule-combination
+  $(call create-core-oat-target-rules,$(1),no-pic,,$(2),$(3))
+  $(call create-core-oat-target-rules,$(1),pic,,$(2),$(3))
 
+  ifdef TARGET_2ND_ARCH
+    $(call create-core-oat-target-rules,$(1),no-pic,2ND_,$(2),$(3))
+    $(call create-core-oat-target-rules,$(1),pic,2ND_,$(2),$(3))
+  endif
+endef
 
-ifeq ($(ART_BUILD_HOST),true)
-include $(CLEAR_VARS)
-LOCAL_MODULE := core.art-host
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.oat.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += $(HOST_CORE_IMG_OUT)
-include $(BUILD_PHONY_PACKAGE)
-endif # ART_BUILD_HOST
+$(eval $(call create-core-oat-target-rule-combination,default,,))
+$(eval $(call create-core-oat-target-rule-combination,optimizing,,))
+$(eval $(call create-core-oat-target-rule-combination,interpreter,,))
 
-# If we aren't building the host toolchain, skip building the target core.art.
-ifeq ($(ART_BUILD_TARGET),true)
-include $(CLEAR_VARS)
-LOCAL_MODULE := core.art
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.oat.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_CORE_IMG_OUT)
-include $(BUILD_PHONY_PACKAGE)
-endif # ART_BUILD_TARGET
+valgrindTARGET_CORE_IMG_OUTS :=
+valgrindTARGET_CORE_OAT_OUTS :=
+$(eval $(call create-core-oat-target-rule-combination,default,valgrind,32))
+$(eval $(call create-core-oat-target-rule-combination,optimizing,valgrind,32))
+$(eval $(call create-core-oat-target-rule-combination,interpreter,valgrind,32))
+
+valgrind-test-art-host-dex2oat-target: $(valgrindTARGET_CORE_IMG_OUTS)
+
+valgrind-test-art-host-dex2oat: valgrind-test-art-host-dex2oat-host valgrind-test-art-host-dex2oat-target
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
new file mode 100644
index 0000000..2967e27
--- /dev/null
+++ b/cmdline/cmdline.h
@@ -0,0 +1,377 @@
+/*
+ * 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_CMDLINE_CMDLINE_H_
+#define ART_CMDLINE_CMDLINE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "runtime.h"
+#include "base/stringpiece.h"
+#include "noop_compiler_callbacks.h"
+#include "base/logging.h"
+
+#if !defined(NDEBUG)
+#define DBG_LOG LOG(INFO)
+#else
+#define DBG_LOG LOG(DEBUG)
+#endif
+
+namespace art {
+
+// TODO: Move to <runtime/utils.h> and remove all copies of this function.
+static bool LocationToFilename(const std::string& location, InstructionSet isa,
+                               std::string* filename) {
+  bool has_system = false;
+  bool has_cache = false;
+  // image_location = /system/framework/boot.art
+  // system_image_filename = /system/framework/<image_isa>/boot.art
+  std::string system_filename(GetSystemImageFilename(location.c_str(), isa));
+  if (OS::FileExists(system_filename.c_str())) {
+    has_system = true;
+  }
+
+  bool have_android_data = false;
+  bool dalvik_cache_exists = false;
+  bool is_global_cache = false;
+  std::string dalvik_cache;
+  GetDalvikCache(GetInstructionSetString(isa), false, &dalvik_cache,
+                 &have_android_data, &dalvik_cache_exists, &is_global_cache);
+
+  std::string cache_filename;
+  if (have_android_data && dalvik_cache_exists) {
+    // Always set output location even if it does not exist,
+    // so that the caller knows where to create the image.
+    //
+    // image_location = /system/framework/boot.art
+    // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
+    std::string error_msg;
+    if (GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(),
+                               &cache_filename, &error_msg)) {
+      has_cache = true;
+    }
+  }
+  if (has_system) {
+    *filename = system_filename;
+    return true;
+  } else if (has_cache) {
+    *filename = cache_filename;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static Runtime* StartRuntime(const char* boot_image_location,
+                             InstructionSet instruction_set) {
+  CHECK(boot_image_location != nullptr);
+
+  RuntimeOptions options;
+
+  // We are more like a compiler than a run-time. We don't want to execute code.
+  {
+    static NoopCompilerCallbacks callbacks;
+    options.push_back(std::make_pair("compilercallbacks", &callbacks));
+  }
+
+  // Boot image location.
+  {
+    std::string boot_image_option;
+    boot_image_option += "-Ximage:";
+    boot_image_option += boot_image_location;
+    options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
+  }
+
+  // Instruction set.
+  options.push_back(
+      std::make_pair("imageinstructionset",
+                     reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
+
+  if (!Runtime::Create(options, false)) {
+    fprintf(stderr, "Failed to create runtime\n");
+    return nullptr;
+  }
+
+  // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
+  // give it away now and then switch to a more manageable ScopedObjectAccess.
+  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+
+  return Runtime::Current();
+}
+
+struct CmdlineArgs {
+  enum ParseStatus {
+    kParseOk,               // Parse successful. Do not set the error message.
+    kParseUnknownArgument,  // Unknown argument. Do not set the error message.
+    kParseError,            // Parse ok, but failed elsewhere. Print the set error message.
+  };
+
+  bool Parse(int argc, char** argv) {
+    // Skip over argv[0].
+    argv++;
+    argc--;
+
+    if (argc == 0) {
+      fprintf(stderr, "No arguments specified\n");
+      PrintUsage();
+      return false;
+    }
+
+    std::string error_msg;
+    for (int i = 0; i < argc; i++) {
+      const StringPiece option(argv[i]);
+      if (option.starts_with("--boot-image=")) {
+        boot_image_location_ = option.substr(strlen("--boot-image=")).data();
+      } else if (option.starts_with("--instruction-set=")) {
+        StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
+        instruction_set_ = GetInstructionSetFromString(instruction_set_str.data());
+        if (instruction_set_ == kNone) {
+          fprintf(stderr, "Unsupported instruction set %s\n", instruction_set_str.data());
+          PrintUsage();
+          return false;
+        }
+      } else if (option.starts_with("--output=")) {
+        output_name_ = option.substr(strlen("--output=")).ToString();
+        const char* filename = output_name_.c_str();
+        out_.reset(new std::ofstream(filename));
+        if (!out_->good()) {
+          fprintf(stderr, "Failed to open output filename %s\n", filename);
+          PrintUsage();
+          return false;
+        }
+        os_ = out_.get();
+      } else {
+        ParseStatus parse_status = ParseCustom(option, &error_msg);
+
+        if (parse_status == kParseUnknownArgument) {
+          fprintf(stderr, "Unknown argument %s\n", option.data());
+        }
+
+        if (parse_status != kParseOk) {
+          fprintf(stderr, "%s\n", error_msg.c_str());
+          PrintUsage();
+          return false;
+        }
+      }
+    }
+
+    DBG_LOG << "will call parse checks";
+
+    {
+      ParseStatus checks_status = ParseChecks(&error_msg);
+      if (checks_status != kParseOk) {
+          fprintf(stderr, "%s\n", error_msg.c_str());
+          PrintUsage();
+          return false;
+      }
+    }
+
+    return true;
+  }
+
+  virtual std::string GetUsage() const {
+    std::string usage;
+
+    usage +=  // Required.
+        "  --boot-image=<file.art>: provide the image location for the boot class path.\n"
+        "      Do not include the arch as part of the name, it is added automatically.\n"
+        "      Example: --boot-image=/system/framework/boot.art\n"
+        "\n";
+    usage += StringPrintf(  // Optional.
+        "  --instruction-set=(arm|arm64|mips|mips64|x86|x86_64): for locating the image\n"
+        "      file based on the image location set.\n"
+        "      Example: --instruction-set=x86\n"
+        "      Default: %s\n"
+        "\n",
+        GetInstructionSetString(kRuntimeISA));
+    usage +=  // Optional.
+        "  --output=<file> may be used to send the output to a file.\n"
+        "      Example: --output=/tmp/oatdump.txt\n"
+        "\n";
+
+    return usage;
+  }
+
+  // Specified by --boot-image.
+  const char* boot_image_location_ = nullptr;
+  // Specified by --instruction-set.
+  InstructionSet instruction_set_ = kRuntimeISA;
+  // Specified by --output.
+  std::ostream* os_ = &std::cout;
+  std::unique_ptr<std::ofstream> out_;  // If something besides cout is used
+  std::string output_name_;
+
+  virtual ~CmdlineArgs() {}
+
+  bool ParseCheckBootImage(std::string* error_msg) {
+    if (boot_image_location_ == nullptr) {
+      *error_msg = "--boot-image must be specified";
+      return false;
+    }
+
+    DBG_LOG << "boot image location: " << boot_image_location_;
+
+    // Checks for --boot-image location.
+    {
+      std::string boot_image_location = boot_image_location_;
+      size_t file_name_idx = boot_image_location.rfind("/");
+      if (file_name_idx == std::string::npos) {  // Prevent a InsertIsaDirectory check failure.
+        *error_msg = "Boot image location must have a / in it";
+        return false;
+      }
+
+      // Don't let image locations with the 'arch' in it through, since it's not a location.
+      // This prevents a common error "Could not create an image space..." when initing the Runtime.
+      if (file_name_idx != std::string::npos) {
+        std::string no_file_name = boot_image_location.substr(0, file_name_idx);
+        size_t ancestor_dirs_idx = no_file_name.rfind("/");
+
+        std::string parent_dir_name;
+        if (ancestor_dirs_idx != std::string::npos) {
+          parent_dir_name = no_file_name.substr(ancestor_dirs_idx + 1);
+        } else {
+          parent_dir_name = no_file_name;
+        }
+
+        DBG_LOG << "boot_image_location parent_dir_name was " << parent_dir_name;
+
+        if (GetInstructionSetFromString(parent_dir_name.c_str()) != kNone) {
+          *error_msg = "Do not specify the architecture as part of the boot image location";
+          return false;
+        }
+      }
+
+      // Check that the boot image location points to a valid file name.
+      std::string file_name;
+      if (!LocationToFilename(boot_image_location, instruction_set_, &file_name)) {
+        *error_msg = StringPrintf("No corresponding file for location '%s' exists",
+                                  file_name.c_str());
+        return false;
+      }
+
+      DBG_LOG << "boot_image_filename does exist: " << file_name;
+    }
+
+    return true;
+  }
+
+  void PrintUsage() {
+    fprintf(stderr, "%s", GetUsage().c_str());
+  }
+
+ protected:
+  virtual ParseStatus ParseCustom(const StringPiece& option ATTRIBUTE_UNUSED,
+                                  std::string* error_msg ATTRIBUTE_UNUSED) {
+    return kParseUnknownArgument;
+  }
+
+  virtual ParseStatus ParseChecks(std::string* error_msg ATTRIBUTE_UNUSED) {
+    return kParseOk;
+  }
+};
+
+template <typename Args = CmdlineArgs>
+struct CmdlineMain {
+  int Main(int argc, char** argv) {
+    InitLogging(argv);
+    std::unique_ptr<Args> args = std::unique_ptr<Args>(CreateArguments());
+    args_ = args.get();
+
+    DBG_LOG << "Try to parse";
+
+    if (args_ == nullptr || !args_->Parse(argc, argv)) {
+      return EXIT_FAILURE;
+    }
+
+    bool needs_runtime = NeedsRuntime();
+    std::unique_ptr<Runtime> runtime;
+
+
+    if (needs_runtime) {
+      std::string error_msg;
+      if (!args_->ParseCheckBootImage(&error_msg)) {
+        fprintf(stderr, "%s\n", error_msg.c_str());
+        args_->PrintUsage();
+        return EXIT_FAILURE;
+      }
+      runtime.reset(CreateRuntime(args.get()));
+      if (runtime == nullptr) {
+        return EXIT_FAILURE;
+      }
+      if (!ExecuteWithRuntime(runtime.get())) {
+        return EXIT_FAILURE;
+      }
+    } else {
+      if (!ExecuteWithoutRuntime()) {
+        return EXIT_FAILURE;
+      }
+    }
+
+    if (!ExecuteCommon()) {
+      return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+  }
+
+  // Override this function to create your own arguments.
+  // Usually will want to return a subtype of CmdlineArgs.
+  virtual Args* CreateArguments() {
+    return new Args();
+  }
+
+  // Override this function to do something else with the runtime.
+  virtual bool ExecuteWithRuntime(Runtime* runtime) {
+    CHECK(runtime != nullptr);
+    // Do nothing
+    return true;
+  }
+
+  // Does the code execution need a runtime? Sometimes it doesn't.
+  virtual bool NeedsRuntime() {
+    return true;
+  }
+
+  // Do execution without having created a runtime.
+  virtual bool ExecuteWithoutRuntime() {
+    return true;
+  }
+
+  // Continue execution after ExecuteWith[out]Runtime
+  virtual bool ExecuteCommon() {
+    return true;
+  }
+
+  virtual ~CmdlineMain() {}
+
+ protected:
+  Args* args_ = nullptr;
+
+ private:
+  Runtime* CreateRuntime(CmdlineArgs* args) {
+    CHECK(args != nullptr);
+
+    return StartRuntime(args->boot_image_location_, args->instruction_set_);
+  }
+};
+}  // namespace art
+
+#endif  // ART_CMDLINE_CMDLINE_H_
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 8b5e6d5..f2f4550 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -58,22 +58,22 @@
 	dex/quick/x86/target_x86.cc \
 	dex/quick/x86/utility_x86.cc \
 	dex/dex_to_dex_compiler.cc \
-	dex/mir_dataflow.cc \
-	dex/mir_field_info.cc \
-	dex/mir_method_info.cc \
-	dex/mir_optimization.cc \
 	dex/bb_optimizations.cc \
 	dex/compiler_ir.cc \
+	dex/frontend.cc \
+	dex/mir_analysis.cc \
+	dex/mir_dataflow.cc \
+	dex/mir_field_info.cc \
+	dex/mir_graph.cc \
+	dex/mir_method_info.cc \
+	dex/mir_optimization.cc \
 	dex/post_opt_passes.cc \
 	dex/pass_driver_me_opts.cc \
 	dex/pass_driver_me_post_opt.cc \
-	dex/frontend.cc \
-	dex/mir_graph.cc \
-	dex/mir_analysis.cc \
+	dex/ssa_transformation.cc \
 	dex/verified_method.cc \
 	dex/verification_results.cc \
 	dex/vreg_analysis.cc \
-	dex/ssa_transformation.cc \
 	dex/quick_compiler_callbacks.cc \
 	driver/compiler_driver.cc \
 	driver/dex_compilation_unit.cc \
@@ -84,22 +84,28 @@
 	jni/quick/x86_64/calling_convention_x86_64.cc \
 	jni/quick/calling_convention.cc \
 	jni/quick/jni_compiler.cc \
-	llvm/llvm_compiler.cc \
 	optimizing/builder.cc \
+	optimizing/bounds_check_elimination.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 \
 	optimizing/gvn.cc \
+	optimizing/inliner.cc \
 	optimizing/instruction_simplifier.cc \
+	optimizing/intrinsics.cc \
+	optimizing/intrinsics_x86_64.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 \
 	optimizing/register_allocator.cc \
 	optimizing/ssa_builder.cc \
 	optimizing/ssa_liveness_analysis.cc \
@@ -118,56 +124,40 @@
 	utils/dwarf_cfi.cc \
 	utils/mips/assembler_mips.cc \
 	utils/mips/managed_register_mips.cc \
+	utils/mips64/assembler_mips64.cc \
+	utils/mips64/managed_register_mips64.cc \
 	utils/x86/assembler_x86.cc \
 	utils/x86/managed_register_x86.cc \
 	utils/x86_64/assembler_x86_64.cc \
 	utils/x86_64/managed_register_x86_64.cc \
 	utils/scoped_arena_allocator.cc \
+	utils/swap_space.cc \
 	buffered_output_stream.cc \
 	compiler.cc \
-	elf_fixup.cc \
-	elf_stripper.cc \
 	elf_writer.cc \
 	elf_writer_quick.cc \
 	file_output_stream.cc \
 	image_writer.cc \
 	oat_writer.cc \
+	output_stream.cc \
 	vector_output_stream.cc
 
-ifeq ($(ART_SEA_IR_MODE),true)
-LIBART_COMPILER_SRC_FILES += \
-	sea_ir/frontend.cc \
-	sea_ir/ir/instruction_tools.cc \
-	sea_ir/ir/sea.cc \
-	sea_ir/code_gen/code_gen.cc \
-	sea_ir/code_gen/code_gen_data.cc \
-	sea_ir/types/type_inference.cc \
-	sea_ir/types/type_inference_visitor.cc \
-	sea_ir/debug/dot_gen.cc
-endif
-
 LIBART_COMPILER_CFLAGS :=
 
-ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-LIBART_COMPILER_SRC_FILES += \
-	dex/portable/mir_to_gbc.cc \
-	elf_writer_mclinker.cc \
-	jni/portable/jni_compiler.cc \
-	llvm/compiler_llvm.cc \
-	llvm/gbc_expander.cc \
-	llvm/generated/art_module.cc \
-	llvm/intrinsic_helper.cc \
-	llvm/ir_builder.cc \
-	llvm/llvm_compilation_unit.cc \
-	llvm/md_builder.cc \
-	llvm/runtime_support_builder.cc \
-	llvm/runtime_support_builder_arm.cc \
-	llvm/runtime_support_builder_x86.cc
-LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
-endif
-
 LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \
-	dex/compiler_enums.h
+  dex/quick/arm/arm_lir.h \
+  dex/quick/arm64/arm64_lir.h \
+  dex/quick/mips/mips_lir.h \
+  dex/quick/resource_mask.h \
+  dex/compiler_enums.h \
+  dex/global_value_numbering.h \
+  dex/pass_me.h \
+  driver/compiler_driver.h \
+  driver/compiler_options.h \
+  image_writer.h \
+  optimizing/locations.h \
+  utils/arm/constants_arm.h \
+  utils/dex_instruction_utils.h
 
 # $(1): target or host
 # $(2): ndebug or debug
@@ -194,7 +184,9 @@
   ifeq ($$(art_ndebug_or_debug),ndebug)
     LOCAL_MODULE := libart-compiler
     LOCAL_SHARED_LIBRARIES += libart
-    LOCAL_FDO_SUPPORT := true
+    ifeq ($$(art_target_or_host),target)
+      LOCAL_FDO_SUPPORT := true
+    endif
   else # debug
     LOCAL_MODULE := libartd-compiler
     LOCAL_SHARED_LIBRARIES += libartd
@@ -224,6 +216,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
@@ -231,43 +224,25 @@
     endif
   endif
 
-  # TODO: clean up the compilers and remove this.
-  LOCAL_CFLAGS += -Wno-unused-parameter
-
-  ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-    LOCAL_SHARED_LIBRARIES += libLLVM
-    LOCAL_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
-    ifeq ($$(art_target_or_host),target)
-      LOCAL_STATIC_LIBRARIES_arm += libmcldARMInfo libmcldARMTarget
-      LOCAL_STATIC_LIBRARIES_x86 += libmcldX86Info libmcldX86Target
-      LOCAL_STATIC_LIBRARIES_x86_64 += libmcldX86Info libmcldX86Target
-      LOCAL_STATIC_LIBRARIES_mips += libmcldMipsInfo libmcldMipsTarget
-      ifeq ($(TARGET_ARCH),arm64)
-         $$(info TODOAArch64: $$(LOCAL_PATH)/Android.mk Add Arm64 specific MCLinker libraries)
-      endif # TARGET_ARCH != arm64
-      include $(LLVM_DEVICE_BUILD_MK)
-    else # host
-      LOCAL_STATIC_LIBRARIES += libmcldARMInfo libmcldARMTarget
-      LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
-      LOCAL_STATIC_LIBRARIES += libmcldMipsInfo libmcldMipsTarget
-      include $(LLVM_HOST_BUILD_MK)
-    endif
-    LOCAL_STATIC_LIBRARIES += libmcldCore libmcldObject libmcldADT libmcldFragment libmcldTarget libmcldCodeGen libmcldLDVariant libmcldMC libmcldSupport libmcldLD libmcldScript
-    include $(LLVM_GEN_INTRINSICS_MK)
-  endif
-
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
 
   ifeq ($$(art_target_or_host),host)
-    LOCAL_LDLIBS += -ldl -lpthread
+    # For compiler driver TLS.
+    LOCAL_LDLIBS += -lpthread
   endif
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+  # Vixl assembly support for ARM64 targets.
+  ifeq ($$(art_ndebug_or_debug),debug)
+    LOCAL_SHARED_LIBRARIES += libvixld
+  else
+    LOCAL_SHARED_LIBRARIES += libvixl
+  endif
   ifeq ($$(art_target_or_host),target)
-    LOCAL_SHARED_LIBRARIES += libcutils libvixl
+    # For atrace.
+    LOCAL_SHARED_LIBRARIES += libcutils
     include $(BUILD_SHARED_LIBRARY)
   else # host
-    LOCAL_STATIC_LIBRARIES += libcutils libvixl
     LOCAL_MULTILIB := both
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
@@ -301,18 +276,3 @@
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-libart-compiler,target,debug))
 endif
-
-# Rule to build /system/lib/libcompiler_rt.a
-# Usually static libraries are not installed on the device.
-ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-ifeq ($(ART_BUILD_TARGET),true)
-# TODO: Move to external/compiler_rt
-$(eval $(call copy-one-file, $(call intermediates-dir-for,STATIC_LIBRARIES,libcompiler_rt,,)/libcompiler_rt.a, $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler_rt.a))
-ifdef TARGET_2ND_ARCH
-$(eval $(call copy-one-file, $(call intermediates-dir-for,STATIC_LIBRARIES,libcompiler_rt,,,t)/libcompiler_rt.a, $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libcompiler_rt.a))
-endif
-
-$(DEX2OAT): $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler_rt.a
-
-endif
-endif
diff --git a/compiler/buffered_output_stream.h b/compiler/buffered_output_stream.h
index 75a3f24..bbc49df 100644
--- a/compiler/buffered_output_stream.h
+++ b/compiler/buffered_output_stream.h
@@ -23,7 +23,7 @@
 
 namespace art {
 
-class BufferedOutputStream : public OutputStream {
+class BufferedOutputStream FINAL : public OutputStream {
  public:
   explicit BufferedOutputStream(OutputStream* out);
 
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index fbaed9f..96f8e0c 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -16,18 +16,13 @@
 
 #include "common_compiler_test.h"
 
-#if defined(__arm__)
-#include <sys/ucontext.h>
-#endif
-#include <fstream>
-
+#include "arch/instruction_set_features.h"
 #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 +33,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 byte* base;
-  uint32_t code_offset, gc_map_offset;
-  if (gc_map == nullptr) {
-    base = reinterpret_cast<const byte*>(code);  // Base of data points at code.
-    base -= kPointerSize;  // Move backward so that code_offset != 0.
-    code_offset = kPointerSize;
-    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);
 
@@ -172,71 +48,56 @@
                                                             method->GetDexMethodIndex()));
   }
   if (compiled_method != nullptr) {
-    const std::vector<uint8_t>* code = compiled_method->GetQuickCode();
-    const void* code_ptr;
-    if (code != nullptr) {
-      uint32_t code_size = code->size();
-      CHECK_NE(0u, code_size);
-      const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
-      uint32_t vmap_table_offset = vmap_table.empty() ? 0u
-          : sizeof(OatQuickMethodHeader) + vmap_table.size();
-      const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
-      uint32_t mapping_table_offset = mapping_table.empty() ? 0u
-          : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size();
-      OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
-                                         compiled_method->GetFrameSizeInBytes(),
-                                         compiled_method->GetCoreSpillMask(),
-                                         compiled_method->GetFpSpillMask(), code_size);
+    const SwapVector<uint8_t>* code = compiled_method->GetQuickCode();
+    uint32_t code_size = code->size();
+    CHECK_NE(0u, code_size);
+    const SwapVector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
+    uint32_t vmap_table_offset = vmap_table.empty() ? 0u
+        : sizeof(OatQuickMethodHeader) + vmap_table.size();
+    const SwapVector<uint8_t>* mapping_table = compiled_method->GetMappingTable();
+    bool mapping_table_used = mapping_table != nullptr && !mapping_table->empty();
+    size_t mapping_table_size = mapping_table_used ? mapping_table->size() : 0U;
+    uint32_t mapping_table_offset = !mapping_table_used ? 0u
+        : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size;
+    const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap();
+    bool gc_map_used = gc_map != nullptr && !gc_map->empty();
+    size_t gc_map_size = gc_map_used ? gc_map->size() : 0U;
+    uint32_t gc_map_offset = !gc_map_used ? 0u
+        : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size + gc_map_size;
+    OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
+                                       compiled_method->GetFrameSizeInBytes(),
+                                       compiled_method->GetCoreSpillMask(),
+                                       compiled_method->GetFpSpillMask(), code_size);
 
-      header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
-      std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
-      size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
-      size_t code_offset = compiled_method->AlignCode(size - code_size);
-      size_t padding = code_offset - (size - code_size);
-      chunk->reserve(padding + size);
-      chunk->resize(sizeof(method_header));
-      memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
-      chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
-      chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
-      chunk->insert(chunk->begin(), padding, 0);
-      chunk->insert(chunk->end(), code->begin(), code->end());
-      CHECK_EQ(padding + size, chunk->size());
-      code_ptr = &(*chunk)[code_offset];
-    } else {
-      code = compiled_method->GetPortableCode();
-      code_ptr = &(*code)[0];
+    header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
+    std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
+    size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table_size +
+        gc_map_size;
+    size_t code_offset = compiled_method->AlignCode(size - code_size);
+    size_t padding = code_offset - (size - code_size);
+    chunk->reserve(padding + size);
+    chunk->resize(sizeof(method_header));
+    memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
+    chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
+    if (mapping_table_used) {
+      chunk->insert(chunk->begin(), mapping_table->begin(), mapping_table->end());
     }
+    if (gc_map_used) {
+      chunk->insert(chunk->begin(), gc_map->begin(), gc_map->end());
+    }
+    chunk->insert(chunk->begin(), padding, 0);
+    chunk->insert(chunk->end(), code->begin(), code->end());
+    CHECK_EQ(padding + size, chunk->size());
+    const void* code_ptr = &(*chunk)[code_offset];
     MakeExecutable(code_ptr, code->size());
     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);
   } 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);
   }
 }
 
@@ -257,7 +118,7 @@
 #else
   // Only warn if not Intel as Intel doesn't have cache flush instructions.
 #if !defined(__i386__) && !defined(__x86_64__)
-  LOG(WARNING) << "UNIMPLEMENTED: cache flush";
+  UNIMPLEMENTED(WARNING) << "cache flush";
 #endif
 #endif
 }
@@ -282,40 +143,28 @@
   {
     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++) {
       Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
       if (!runtime_->HasCalleeSaveMethod(type)) {
-        runtime_->SetCalleeSaveMethod(
-            runtime_->CreateCalleeSaveMethod(type), type);
+        runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(), type);
       }
     }
 
     // TODO: make selectable
-    Compiler::Kind compiler_kind
-    = (kUsePortableCompiler) ? Compiler::kPortable : Compiler::kQuick;
+    Compiler::Kind compiler_kind = 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,
-                                              true, new std::set<std::string>,
-                                              2, true, true, timer_.get()));
+                                              instruction_set_features_.get(),
+                                              true, new std::set<std::string>, nullptr,
+                                              2, true, true, "", timer_.get(), -1, ""));
   }
   // We typically don't generate an image in unit tests, disable this optimization by default.
   compiler_driver_->SetSupportBootImageFixup(false);
@@ -397,8 +246,9 @@
   // 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<byte*>(ART_BASE_ADDRESS),
+                                                reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS),
                                                 (size_t)100 * 1024 * 1024,  // 100MB
                                                 PROT_NONE,
                                                 false /* no need for 4gb flag with fixed mmap*/,
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index df06b71..9cffbc8 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -42,7 +42,7 @@
   ~CommonCompilerTest();
 
   // Create an OatMethod based on pointers (for unit tests).
-  OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map);
+  OatFile::OatMethod CreateOatMethod(const void* code);
 
   void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -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/compiled_method.cc b/compiler/compiled_method.cc
index 698bf3b..22be28c 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -20,35 +20,13 @@
 namespace art {
 
 CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-                           const std::vector<uint8_t>& quick_code)
+                           const ArrayRef<const uint8_t>& quick_code)
     : compiler_driver_(compiler_driver), instruction_set_(instruction_set),
-      portable_code_(nullptr), quick_code_(nullptr) {
-  SetCode(&quick_code, nullptr);
+      quick_code_(nullptr) {
+  SetCode(&quick_code);
 }
 
-CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-                           const std::string& elf_object, const std::string& symbol)
-    : compiler_driver_(compiler_driver), instruction_set_(instruction_set),
-      portable_code_(nullptr), quick_code_(nullptr), symbol_(symbol) {
-  CHECK_NE(elf_object.size(), 0U);
-  CHECK_NE(symbol.size(), 0U);
-  std::vector<uint8_t> temp_code(elf_object.size());
-  for (size_t i = 0; i < elf_object.size(); ++i) {
-    temp_code[i] = elf_object[i];
-  }
-  // TODO: we shouldn't just shove ELF objects in as "code" but
-  // change to have different kinds of compiled methods.  This is
-  // being deferred until we work on hybrid execution or at least
-  // until we work on batch compilation.
-  SetCode(nullptr, &temp_code);
-}
-
-void CompiledCode::SetCode(const std::vector<uint8_t>* quick_code,
-                           const std::vector<uint8_t>* portable_code) {
-  if (portable_code != nullptr) {
-    CHECK(!portable_code->empty());
-    portable_code_ = compiler_driver_->DeduplicateCode(*portable_code);
-  }
+void CompiledCode::SetCode(const ArrayRef<const uint8_t>* quick_code) {
   if (quick_code != nullptr) {
     CHECK(!quick_code->empty());
     quick_code_ = compiler_driver_->DeduplicateCode(*quick_code);
@@ -64,17 +42,8 @@
     } else {
       return std::equal(quick_code_->begin(), quick_code_->end(), rhs.quick_code_->begin());
     }
-  } else if (portable_code_ != nullptr) {
-    if (rhs.portable_code_ == nullptr) {
-      return false;
-    } else if (portable_code_->size() != rhs.portable_code_->size()) {
-      return false;
-    } else {
-      return std::equal(portable_code_->begin(), portable_code_->end(),
-                        rhs.portable_code_->begin());
-    }
   }
-  return (rhs.quick_code_ == nullptr) && (rhs.portable_code_ == nullptr);
+  return (rhs.quick_code_ == nullptr);
 }
 
 uint32_t CompiledCode::AlignCode(uint32_t offset) const {
@@ -94,6 +63,7 @@
     case kArm:
     case kArm64:
     case kMips:
+    case kMips64:
     case kX86:
     case kX86_64:
       return 0;
@@ -113,6 +83,7 @@
     case kArm:
     case kArm64:
     case kMips:
+    case kMips64:
     case kX86:
     case kX86_64:
       return code_pointer;
@@ -128,13 +99,8 @@
   }
 }
 
-const std::string& CompiledCode::GetSymbol() const {
-  CHECK_NE(0U, symbol_.size());
-  return symbol_;
-}
-
 const std::vector<uint32_t>& CompiledCode::GetOatdataOffsetsToCompliledCodeOffset() const {
-  CHECK_NE(0U, oatdata_offsets_to_compiled_code_offset_.size()) << symbol_;
+  CHECK_NE(0U, oatdata_offsets_to_compiled_code_offset_.size());
   return oatdata_offsets_to_compiled_code_offset_;
 }
 
@@ -144,90 +110,88 @@
 
 CompiledMethod::CompiledMethod(CompilerDriver* driver,
                                InstructionSet instruction_set,
-                               const std::vector<uint8_t>& quick_code,
+                               const ArrayRef<const uint8_t>& quick_code,
                                const size_t frame_size_in_bytes,
                                const uint32_t core_spill_mask,
                                const uint32_t fp_spill_mask,
-                               SrcMap* src_mapping_table,
-                               const std::vector<uint8_t>& mapping_table,
-                               const std::vector<uint8_t>& vmap_table,
-                               const std::vector<uint8_t>& native_gc_map,
-                               const std::vector<uint8_t>* cfi_info,
+                               DefaultSrcMap* src_mapping_table,
+                               const ArrayRef<const uint8_t>& mapping_table,
+                               const ArrayRef<const uint8_t>& vmap_table,
+                               const ArrayRef<const uint8_t>& native_gc_map,
+                               const ArrayRef<const uint8_t>& cfi_info,
                                const ArrayRef<LinkerPatch>& patches)
     : CompiledCode(driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
-      src_mapping_table_(driver->DeduplicateSrcMappingTable(src_mapping_table->Arrange())),
-      mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
+      src_mapping_table_(src_mapping_table == nullptr ?
+          driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) :
+          driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(src_mapping_table->Arrange()))),
+      mapping_table_(mapping_table.data() == nullptr ?
+          nullptr : driver->DeduplicateMappingTable(mapping_table)),
       vmap_table_(driver->DeduplicateVMapTable(vmap_table)),
-      gc_map_(driver->DeduplicateGCMap(native_gc_map)),
-      cfi_info_(driver->DeduplicateCFIInfo(cfi_info)),
-      patches_(patches.begin(), patches.end()) {
+      gc_map_(native_gc_map.data() == nullptr ? nullptr : driver->DeduplicateGCMap(native_gc_map)),
+      cfi_info_(cfi_info.data() == nullptr ? nullptr : driver->DeduplicateCFIInfo(cfi_info)),
+      patches_(patches.begin(), patches.end(), driver->GetSwapSpaceAllocator()) {
 }
 
-CompiledMethod::CompiledMethod(CompilerDriver* driver,
-                               InstructionSet instruction_set,
-                               const std::vector<uint8_t>& quick_code,
-                               const size_t frame_size_in_bytes,
-                               const uint32_t core_spill_mask,
-                               const uint32_t fp_spill_mask,
-                               const std::vector<uint8_t>& mapping_table,
-                               const std::vector<uint8_t>& stack_map)
-    : CompiledCode(driver, instruction_set, quick_code),
-      frame_size_in_bytes_(frame_size_in_bytes),
-      core_spill_mask_(core_spill_mask),
-      fp_spill_mask_(fp_spill_mask),
-      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
-      mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
-      vmap_table_(driver->DeduplicateVMapTable(stack_map)),
-      gc_map_(nullptr),
-      cfi_info_(nullptr),
-      patches_() {
+CompiledMethod* CompiledMethod::SwapAllocCompiledMethod(
+    CompilerDriver* driver,
+    InstructionSet instruction_set,
+    const ArrayRef<const uint8_t>& quick_code,
+    const size_t frame_size_in_bytes,
+    const uint32_t core_spill_mask,
+    const uint32_t fp_spill_mask,
+    DefaultSrcMap* src_mapping_table,
+    const ArrayRef<const uint8_t>& mapping_table,
+    const ArrayRef<const uint8_t>& vmap_table,
+    const ArrayRef<const uint8_t>& native_gc_map,
+    const ArrayRef<const uint8_t>& cfi_info,
+    const ArrayRef<LinkerPatch>& patches) {
+  SwapAllocator<CompiledMethod> alloc(driver->GetSwapSpaceAllocator());
+  CompiledMethod* ret = alloc.allocate(1);
+  alloc.construct(ret, driver, instruction_set, quick_code, frame_size_in_bytes, core_spill_mask,
+                  fp_spill_mask, src_mapping_table, mapping_table, vmap_table, native_gc_map,
+                  cfi_info, patches);
+  return ret;
 }
 
-CompiledMethod::CompiledMethod(CompilerDriver* driver,
-                               InstructionSet instruction_set,
-                               const std::vector<uint8_t>& code,
-                               const size_t frame_size_in_bytes,
-                               const uint32_t core_spill_mask,
-                               const uint32_t fp_spill_mask,
-                               const std::vector<uint8_t>* cfi_info)
-    : CompiledCode(driver, instruction_set, code),
-      frame_size_in_bytes_(frame_size_in_bytes),
-      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
-      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
-      mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
-      vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
-      gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())),
-      cfi_info_(driver->DeduplicateCFIInfo(cfi_info)),
-      patches_() {
+CompiledMethod* CompiledMethod::SwapAllocCompiledMethodStackMap(
+    CompilerDriver* driver,
+    InstructionSet instruction_set,
+    const ArrayRef<const uint8_t>& quick_code,
+    const size_t frame_size_in_bytes,
+    const uint32_t core_spill_mask,
+    const uint32_t fp_spill_mask,
+    const ArrayRef<const uint8_t>& stack_map) {
+  SwapAllocator<CompiledMethod> alloc(driver->GetSwapSpaceAllocator());
+  CompiledMethod* ret = alloc.allocate(1);
+  alloc.construct(ret, driver, instruction_set, quick_code, frame_size_in_bytes, core_spill_mask,
+                  fp_spill_mask, nullptr, ArrayRef<const uint8_t>(), stack_map,
+                  ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(), ArrayRef<LinkerPatch>());
+  return ret;
 }
 
-// Constructs a CompiledMethod for the Portable compiler.
-CompiledMethod::CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set,
-                               const std::string& code, const std::vector<uint8_t>& gc_map,
-                               const std::string& symbol)
-    : CompiledCode(driver, instruction_set, code, symbol),
-      frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
-      fp_spill_mask_(0),
-      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
-      mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
-      vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
-      gc_map_(driver->DeduplicateGCMap(gc_map)),
-      cfi_info_(nullptr),
-      patches_() {
+CompiledMethod* CompiledMethod::SwapAllocCompiledMethodCFI(
+    CompilerDriver* driver,
+    InstructionSet instruction_set,
+    const ArrayRef<const uint8_t>& quick_code,
+    const size_t frame_size_in_bytes,
+    const uint32_t core_spill_mask,
+    const uint32_t fp_spill_mask,
+    const ArrayRef<const uint8_t>& cfi_info) {
+  SwapAllocator<CompiledMethod> alloc(driver->GetSwapSpaceAllocator());
+  CompiledMethod* ret = alloc.allocate(1);
+  alloc.construct(ret, driver, instruction_set, quick_code, frame_size_in_bytes, core_spill_mask,
+                  fp_spill_mask, nullptr, ArrayRef<const uint8_t>(),
+                  ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(),
+                  cfi_info, ArrayRef<LinkerPatch>());
+  return ret;
 }
 
-CompiledMethod::CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set,
-                               const std::string& code, const std::string& symbol)
-    : CompiledCode(driver, instruction_set, code, symbol),
-      frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
-      fp_spill_mask_(0),
-      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
-      mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
-      vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
-      gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())),
-      cfi_info_(nullptr),
-      patches_() {
+
+void CompiledMethod::ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m) {
+  SwapAllocator<CompiledMethod> alloc(driver->GetSwapSpaceAllocator());
+  alloc.destroy(m);
+  alloc.deallocate(m, 1);
 }
 
 }  // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index cdae8d2..6013507 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -21,10 +21,11 @@
 #include <string>
 #include <vector>
 
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
 #include "method_reference.h"
 #include "utils.h"
 #include "utils/array_ref.h"
+#include "utils/swap_space.h"
 
 namespace llvm {
   class Function;
@@ -38,25 +39,17 @@
  public:
   // For Quick to supply an code blob
   CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-               const std::vector<uint8_t>& quick_code);
-
-  // For Portable to supply an ELF object
-  CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
-               const std::string& elf_object, const std::string &symbol);
+               const ArrayRef<const uint8_t>& quick_code);
 
   InstructionSet GetInstructionSet() const {
     return instruction_set_;
   }
 
-  const std::vector<uint8_t>* GetPortableCode() const {
-    return portable_code_;
-  }
-
-  const std::vector<uint8_t>* GetQuickCode() const {
+  const SwapVector<uint8_t>* GetQuickCode() const {
     return quick_code_;
   }
 
-  void SetCode(const std::vector<uint8_t>* quick_code, const std::vector<uint8_t>* portable_code);
+  void SetCode(const ArrayRef<const uint8_t>* quick_code);
 
   bool operator==(const CompiledCode& rhs) const;
 
@@ -77,7 +70,6 @@
   static const void* CodePointer(const void* code_pointer,
                                  InstructionSet instruction_set);
 
-  const std::string& GetSymbol() const;
   const std::vector<uint32_t>& GetOatdataOffsetsToCompliledCodeOffset() const;
   void AddOatdataOffsetToCompliledCodeOffset(uint32_t offset);
 
@@ -86,14 +78,8 @@
 
   const InstructionSet instruction_set_;
 
-  // The ELF image for portable.
-  std::vector<uint8_t>* portable_code_;
-
   // Used to store the PIC code for Quick.
-  std::vector<uint8_t>* quick_code_;
-
-  // Used for the Portable ELF symbol name.
-  const std::string symbol_;
+  SwapVector<uint8_t>* quick_code_;
 
   // There are offsets from the oatdata symbol to where the offset to
   // the compiled method will be found. These are computed by the
@@ -124,8 +110,23 @@
   }
 };
 
-class SrcMap FINAL : public std::vector<SrcMapElem> {
+template <class Allocator>
+class SrcMap FINAL : public std::vector<SrcMapElem, Allocator> {
  public:
+  using std::vector<SrcMapElem, Allocator>::begin;
+  using typename std::vector<SrcMapElem, Allocator>::const_iterator;
+  using std::vector<SrcMapElem, Allocator>::empty;
+  using std::vector<SrcMapElem, Allocator>::end;
+  using std::vector<SrcMapElem, Allocator>::resize;
+  using std::vector<SrcMapElem, Allocator>::shrink_to_fit;
+  using std::vector<SrcMapElem, Allocator>::size;
+
+  explicit SrcMap() {}
+
+  template <class InputIt>
+  SrcMap(InputIt first, InputIt last, const Allocator& alloc)
+      : std::vector<SrcMapElem, Allocator>(first, last, alloc) {}
+
   void SortByFrom() {
     std::sort(begin(), end(), [] (const SrcMapElem& lhs, const SrcMapElem& rhs) -> bool {
       return lhs.from_ < rhs.from_;
@@ -162,7 +163,7 @@
       }
       this->resize(i + 1);
 
-      for (size_t i = size(); --i >= 1; ) {
+      for (i = size(); --i >= 1; ) {
         (*this)[i].from_ -= (*this)[i-1].from_;
         (*this)[i].to_ -= (*this)[i-1].to_;
       }
@@ -173,6 +174,10 @@
   }
 };
 
+using DefaultSrcMap = SrcMap<std::allocator<SrcMapElem>>;
+using SwapSrcMap = SrcMap<SwapAllocator<SrcMapElem>>;
+
+
 enum LinkerPatchType {
   kLinkerPatchMethod,
   kLinkerPatchCall,
@@ -270,49 +275,57 @@
 
 class CompiledMethod FINAL : public CompiledCode {
  public:
-  // Constructs a CompiledMethod for Quick.
+  // Constructs a CompiledMethod.
+  // Note: Consider using the static allocation methods below that will allocate the CompiledMethod
+  //       in the swap space.
   CompiledMethod(CompilerDriver* driver,
                  InstructionSet instruction_set,
-                 const std::vector<uint8_t>& quick_code,
+                 const ArrayRef<const uint8_t>& quick_code,
                  const size_t frame_size_in_bytes,
                  const uint32_t core_spill_mask,
                  const uint32_t fp_spill_mask,
-                 SrcMap* src_mapping_table,
-                 const std::vector<uint8_t>& mapping_table,
-                 const std::vector<uint8_t>& vmap_table,
-                 const std::vector<uint8_t>& native_gc_map,
-                 const std::vector<uint8_t>* cfi_info,
+                 DefaultSrcMap* src_mapping_table,
+                 const ArrayRef<const uint8_t>& mapping_table,
+                 const ArrayRef<const uint8_t>& vmap_table,
+                 const ArrayRef<const uint8_t>& native_gc_map,
+                 const ArrayRef<const uint8_t>& cfi_info,
                  const ArrayRef<LinkerPatch>& patches = ArrayRef<LinkerPatch>());
 
-  // Constructs a CompiledMethod for Optimizing.
-  CompiledMethod(CompilerDriver* driver,
-                 InstructionSet instruction_set,
-                 const std::vector<uint8_t>& quick_code,
-                 const size_t frame_size_in_bytes,
-                 const uint32_t core_spill_mask,
-                 const uint32_t fp_spill_mask,
-                 const std::vector<uint8_t>& mapping_table,
-                 const std::vector<uint8_t>& vmap_table);
-
-  // Constructs a CompiledMethod for the QuickJniCompiler.
-  CompiledMethod(CompilerDriver* driver,
-                 InstructionSet instruction_set,
-                 const std::vector<uint8_t>& quick_code,
-                 const size_t frame_size_in_bytes,
-                 const uint32_t core_spill_mask,
-                 const uint32_t fp_spill_mask,
-                 const std::vector<uint8_t>* cfi_info);
-
-  // Constructs a CompiledMethod for the Portable compiler.
-  CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set, const std::string& code,
-                 const std::vector<uint8_t>& gc_map, const std::string& symbol);
-
-  // Constructs a CompiledMethod for the Portable JniCompiler.
-  CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set, const std::string& code,
-                 const std::string& symbol);
-
   ~CompiledMethod() {}
 
+  static CompiledMethod* SwapAllocCompiledMethod(
+      CompilerDriver* driver,
+      InstructionSet instruction_set,
+      const ArrayRef<const uint8_t>& quick_code,
+      const size_t frame_size_in_bytes,
+      const uint32_t core_spill_mask,
+      const uint32_t fp_spill_mask,
+      DefaultSrcMap* src_mapping_table,
+      const ArrayRef<const uint8_t>& mapping_table,
+      const ArrayRef<const uint8_t>& vmap_table,
+      const ArrayRef<const uint8_t>& native_gc_map,
+      const ArrayRef<const uint8_t>& cfi_info,
+      const ArrayRef<LinkerPatch>& patches = ArrayRef<LinkerPatch>());
+
+  static CompiledMethod* SwapAllocCompiledMethodStackMap(
+      CompilerDriver* driver,
+      InstructionSet instruction_set,
+      const ArrayRef<const uint8_t>& quick_code,
+      const size_t frame_size_in_bytes,
+      const uint32_t core_spill_mask,
+      const uint32_t fp_spill_mask,
+      const ArrayRef<const uint8_t>& stack_map);
+
+  static CompiledMethod* SwapAllocCompiledMethodCFI(CompilerDriver* driver,
+                                                    InstructionSet instruction_set,
+                                                    const ArrayRef<const uint8_t>& quick_code,
+                                                    const size_t frame_size_in_bytes,
+                                                    const uint32_t core_spill_mask,
+                                                    const uint32_t fp_spill_mask,
+                                                    const ArrayRef<const uint8_t>& cfi_info);
+
+  static void ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m);
+
   size_t GetFrameSizeInBytes() const {
     return frame_size_in_bytes_;
   }
@@ -325,30 +338,29 @@
     return fp_spill_mask_;
   }
 
-  const SrcMap& GetSrcMappingTable() const {
+  const SwapSrcMap& GetSrcMappingTable() const {
     DCHECK(src_mapping_table_ != nullptr);
     return *src_mapping_table_;
   }
 
-  const std::vector<uint8_t>& GetMappingTable() const {
-    DCHECK(mapping_table_ != nullptr);
-    return *mapping_table_;
+  SwapVector<uint8_t> const* GetMappingTable() const {
+    return mapping_table_;
   }
 
-  const std::vector<uint8_t>& GetVmapTable() const {
+  const SwapVector<uint8_t>& GetVmapTable() const {
     DCHECK(vmap_table_ != nullptr);
     return *vmap_table_;
   }
 
-  std::vector<uint8_t> const* GetGcMap() const {
+  SwapVector<uint8_t> const* GetGcMap() const {
     return gc_map_;
   }
 
-  const std::vector<uint8_t>* GetCFIInfo() const {
+  const SwapVector<uint8_t>* GetCFIInfo() const {
     return cfi_info_;
   }
 
-  const std::vector<LinkerPatch>& GetPatches() const {
+  const SwapVector<LinkerPatch>& GetPatches() const {
     return patches_;
   }
 
@@ -360,19 +372,19 @@
   // For quick code, a bit mask describing spilled FPR callee-save registers.
   const uint32_t fp_spill_mask_;
   // For quick code, a set of pairs (PC, Line) mapping from native PC offset to Java line
-  SrcMap* src_mapping_table_;
+  SwapSrcMap* src_mapping_table_;
   // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to
   // native PC offset. Size prefixed.
-  std::vector<uint8_t>* mapping_table_;
+  SwapVector<uint8_t>* mapping_table_;
   // For quick code, a uleb128 encoded map from GPR/FPR register to dex register. Size prefixed.
-  std::vector<uint8_t>* vmap_table_;
+  SwapVector<uint8_t>* vmap_table_;
   // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers
-  // are live. For portable code, the key is a dalvik PC.
-  std::vector<uint8_t>* gc_map_;
+  // are live.
+  SwapVector<uint8_t>* gc_map_;
   // For quick code, a FDE entry for the debug_frame section.
-  std::vector<uint8_t>* cfi_info_;
+  SwapVector<uint8_t>* cfi_info_;
   // For quick code, linker patches needed by the method.
-  std::vector<LinkerPatch> patches_;
+  SwapVector<LinkerPatch> patches_;
 };
 
 }  // namespace art
diff --git a/compiler/compiler.cc b/compiler/compiler.cc
index fbfd8e6..baa6688 100644
--- a/compiler/compiler.cc
+++ b/compiler/compiler.cc
@@ -19,45 +19,10 @@
 #include "base/logging.h"
 #include "dex/quick/quick_compiler.h"
 #include "driver/compiler_driver.h"
-#include "llvm/llvm_compiler.h"
 #include "optimizing/optimizing_compiler.h"
 
 namespace art {
 
-#ifdef ART_SEA_IR_MODE
-extern "C" art::CompiledMethod* SeaIrCompileMethod(const art::DexFile::CodeItem* code_item,
-                                                   uint32_t access_flags,
-                                                   art::InvokeType invoke_type,
-                                                   uint16_t class_def_idx,
-                                                   uint32_t method_idx,
-                                                   jobject class_loader,
-                                                   const art::DexFile& dex_file);
-#endif
-
-
-CompiledMethod* Compiler::TryCompileWithSeaIR(const art::DexFile::CodeItem* code_item,
-                                              uint32_t access_flags,
-                                              art::InvokeType invoke_type,
-                                              uint16_t class_def_idx,
-                                              uint32_t method_idx,
-                                              jobject class_loader,
-                                              const art::DexFile& dex_file) {
-#ifdef ART_SEA_IR_MODE
-    bool use_sea = (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
-    if (use_sea) {
-      LOG(INFO) << "Using SEA IR to compile..." << std::endl;
-      return SeaIrCompileMethod(code_item,
-                                access_flags,
-                                invoke_type,
-                                class_def_idx,
-                                method_idx,
-                                class_loader,
-                                dex_file);
-  }
-#endif
-  return nullptr;
-}
-
 Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) {
   switch (kind) {
     case kQuick:
@@ -66,17 +31,32 @@
     case kOptimizing:
       return CreateOptimizingCompiler(driver);
 
-    case kPortable:
-      {
-        Compiler* compiler = CreateLLVMCompiler(driver);
-        CHECK(compiler != nullptr) << "Portable compiler not compiled";
-        return compiler;
-      }
-
     default:
       LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
   }
-  return nullptr;
+}
+
+bool Compiler::IsPathologicalCase(const DexFile::CodeItem& code_item,
+                                  uint32_t method_idx,
+                                  const DexFile& dex_file) {
+  /*
+   * Skip compilation for pathologically large methods - either by instruction count or num vregs.
+   * Dalvik uses 16-bit uints for instruction and register counts.  We'll limit to a quarter
+   * of that, which also guarantees we cannot overflow our 16-bit internal Quick SSA name space.
+   */
+  if (code_item.insns_size_in_code_units_ >= UINT16_MAX / 4) {
+    LOG(INFO) << "Method exceeds compiler instruction limit: "
+              << code_item.insns_size_in_code_units_
+              << " in " << PrettyMethod(method_idx, dex_file);
+    return true;
+  }
+  if (code_item.registers_size_ >= UINT16_MAX / 4) {
+    LOG(INFO) << "Method exceeds compiler virtual register limit: "
+              << code_item.registers_size_ << " in " << PrettyMethod(method_idx, dex_file);
+    return true;
+  }
+  return false;
 }
 
 }  // namespace art
diff --git a/compiler/compiler.h b/compiler/compiler.h
index 05fa858..d688ead 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -32,24 +32,16 @@
   class ArtMethod;
 }
 
-// Base class for compiler-specific thread-local storage for compiler worker threads
-class CompilerTls {
-  public:
-    CompilerTls() {}
-    ~CompilerTls() {}
-};
-
 class Compiler {
  public:
   enum Kind {
     kQuick,
-    kOptimizing,
-    kPortable
+    kOptimizing
   };
 
   static Compiler* Create(CompilerDriver* driver, Kind kind);
 
-  virtual void Init() const = 0;
+  virtual void Init() = 0;
 
   virtual void UnInit() const = 0;
 
@@ -64,14 +56,6 @@
                                   jobject class_loader,
                                   const DexFile& dex_file) const = 0;
 
-  static CompiledMethod* TryCompileWithSeaIR(const art::DexFile::CodeItem* code_item,
-                                             uint32_t access_flags,
-                                             art::InvokeType invoke_type,
-                                             uint16_t class_def_idx,
-                                             uint32_t method_idx,
-                                             jobject class_loader,
-                                             const art::DexFile& dex_file);
-
   virtual CompiledMethod* JniCompile(uint32_t access_flags,
                                      uint32_t method_idx,
                                      const DexFile& dex_file) const = 0;
@@ -92,15 +76,6 @@
     return maximum_compilation_time_before_warning_;
   }
 
-  virtual bool IsPortable() const {
-    return false;
-  }
-
-  void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
-    UNUSED(driver);
-    UNUSED(filename);
-  }
-
   virtual void InitCompilationUnit(CompilationUnit& cu) const = 0;
 
   virtual ~Compiler() {}
@@ -115,12 +90,15 @@
    */
   virtual std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver)
       const {
+    UNUSED(driver);
     return nullptr;
   }
 
-  virtual CompilerTls* CreateNewCompilerTls() {
-    return nullptr;
-  }
+  // Returns whether the method to compile is such a pathological case that
+  // it's not worth compiling.
+  static bool IsPathologicalCase(const DexFile::CodeItem& code_item,
+                                 uint32_t method_idx,
+                                 const DexFile& dex_file);
 
  protected:
   explicit Compiler(CompilerDriver* driver, uint64_t warning) :
diff --git a/compiler/dex/backend.h b/compiler/dex/backend.h
index cab3427..9cad933 100644
--- a/compiler/dex/backend.h
+++ b/compiler/dex/backend.h
@@ -38,7 +38,7 @@
 
     /*
      * Return the number of reservable vector registers supported
-     * @param long_or_fp ‘true’ if floating point computations will be
+     * @param long_or_fp, true if floating point computations will be
      * executed or the operations will be long type while vector
      * registers are reserved.
      * @return the number of vector registers that are available
@@ -46,7 +46,10 @@
      * are held back to generate scalar code without exhausting vector
      * registers, if scalar code also uses the vector registers.
      */
-    virtual int NumReservableVectorRegisters(bool long_or_fp) { return 0; }
+    virtual int NumReservableVectorRegisters(bool long_or_fp) {
+      UNUSED(long_or_fp);
+      return 0;
+    }
 
   protected:
     explicit Backend(ArenaAllocator* arena) : arena_(arena) {}
diff --git a/compiler/dex/bb_optimizations.cc b/compiler/dex/bb_optimizations.cc
index 6a610ab..11a7e44 100644
--- a/compiler/dex/bb_optimizations.cc
+++ b/compiler/dex/bb_optimizations.cc
@@ -52,19 +52,31 @@
 }
 
 /*
- * BasicBlock Optimization pass implementation start.
+ * MethodUseCount pass implementation start.
  */
-void BBOptimizations::Start(PassDataHolder* data) const {
+bool MethodUseCount::Gate(const PassDataHolder* data) const {
   DCHECK(data != nullptr);
-  CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
+  CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
   DCHECK(c_unit != nullptr);
-  /*
-   * This pass has a different ordering depEnding on the suppress exception,
-   * so do the pass here for now:
-   *   - Later, the Start should just change the ordering and we can move the extended
-   *     creation into the pass driver's main job with a new iterator
-   */
-  c_unit->mir_graph->BasicBlockOptimization();
+  // First initialize the data.
+  c_unit->mir_graph->InitializeMethodUses();
+
+  // Now check if the pass is to be ignored.
+  bool res = ((c_unit->disable_opt & (1 << kPromoteRegs)) == 0);
+
+  return res;
+}
+
+bool MethodUseCount::Worker(PassDataHolder* data) const {
+  DCHECK(data != nullptr);
+  PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
+  CompilationUnit* c_unit = pass_me_data_holder->c_unit;
+  DCHECK(c_unit != nullptr);
+  BasicBlock* bb = pass_me_data_holder->bb;
+  DCHECK(bb != nullptr);
+  c_unit->mir_graph->CountUses(bb);
+  // No need of repeating, so just return false.
+  return false;
 }
 
 }  // namespace art
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h
index b2c348b..aac2644 100644
--- a/compiler/dex/bb_optimizations.h
+++ b/compiler/dex/bb_optimizations.h
@@ -137,20 +137,20 @@
 };
 
 /**
- * @class NullCheckEliminationAndTypeInference
- * @brief Null check elimination and type inference.
+ * @class NullCheckElimination
+ * @brief Null check elimination pass.
  */
-class NullCheckEliminationAndTypeInference : public PassME {
+class NullCheckElimination : public PassME {
  public:
-  NullCheckEliminationAndTypeInference()
-    : PassME("NCE_TypeInference", kRepeatingTopologicalSortTraversal, "4_post_nce_cfg") {
+  NullCheckElimination()
+    : PassME("NCE", kRepeatingPreOrderDFSTraversal, "3_post_nce_cfg") {
   }
 
-  void Start(PassDataHolder* data) const {
+  bool Gate(const PassDataHolder* data) const {
     DCHECK(data != nullptr);
-    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
+    CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
     DCHECK(c_unit != nullptr);
-    c_unit->mir_graph->EliminateNullChecksAndInferTypesStart();
+    return c_unit->mir_graph->EliminateNullChecksGate();
   }
 
   bool Worker(PassDataHolder* data) const {
@@ -160,21 +160,21 @@
     DCHECK(c_unit != nullptr);
     BasicBlock* bb = pass_me_data_holder->bb;
     DCHECK(bb != nullptr);
-    return c_unit->mir_graph->EliminateNullChecksAndInferTypes(bb);
+    return c_unit->mir_graph->EliminateNullChecks(bb);
   }
 
   void End(PassDataHolder* data) const {
     DCHECK(data != nullptr);
     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
     DCHECK(c_unit != nullptr);
-    c_unit->mir_graph->EliminateNullChecksAndInferTypesEnd();
+    c_unit->mir_graph->EliminateNullChecksEnd();
   }
 };
 
 class ClassInitCheckElimination : public PassME {
  public:
   ClassInitCheckElimination()
-    : PassME("ClInitCheckElimination", kLoopRepeatingTopologicalSortTraversal) {
+    : PassME("ClInitCheckElimination", kRepeatingPreOrderDFSTraversal) {
   }
 
   bool Gate(const PassDataHolder* data) const {
@@ -250,19 +250,63 @@
     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;
 };
 
 /**
+ * @class ConstantPropagation
+ * @brief Perform a constant propagation pass.
+ */
+class ConstantPropagation : public PassME {
+ public:
+  ConstantPropagation() : PassME("ConstantPropagation") {
+  }
+
+  void Start(PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    c_unit->mir_graph->InitializeConstantPropagation();
+  }
+
+  bool Worker(PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    BasicBlock* bb = down_cast<PassMEDataHolder*>(data)->bb;
+    DCHECK(bb != nullptr);
+    c_unit->mir_graph->DoConstantPropagation(bb);
+    // No need of repeating, so just return false.
+    return false;
+  }
+};
+
+/**
+ * @class MethodUseCount
+ * @brief Count the register uses of the method
+ */
+class MethodUseCount : public PassME {
+ public:
+  MethodUseCount() : PassME("UseCount") {
+  }
+
+  bool Worker(PassDataHolder* data) const;
+
+  bool Gate(const PassDataHolder* data) const;
+};
+
+/**
  * @class BasicBlock Optimizations
  * @brief Any simple BasicBlock optimization can be put here.
  */
 class BBOptimizations : public PassME {
  public:
-  BBOptimizations() : PassME("BBOptimizations", kNoNodes, "5_post_bbo_cfg") {
+  BBOptimizations()
+      : PassME("BBOptimizations", kNoNodes, kOptimizationBasicBlockChange, "5_post_bbo_cfg") {
   }
 
   bool Gate(const PassDataHolder* data) const {
@@ -272,7 +316,63 @@
     return ((c_unit->disable_opt & (1 << kBBOpt)) == 0);
   }
 
-  void Start(PassDataHolder* data) const;
+  void Start(PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    c_unit->mir_graph->BasicBlockOptimizationStart();
+
+    /*
+     * This pass has a different ordering depending on the suppress exception,
+     * so do the pass here for now:
+     *   - Later, the Start should just change the ordering and we can move the extended
+     *     creation into the pass driver's main job with a new iterator
+     */
+    c_unit->mir_graph->BasicBlockOptimization();
+  }
+
+  void End(PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    c_unit->mir_graph->BasicBlockOptimizationEnd();
+    down_cast<PassMEDataHolder*>(data)->dirty = !c_unit->mir_graph->DfsOrdersUpToDate();
+  }
+};
+
+/**
+ * @class SuspendCheckElimination
+ * @brief Any simple BasicBlock optimization can be put here.
+ */
+class SuspendCheckElimination : public PassME {
+ public:
+  SuspendCheckElimination()
+    : PassME("SuspendCheckElimination", kTopologicalSortTraversal, "6_post_sce_cfg") {
+  }
+
+  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->EliminateSuspendChecksGate();
+  }
+
+  bool Worker(PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
+    CompilationUnit* c_unit = pass_me_data_holder->c_unit;
+    DCHECK(c_unit != nullptr);
+    BasicBlock* bb = pass_me_data_holder->bb;
+    DCHECK(bb != nullptr);
+    return c_unit->mir_graph->EliminateSuspendChecks(bb);
+  }
+
+  void End(PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    c_unit->mir_graph->EliminateSuspendChecksEnd();
+  }
 };
 
 }  // namespace art
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index e4003bf..7edb490 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -28,6 +28,7 @@
   kRefReg,
   kAnyReg,
 };
+std::ostream& operator<<(std::ostream& os, const RegisterClass& rhs);
 
 enum BitsUsed {
   kSize32Bits,
@@ -37,6 +38,7 @@
   kSize512Bits,
   kSize1024Bits,
 };
+std::ostream& operator<<(std::ostream& os, const BitsUsed& rhs);
 
 enum SpecialTargetRegister {
   kSelf,            // Thread pointer.
@@ -60,6 +62,14 @@
   kFArg5,
   kFArg6,
   kFArg7,
+  kFArg8,
+  kFArg9,
+  kFArg10,
+  kFArg11,
+  kFArg12,
+  kFArg13,
+  kFArg14,
+  kFArg15,
   kRet0,
   kRet1,
   kInvokeTgt,
@@ -67,6 +77,7 @@
   kHiddenFpArg,
   kCount
 };
+std::ostream& operator<<(std::ostream& os, const SpecialTargetRegister& code);
 
 enum RegLocationType {
   kLocDalvikFrame = 0,  // Normal Dalvik register
@@ -74,6 +85,7 @@
   kLocCompilerTemp,
   kLocInvalid
 };
+std::ostream& operator<<(std::ostream& os, const RegLocationType& rhs);
 
 enum BBType {
   kNullBlock,
@@ -83,6 +95,7 @@
   kExceptionHandling,
   kDead,
 };
+std::ostream& operator<<(std::ostream& os, const BBType& code);
 
 // Shared pseudo opcodes - must be < 0.
 enum LIRPseudoOpcode {
@@ -103,6 +116,7 @@
   kPseudoEHBlockLabel = -2,
   kPseudoNormalBlockLabel = -1,
 };
+std::ostream& operator<<(std::ostream& os, const LIRPseudoOpcode& rhs);
 
 enum ExtendedMIROpcode {
   kMirOpFirst = kNumPackedOpcodes,
@@ -297,21 +311,51 @@
   // arg[0]: TypeSize (most other vector opcodes have this in vC)
   kMirOpPackedArrayPut,
 
+  // @brief Multiply-add integer.
+  // vA: destination
+  // vB: multiplicand
+  // vC: multiplier
+  // arg[0]: addend
+  kMirOpMaddInt,
+
+  // @brief Multiply-subtract integer.
+  // vA: destination
+  // vB: multiplicand
+  // vC: multiplier
+  // arg[0]: minuend
+  kMirOpMsubInt,
+
+  // @brief Multiply-add long.
+  // vA: destination
+  // vB: multiplicand
+  // vC: multiplier
+  // arg[0]: addend
+  kMirOpMaddLong,
+
+  // @brief Multiply-subtract long.
+  // vA: destination
+  // vB: multiplicand
+  // vC: multiplier
+  // arg[0]: minuend
+  kMirOpMsubLong,
+
   kMirOpLast,
 };
 
 enum MIROptimizationFlagPositions {
   kMIRIgnoreNullCheck = 0,
-  kMIRNullCheckOnly,
   kMIRIgnoreRangeCheck,
-  kMIRRangeCheckOnly,
-  kMIRIgnoreClInitCheck,
+  kMIRStoreNonNullValue,              // Storing non-null value, always mark GC card.
+  kMIRClassIsInitialized,
+  kMIRClassIsInDexCache,
+  kMirIgnoreDivZeroCheck,
   kMIRInlined,                        // Invoke is inlined (ie dead).
   kMIRInlinedPred,                    // Invoke is inlined via prediction.
   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,
 };
@@ -323,11 +367,13 @@
   kPackedSwitch,
   kSparseSwitch,
 };
+std::ostream& operator<<(std::ostream& os, const BlockListType& rhs);
 
 enum AssemblerStatus {
   kSuccess,
   kRetryAll,
 };
+std::ostream& operator<<(std::ostream& os, const AssemblerStatus& rhs);
 
 enum OpSize {
   kWord,            // Natural word size of target (32/64).
@@ -341,7 +387,6 @@
   kUnsignedByte,
   kSignedByte,
 };
-
 std::ostream& operator<<(std::ostream& os, const OpSize& kind);
 
 enum OpKind {
@@ -383,6 +428,7 @@
   kOpBx,
   kOpInvalid,
 };
+std::ostream& operator<<(std::ostream& os, const OpKind& rhs);
 
 enum MoveType {
   kMov8GP,      // Move 8-bit general purpose register.
@@ -399,8 +445,7 @@
   kMovLo128FP,  // Move low 64-bits of 128-bit FP register.
   kMovHi128FP,  // Move high 64-bits of 128-bit FP register.
 };
-
-std::ostream& operator<<(std::ostream& os, const OpKind& kind);
+std::ostream& operator<<(std::ostream& os, const MoveType& kind);
 
 enum ConditionCode {
   kCondEq,  // equal
@@ -422,7 +467,6 @@
   kCondAl,  // always
   kCondNv,  // never
 };
-
 std::ostream& operator<<(std::ostream& os, const ConditionCode& kind);
 
 // Target specific condition encodings
@@ -444,7 +488,6 @@
   kArmCondAl = 0xe,  // 1110
   kArmCondNv = 0xf,  // 1111
 };
-
 std::ostream& operator<<(std::ostream& os, const ArmConditionCode& kind);
 
 enum X86ConditionCode {
@@ -492,7 +535,6 @@
   kX86CondNle = 0xf,    // not-less-than
   kX86CondG   = kX86CondNle,  // greater
 };
-
 std::ostream& operator<<(std::ostream& os, const X86ConditionCode& kind);
 
 enum DividePattern {
@@ -501,7 +543,6 @@
   Divide5,
   Divide7,
 };
-
 std::ostream& operator<<(std::ostream& os, const DividePattern& pattern);
 
 /**
@@ -514,7 +555,7 @@
  * The current recipe is as follows:
  * -# Use AnyStore ~= (LoadStore | StoreStore) ~= release barrier before volatile store.
  * -# Use AnyAny barrier after volatile store.  (StoreLoad is as expensive.)
- * -# Use LoadAny barrier ~= (LoadLoad | LoadStore) ~= acquire barrierafter each volatile load.
+ * -# Use LoadAny barrier ~= (LoadLoad | LoadStore) ~= acquire barrier after each volatile load.
  * -# Use StoreStore barrier after all stores but before return from any constructor whose
  *    class has final fields.
  * -# Use NTStoreStore to order non-temporal stores with respect to all later
@@ -527,7 +568,6 @@
   kAnyAny,
   kNTStoreStore,
 };
-
 std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind);
 
 enum OpFeatureFlags {
@@ -584,6 +624,7 @@
   kDefHi,
   kDefLo
 };
+std::ostream& operator<<(std::ostream& os, const OpFeatureFlags& rhs);
 
 enum SelectInstructionKind {
   kSelectNone,
@@ -591,36 +632,34 @@
   kSelectMove,
   kSelectGoto
 };
-
 std::ostream& operator<<(std::ostream& os, const SelectInstructionKind& kind);
 
-// LIR fixup kinds for Arm
+// LIR fixup kinds for Arm and X86.
 enum FixupKind {
   kFixupNone,
-  kFixupLabel,       // For labels we just adjust the offset.
-  kFixupLoad,        // Mostly for immediates.
-  kFixupVLoad,       // FP load which *may* be pc-relative.
-  kFixupCBxZ,        // Cbz, Cbnz.
-  kFixupTBxZ,        // Tbz, Tbnz.
-  kFixupPushPop,     // Not really pc relative, but changes size based on args.
-  kFixupCondBranch,  // Conditional branch
-  kFixupT1Branch,    // Thumb1 Unconditional branch
-  kFixupT2Branch,    // Thumb2 Unconditional branch
-  kFixupBlx1,        // Blx1 (start of Blx1/Blx2 pair).
-  kFixupBl1,         // Bl1 (start of Bl1/Bl2 pair).
-  kFixupAdr,         // Adr.
-  kFixupMovImmLST,   // kThumb2MovImm16LST.
-  kFixupMovImmHST,   // kThumb2MovImm16HST.
-  kFixupAlign4,      // Align to 4-byte boundary.
+  kFixupLabel,             // For labels we just adjust the offset.
+  kFixupLoad,              // Mostly for immediates.
+  kFixupVLoad,             // FP load which *may* be pc-relative.
+  kFixupCBxZ,              // Cbz, Cbnz.
+  kFixupTBxZ,              // Tbz, Tbnz.
+  kFixupCondBranch,        // Conditional branch
+  kFixupT1Branch,          // Thumb1 Unconditional branch
+  kFixupT2Branch,          // Thumb2 Unconditional branch
+  kFixupBlx1,              // Blx1 (start of Blx1/Blx2 pair).
+  kFixupBl1,               // Bl1 (start of Bl1/Bl2 pair).
+  kFixupAdr,               // Adr.
+  kFixupMovImmLST,         // kThumb2MovImm16LST.
+  kFixupMovImmHST,         // kThumb2MovImm16HST.
+  kFixupAlign4,            // Align to 4-byte boundary.
+  kFixupA53Erratum835769,  // Cortex A53 Erratum 835769.
+  kFixupSwitchTable,       // X86_64 packed switch table.
 };
-
 std::ostream& operator<<(std::ostream& os, const FixupKind& kind);
 
 enum VolatileKind {
   kNotVolatile,      // Load/Store is not volatile
   kVolatile          // Load/Store is volatile
 };
-
 std::ostream& operator<<(std::ostream& os, const VolatileKind& kind);
 
 enum WideKind {
@@ -628,7 +667,6 @@
   kWide,         // Wide view
   kRef           // Ref width
 };
-
 std::ostream& operator<<(std::ostream& os, const WideKind& kind);
 
 }  // namespace art
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/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index f9a05c2..f7968c2 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -120,6 +120,22 @@
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
         break;
 
+      case Instruction::IGET_BOOLEAN:
+        CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false);
+        break;
+
+      case Instruction::IGET_BYTE:
+        CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false);
+        break;
+
+      case Instruction::IGET_CHAR:
+        CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false);
+        break;
+
+      case Instruction::IGET_SHORT:
+        CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false);
+        break;
+
       case Instruction::IPUT:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
         break;
@@ -282,10 +298,11 @@
 }  // namespace art
 
 extern "C" void ArtCompileDEX(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item,
-                  uint32_t access_flags, art::InvokeType invoke_type,
-                  uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
-                  const art::DexFile& dex_file,
-                  art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
+                              uint32_t access_flags, art::InvokeType invoke_type,
+                              uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
+                              const art::DexFile& dex_file,
+                              art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
+  UNUSED(invoke_type);
   if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) {
     art::DexCompilationUnit unit(NULL, class_loader, art::Runtime::Current()->GetClassLinker(),
                                  dex_file, code_item, class_def_idx, method_idx, access_flags,
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 07f3033..dd8b4c8 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,10 +42,12 @@
   // (1 << kNullCheckElimination) |
   // (1 << kClassInitCheckElimination) |
   // (1 << kGlobalValueNumbering) |
+  // (1 << kLocalValueNumbering) |
   // (1 << kPromoteRegs) |
   // (1 << kTrackLiveTemps) |
   // (1 << kSafeOptimizations) |
   // (1 << kBBOpt) |
+  // (1 << kSuspendCheckElimination) |
   // (1 << kMatch) |
   // (1 << kPromoteCompilerTemps) |
   // (1 << kSuppressExceptionEdges) |
@@ -66,8 +69,6 @@
   // (1 << kDebugShowNops) |
   // (1 << kDebugCountOpcodes) |
   // (1 << kDebugDumpCheckStats) |
-  // (1 << kDebugDumpBitcodeFile) |
-  // (1 << kDebugVerifyBitcode) |
   // (1 << kDebugShowSummaryMemoryUsage) |
   // (1 << kDebugShowFilterStats) |
   // (1 << kDebugTimings) |
@@ -82,27 +83,12 @@
                                      jobject class_loader, const DexFile& dex_file,
                                      void* llvm_compilation_unit) {
   VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
-  /*
-   * Skip compilation for pathologically large methods - either by instruction count or num vregs.
-   * Dalvik uses 16-bit uints for instruction and register counts.  We'll limit to a quarter
-   * of that, which also guarantees we cannot overflow our 16-bit internal SSA name space.
-   */
-  if (code_item->insns_size_in_code_units_ >= UINT16_MAX / 4) {
-    LOG(INFO) << "Method exceeds compiler instruction limit: "
-              << code_item->insns_size_in_code_units_
-              << " in " << PrettyMethod(method_idx, dex_file);
-    return NULL;
-  }
-  if (code_item->registers_size_ >= UINT16_MAX / 4) {
-    LOG(INFO) << "Method exceeds compiler virtual register limit: "
-              << code_item->registers_size_ << " in " << PrettyMethod(method_idx, dex_file);
-    return NULL;
-  }
-
-  if (!driver.GetCompilerOptions().IsCompilationEnabled()) {
+  if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) {
     return nullptr;
   }
 
+  DCHECK(driver.GetCompilerOptions().IsCompilationEnabled());
+
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   CompilationUnit cu(driver.GetArenaPool());
 
@@ -133,15 +119,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..4266535 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -41,10 +41,12 @@
   kNullCheckElimination,
   kClassInitCheckElimination,
   kGlobalValueNumbering,
+  kLocalValueNumbering,
   kPromoteRegs,
   kTrackLiveTemps,
   kSafeOptimizations,
   kBBOpt,
+  kSuspendCheckElimination,
   kMatch,
   kPromoteCompilerTemps,
   kBranchFusing,
@@ -68,8 +70,6 @@
   kDebugShowNops,
   kDebugCountOpcodes,
   kDebugDumpCheckStats,
-  kDebugDumpBitcodeFile,
-  kDebugVerifyBitcode,
   kDebugShowSummaryMemoryUsage,
   kDebugShowFilterStats,
   kDebugTimings,
diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc
index af57529..578952b 100644
--- a/compiler/dex/global_value_numbering.cc
+++ b/compiler/dex/global_value_numbering.cc
@@ -15,22 +15,21 @@
  */
 
 #include "global_value_numbering.h"
-
 #include "local_value_numbering.h"
 
 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()),
       array_location_map_(ArrayLocationComparator(), allocator->Adapter()),
       array_location_reverse_map_(allocator->Adapter()),
       ref_set_map_(std::less<ValueNameSet>(), allocator->Adapter()),
@@ -48,19 +47,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_;
@@ -68,12 +67,8 @@
   DCHECK(work_lvn_.get() == nullptr);
   work_lvn_.reset(new (allocator) LocalValueNumbering(this, bb->id, allocator));
   if (bb->block_type == kEntryBlock) {
-    if ((cu_->access_flags & kAccStatic) == 0) {
-      // If non-static method, mark "this" as non-null
-      int this_reg = cu_->mir_graph->GetFirstInVR();
-      uint16_t value_name = work_lvn_->GetSRegValueName(this_reg);
-      work_lvn_->SetValueNameNullChecked(value_name);
-    }
+    work_lvn_->PrepareEntryBlock();
+    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 +78,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);
@@ -110,27 +104,14 @@
     if (bb->catch_entry) {
       merge_type = LocalValueNumbering::kCatchMerge;
     } else if (bb->last_mir_insn != nullptr &&
-        (bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_VOID ||
-         bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN ||
-         bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_OBJECT ||
-         bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_WIDE) &&
-        (bb->first_mir_insn == bb->last_mir_insn ||
-         (static_cast<int>(bb->first_mir_insn->dalvikInsn.opcode) == kMirOpPhi &&
-          (bb->first_mir_insn->next == bb->last_mir_insn ||
-           (static_cast<int>(bb->first_mir_insn->next->dalvikInsn.opcode) == kMirOpPhi &&
-            bb->first_mir_insn->next->next == bb->last_mir_insn))))) {
+        IsInstructionReturn(bb->last_mir_insn->dalvikInsn.opcode) &&
+        bb->GetFirstNonPhiInsn() == bb->last_mir_insn) {
       merge_type = LocalValueNumbering::kReturnMerge;
     }
     // At least one predecessor must have been processed before this bb.
     CHECK(!merge_lvns_.empty());
     if (merge_lvns_.size() == 1u) {
       work_lvn_->MergeOne(*merge_lvns_[0], merge_type);
-      BasicBlock* pred_bb = mir_graph_->GetBasicBlock(merge_lvns_[0]->Id());
-      if (HasNullCheckLastInsn(pred_bb, bb->id)) {
-        int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
-        uint16_t value_name = merge_lvns_[0]->GetSRegValueName(s_reg);
-        work_lvn_->SetValueNameNullChecked(value_name);
-      }
     } else {
       work_lvn_->Merge(merge_type);
     }
@@ -154,19 +135,6 @@
   return change;
 }
 
-uint16_t GlobalValueNumbering::GetFieldId(const MirFieldInfo& field_info, uint16_t type) {
-  FieldReference key = { field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex(), type };
-  auto lb = field_index_map_.lower_bound(key);
-  if (lb != field_index_map_.end() && !field_index_map_.key_comp()(key, lb->first)) {
-    return lb->second;
-  }
-  DCHECK_LT(field_index_map_.size(), kNoValue);
-  uint16_t id = field_index_map_.size();
-  auto it = field_index_map_.PutBefore(lb, key, id);
-  field_index_reverse_map_.push_back(&*it);
-  return id;
-}
-
 uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) {
   auto cmp = array_location_map_.key_comp();
   ArrayLocation key = { base, index };
@@ -216,4 +184,20 @@
   return true;
 }
 
+bool GlobalValueNumbering::DivZeroCheckedInAllPredecessors(
+    const ScopedArenaVector<uint16_t>& merge_names) const {
+  // Implicit parameters:
+  //   - *work_lvn: the LVN for which we're checking predecessors.
+  //   - merge_lvns_: the predecessor LVNs.
+  DCHECK_EQ(merge_lvns_.size(), merge_names.size());
+  for (size_t i = 0, size = merge_lvns_.size(); i != size; ++i) {
+    const LocalValueNumbering* pred_lvn = merge_lvns_[i];
+    uint16_t value_name = merge_names[i];
+    if (!pred_lvn->IsValueDivZeroChecked(value_name)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace art
diff --git a/compiler/dex/global_value_numbering.h b/compiler/dex/global_value_numbering.h
index 27183bf..d72144a 100644
--- a/compiler/dex/global_value_numbering.h
+++ b/compiler/dex/global_value_numbering.h
@@ -19,16 +19,33 @@
 
 #include "base/macros.h"
 #include "compiler_internals.h"
-#include "utils/scoped_arena_containers.h"
+#include "utils/arena_object.h"
 
 namespace art {
 
 class LocalValueNumbering;
 class MirFieldInfo;
 
-class GlobalValueNumbering {
+class GlobalValueNumbering : public DeletableArenaObject<kArenaAllocMisc> {
  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;
+  }
+
+  // Instance and static field id map is held by MIRGraph to avoid multiple recalculations
+  // when doing LVN.
+  template <typename Container>  // Container of MirIFieldLoweringInfo or MirSFieldLoweringInfo.
+  static uint16_t* PrepareGvnFieldIds(ScopedArenaAllocator* allocator,
+                                      const Container& field_infos);
+
+  GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator, Mode mode);
   ~GlobalValueNumbering();
 
   // Prepare LVN for the basic block.
@@ -44,34 +61,17 @@
   }
 
   // Allow modifications.
-  void AllowModifications() {
-    DCHECK(Good());
-    modifications_allowed_ = true;
-  }
+  void StartPostProcessing();
 
   bool CanModify() const {
-    // TODO: DCHECK(Good()), see AllowModifications() and NewValueName().
     return modifications_allowed_ && Good();
   }
 
-  // GlobalValueNumbering should be allocated on the ArenaStack (or the native stack).
-  static void* operator new(size_t size, ScopedArenaAllocator* allocator) {
-    return allocator->Alloc(sizeof(GlobalValueNumbering), kArenaAllocMisc);
-  }
-
-  // Allow delete-expression to destroy a GlobalValueNumbering object without deallocation.
-  static void operator delete(void* ptr) { UNUSED(ptr); }
-
  private:
   static constexpr uint16_t kNoValue = 0xffffu;
 
   // Allocate a new value name.
-  uint16_t NewValueName() {
-    // TODO: No new values should be needed once we allow modifications.
-    // DCHECK(!modifications_allowed_);
-    ++last_value_;
-    return last_value_;
-  }
+  uint16_t NewValueName();
 
   // Key is concatenation of opcode, operand1, operand2 and modifier, value is value name.
   typedef ScopedArenaSafeMap<uint64_t, uint16_t> ValueMap;
@@ -95,6 +95,19 @@
     return res;
   }
 
+  // Look up a value in the global value map, don't add a new entry if there was none before.
+  uint16_t FindValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier) {
+    uint16_t res;
+    uint64_t key = BuildKey(op, operand1, operand2, modifier);
+    ValueMap::iterator lb = global_value_map_.lower_bound(key);
+    if (lb != global_value_map_.end() && lb->first == key) {
+      res = lb->second;
+    } else {
+      res = kNoValue;
+    }
+    return res;
+  }
+
   // Check if the exact value is stored in the global value map.
   bool HasValue(uint16_t op, uint16_t operand1, uint16_t operand2, uint16_t modifier,
                 uint16_t value) const {
@@ -107,34 +120,24 @@
     return (it != global_value_map_.end() && it->second == value);
   }
 
-  // FieldReference represents a unique resolved field.
-  struct FieldReference {
-    const DexFile* dex_file;
-    uint16_t field_idx;
-    uint16_t type;  // See comments for LocalValueNumbering::kFieldTypeCount.
-  };
+  // Get an instance field id.
+  uint16_t GetIFieldId(MIR* mir) {
+    return GetMirGraph()->GetGvnIFieldId(mir);
+  }
 
-  struct FieldReferenceComparator {
-    bool operator()(const FieldReference& lhs, const FieldReference& rhs) const {
-      if (lhs.field_idx != rhs.field_idx) {
-        return lhs.field_idx < rhs.field_idx;
-      }
-      // If the field_idx and dex_file match, the type must also match.
-      DCHECK(lhs.dex_file != rhs.dex_file || lhs.type == rhs.type);
-      return lhs.dex_file < rhs.dex_file;
-    }
-  };
+  // Get a static field id.
+  uint16_t GetSFieldId(MIR* mir) {
+    return GetMirGraph()->GetGvnSFieldId(mir);
+  }
 
-  // Maps field key to field id for resolved fields.
-  typedef ScopedArenaSafeMap<FieldReference, uint32_t, FieldReferenceComparator> FieldIndexMap;
+  // Get an instance field type based on field id.
+  uint16_t GetIFieldType(uint16_t field_id) {
+    return static_cast<uint16_t>(GetMirGraph()->GetIFieldLoweringInfo(field_id).MemAccessType());
+  }
 
-  // Get a field id.
-  uint16_t GetFieldId(const MirFieldInfo& field_info, uint16_t type);
-
-  // Get a field type based on field id.
-  uint16_t GetFieldType(uint16_t field_id) {
-    DCHECK_LT(field_id, field_index_reverse_map_.size());
-    return field_index_reverse_map_[field_id]->first.type;
+  // Get a static field type based on field id.
+  uint16_t GetSFieldType(uint16_t field_id) {
+    return static_cast<uint16_t>(GetMirGraph()->GetSFieldLoweringInfo(field_id).MemAccessType());
   }
 
   struct ArrayLocation {
@@ -192,6 +195,8 @@
 
   bool NullCheckedInAllPredecessors(const ScopedArenaVector<uint16_t>& merge_names) const;
 
+  bool DivZeroCheckedInAllPredecessors(const ScopedArenaVector<uint16_t>& merge_names) const;
+
   CompilationUnit* GetCompilationUnit() const {
     return cu_;
   }
@@ -205,9 +210,12 @@
   }
 
   CompilationUnit* const cu_;
-  MIRGraph* mir_graph_;
+  MIRGraph* const 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,9 +233,10 @@
   // 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_;
   ArrayLocationMap array_location_map_;
   ScopedArenaVector<const ArrayLocationMap::value_type*> array_location_reverse_map_;
   RefSetIdMap ref_set_map_;
@@ -237,9 +246,49 @@
   ScopedArenaVector<const LocalValueNumbering*> merge_lvns_;  // Not owning.
 
   friend class LocalValueNumbering;
+  friend class GlobalValueNumberingTest;
 
   DISALLOW_COPY_AND_ASSIGN(GlobalValueNumbering);
 };
+std::ostream& operator<<(std::ostream& os, const GlobalValueNumbering::Mode& rhs);
+
+inline  void GlobalValueNumbering::StartPostProcessing() {
+  DCHECK(Good());
+  DCHECK_EQ(mode_, kModeGvn);
+  mode_ = kModeGvnPostProcessing;
+}
+
+inline uint16_t GlobalValueNumbering::NewValueName() {
+  DCHECK_NE(mode_, kModeGvnPostProcessing);
+  ++last_value_;
+  return last_value_;
+}
+
+template <typename Container>  // Container of MirIFieldLoweringInfo or MirSFieldLoweringInfo.
+uint16_t* GlobalValueNumbering::PrepareGvnFieldIds(ScopedArenaAllocator* allocator,
+                                                   const Container& field_infos) {
+  size_t size = field_infos.size();
+  uint16_t* field_ids = reinterpret_cast<uint16_t*>(allocator->Alloc(size * sizeof(uint16_t),
+                                                                     kArenaAllocMisc));
+  for (size_t i = 0u; i != size; ++i) {
+    size_t idx = i;
+    const MirFieldInfo& cur_info = field_infos[i];
+    if (cur_info.IsResolved()) {
+      for (size_t j = 0; j != i; ++j) {
+        const MirFieldInfo& prev_info = field_infos[j];
+        if (prev_info.IsResolved() &&
+            prev_info.DeclaringDexFile() == cur_info.DeclaringDexFile() &&
+            prev_info.DeclaringFieldIndex() == cur_info.DeclaringFieldIndex()) {
+          DCHECK_EQ(cur_info.MemAccessType(), prev_info.MemAccessType());
+          idx = j;
+          break;
+        }
+      }
+    }
+    field_ids[i] = idx;
+  }
+  return field_ids;
+}
 
 }  // namespace art
 
diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc
index 1d9920d..18e3469 100644
--- a/compiler/dex/global_value_numbering_test.cc
+++ b/compiler/dex/global_value_numbering_test.cc
@@ -17,6 +17,7 @@
 #include "compiler_internals.h"
 #include "dataflow_iterator.h"
 #include "dataflow_iterator-inl.h"
+#include "dex/mir_field_info.h"
 #include "global_value_numbering.h"
 #include "local_value_numbering.h"
 #include "gtest/gtest.h"
@@ -25,11 +26,14 @@
 
 class GlobalValueNumberingTest : public testing::Test {
  protected:
+  static constexpr uint16_t kNoValue = GlobalValueNumbering::kNoValue;
+
   struct IFieldDef {
     uint16_t field_idx;
     uintptr_t declaring_dex_file;
     uint16_t declaring_field_idx;
     bool is_volatile;
+    DexMemAccessType type;
   };
 
   struct SFieldDef {
@@ -37,6 +41,7 @@
     uintptr_t declaring_dex_file;
     uint16_t declaring_field_idx;
     bool is_volatile;
+    DexMemAccessType type;
   };
 
   struct BBDef {
@@ -125,20 +130,23 @@
     { bb, opcode, 0u, 0u, 1, { reg }, 0, { } }
 #define DEF_MOVE(bb, opcode, reg, src) \
     { bb, opcode, 0u, 0u, 1, { src }, 1, { reg } }
+#define DEF_MOVE_WIDE(bb, opcode, reg, src) \
+    { bb, opcode, 0u, 0u, 2, { src, src + 1 }, 2, { reg, reg + 1 } }
 #define DEF_PHI2(bb, reg, src1, src2) \
     { bb, static_cast<Instruction::Code>(kMirOpPhi), 0, 0u, 2u, { src1, src2 }, 1, { reg } }
+#define DEF_DIV_REM(bb, opcode, result, dividend, divisor) \
+    { bb, opcode, 0u, 0u, 2, { dividend, divisor }, 1, { result } }
 
   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);
+      MirIFieldLoweringInfo field_info(def->field_idx, def->type);
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
-        field_info.flags_ = 0u |  // Without kFlagIsStatic.
-            (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u);
+        field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile);
       }
       cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
     }
@@ -154,14 +162,14 @@
     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);
+      MirSFieldLoweringInfo field_info(def->field_idx, def->type);
       // Mark even unresolved fields as initialized.
-      field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic |
-          MirSFieldLoweringInfo::kFlagIsInitialized;
+      field_info.flags_ |= MirSFieldLoweringInfo::kFlagClassIsInitialized;
+      // NOTE: MirSFieldLoweringInfo::kFlagClassIsInDexCache isn't used by GVN.
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
-        field_info.flags_ |= (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u);
+        field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile);
       }
       cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
     }
@@ -207,7 +215,6 @@
         bb->data_flow_info->live_in_v = live_in_v_;
       }
     }
-    cu_.mir_graph->num_blocks_ = count;
     ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
     cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
     ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
@@ -233,12 +240,16 @@
       mir->dalvikInsn.opcode = def->opcode;
       mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
       mir->dalvikInsn.vB_wide = def->value;
-      if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
+      if (IsInstructionIGetOrIPut(def->opcode)) {
         ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size());
         mir->meta.ifield_lowering_info = def->field_info;
-      } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
+        ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_info].MemAccessType(),
+                  IGetOrIPutMemAccessType(def->opcode));
+      } else if (IsInstructionSGetOrSPut(def->opcode)) {
         ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size());
         mir->meta.sfield_lowering_info = def->field_info;
+        ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_info].MemAccessType(),
+                  SGetOrSPutMemAccessType(def->opcode));
       } else if (def->opcode == static_cast<Instruction::Code>(kMirOpPhi)) {
         mir->meta.phi_incoming = static_cast<BasicBlockId*>(
             allocator_->Alloc(def->num_uses * sizeof(BasicBlockId), kArenaAllocDFInfo));
@@ -283,9 +294,13 @@
     cu_.mir_graph->ComputeDominators();
     cu_.mir_graph->ComputeTopologicalSortOrder();
     cu_.mir_graph->SSATransformationEnd();
+    cu_.mir_graph->temp_.gvn.ifield_ids_ =  GlobalValueNumbering::PrepareGvnFieldIds(
+        allocator_.get(), cu_.mir_graph->ifield_lowering_infos_);
+    cu_.mir_graph->temp_.gvn.sfield_ids_ =  GlobalValueNumbering::PrepareGvnFieldIds(
+        allocator_.get(), cu_.mir_graph->sfield_lowering_infos_);
     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 +319,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);
@@ -342,6 +356,8 @@
       cu_.mir_graph->ssa_base_vregs_.push_back(i);
       cu_.mir_graph->ssa_subscripts_.push_back(0);
     }
+    // Set shorty for a void-returning method without arguments.
+    cu_.shorty = "V";
   }
 
   static constexpr size_t kMaxSsaRegs = 16384u;
@@ -357,6 +373,8 @@
   ArenaBitVector* live_in_v_;
 };
 
+constexpr uint16_t GlobalValueNumberingTest::kNoValue;
+
 class GlobalValueNumberingTestDiamond : public GlobalValueNumberingTest {
  public:
   GlobalValueNumberingTestDiamond();
@@ -490,18 +508,18 @@
 
 TEST_F(GlobalValueNumberingTestDiamond, NonAliasingIFields) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Int.
-      { 4u, 1u, 4u, false },  // Short.
-      { 5u, 1u, 5u, false },  // Char.
-      { 6u, 0u, 0u, false },  // Unresolved, Short.
-      { 7u, 1u, 7u, false },  // Int.
-      { 8u, 0u, 0u, false },  // Unresolved, Int.
-      { 9u, 1u, 9u, false },  // Int.
-      { 10u, 1u, 10u, false },  // Int.
-      { 11u, 1u, 11u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
+      { 4u, 1u, 4u, false, kDexMemAccessShort },
+      { 5u, 1u, 5u, false, kDexMemAccessChar },
+      { 6u, 0u, 0u, false, kDexMemAccessShort },   // Unresolved.
+      { 7u, 1u, 7u, false, kDexMemAccessWord },
+      { 8u, 0u, 0u, false, kDexMemAccessWord },    // Unresolved.
+      { 9u, 1u, 9u, false, kDexMemAccessWord },
+      { 10u, 1u, 10u, false, kDexMemAccessWord },
+      { 11u, 1u, 11u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -596,15 +614,15 @@
 
 TEST_F(GlobalValueNumberingTestDiamond, AliasingIFieldsSingleObject) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Int.
-      { 4u, 1u, 4u, false },  // Short.
-      { 5u, 1u, 5u, false },  // Char.
-      { 6u, 0u, 0u, false },  // Unresolved, Short.
-      { 7u, 1u, 7u, false },  // Int.
-      { 8u, 1u, 8u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
+      { 4u, 1u, 4u, false, kDexMemAccessShort },
+      { 5u, 1u, 5u, false, kDexMemAccessChar },
+      { 6u, 0u, 0u, false, kDexMemAccessShort },  // Unresolved.
+      { 7u, 1u, 7u, false, kDexMemAccessWord },
+      { 8u, 1u, 8u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -663,15 +681,15 @@
 
 TEST_F(GlobalValueNumberingTestDiamond, AliasingIFieldsTwoObjects) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Int.
-      { 4u, 1u, 4u, false },  // Short.
-      { 5u, 1u, 5u, false },  // Char.
-      { 6u, 0u, 0u, false },  // Unresolved, Short.
-      { 7u, 1u, 7u, false },  // Int.
-      { 8u, 1u, 8u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
+      { 4u, 1u, 4u, false, kDexMemAccessShort },
+      { 5u, 1u, 5u, false, kDexMemAccessChar },
+      { 6u, 0u, 0u, false, kDexMemAccessShort },   // Unresolved.
+      { 7u, 1u, 7u, false, kDexMemAccessWord },
+      { 8u, 1u, 8u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -732,15 +750,15 @@
 
 TEST_F(GlobalValueNumberingTestDiamond, SFields) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Int.
-      { 4u, 1u, 4u, false },  // Short.
-      { 5u, 1u, 5u, false },  // Char.
-      { 6u, 0u, 0u, false },  // Unresolved, Short.
-      { 7u, 1u, 7u, false },  // Int.
-      { 8u, 1u, 8u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
+      { 4u, 1u, 4u, false, kDexMemAccessShort },
+      { 5u, 1u, 5u, false, kDexMemAccessChar },
+      { 6u, 0u, 0u, false, kDexMemAccessShort },   // Unresolved.
+      { 7u, 1u, 7u, false, kDexMemAccessWord },
+      { 8u, 1u, 8u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -982,20 +1000,106 @@
   EXPECT_EQ(value_names_[18], value_names_[21]);
 }
 
+TEST_F(GlobalValueNumberingTestDiamond, PhiWide) {
+  static const MIRDef mirs[] = {
+      DEF_CONST_WIDE(3, Instruction::CONST_WIDE, 0u, 1000),
+      DEF_CONST_WIDE(4, Instruction::CONST_WIDE, 2u, 2000),
+      DEF_CONST_WIDE(5, Instruction::CONST_WIDE, 4u, 3000),
+      DEF_MOVE_WIDE(4, Instruction::MOVE_WIDE, 6u, 0u),
+      DEF_MOVE_WIDE(4, Instruction::MOVE_WIDE, 8u, 2u),
+      DEF_MOVE_WIDE(5, Instruction::MOVE_WIDE, 10u, 0u),
+      DEF_MOVE_WIDE(5, Instruction::MOVE_WIDE, 12u, 4u),
+      DEF_PHI2(6, 14u, 6u, 10u),    // Same as CONST_WIDE 0u (1000).
+      DEF_PHI2(6, 15u, 7u, 11u),    // Same as CONST_WIDE 0u (1000), high word.
+      DEF_PHI2(6, 16u, 6u,  0u),    // Same as CONST_WIDE 0u (1000).
+      DEF_PHI2(6, 17u, 7u,  1u),    // Same as CONST_WIDE 0u (1000), high word.
+      DEF_PHI2(6, 18u, 0u, 10u),    // Same as CONST_WIDE 0u (1000).
+      DEF_PHI2(6, 19u, 1u, 11u),    // Same as CONST_WIDE 0u (1000), high word.
+      DEF_PHI2(6, 20u, 8u, 10u),    // Merge 2u (2000) and 0u (1000).
+      DEF_PHI2(6, 21u, 9u, 11u),    // Merge 2u (2000) and 0u (1000), high word.
+      DEF_PHI2(6, 22u, 2u, 10u),    // Merge 2u (2000) and 0u (1000).
+      DEF_PHI2(6, 23u, 3u, 11u),    // Merge 2u (2000) and 0u (1000), high word.
+      DEF_PHI2(6, 24u, 8u,  0u),    // Merge 2u (2000) and 0u (1000).
+      DEF_PHI2(6, 25u, 9u,  1u),    // Merge 2u (2000) and 0u (1000), high word.
+      DEF_PHI2(6, 26u, 2u,  0u),    // Merge 2u (2000) and 0u (1000).
+      DEF_PHI2(6, 27u, 5u,  1u),    // Merge 2u (2000) and 0u (1000), high word.
+      DEF_PHI2(6, 28u, 6u, 12u),    // Merge 0u (1000) and 4u (3000).
+      DEF_PHI2(6, 29u, 7u, 13u),    // Merge 0u (1000) and 4u (3000), high word.
+      DEF_PHI2(6, 30u, 0u, 12u),    // Merge 0u (1000) and 4u (3000).
+      DEF_PHI2(6, 31u, 1u, 13u),    // Merge 0u (1000) and 4u (3000), high word.
+      DEF_PHI2(6, 32u, 6u,  4u),    // Merge 0u (1000) and 4u (3000).
+      DEF_PHI2(6, 33u, 7u,  5u),    // Merge 0u (1000) and 4u (3000), high word.
+      DEF_PHI2(6, 34u, 0u,  4u),    // Merge 0u (1000) and 4u (3000).
+      DEF_PHI2(6, 35u, 1u,  5u),    // Merge 0u (1000) and 4u (3000), high word.
+      DEF_PHI2(6, 36u, 8u, 12u),    // Merge 2u (2000) and 4u (3000).
+      DEF_PHI2(6, 37u, 9u, 13u),    // Merge 2u (2000) and 4u (3000), high word.
+      DEF_PHI2(6, 38u, 2u, 12u),    // Merge 2u (2000) and 4u (3000).
+      DEF_PHI2(6, 39u, 3u, 13u),    // Merge 2u (2000) and 4u (3000), high word.
+      DEF_PHI2(6, 40u, 8u,  4u),    // Merge 2u (2000) and 4u (3000).
+      DEF_PHI2(6, 41u, 9u,  5u),    // Merge 2u (2000) and 4u (3000), high word.
+      DEF_PHI2(6, 42u, 2u,  4u),    // Merge 2u (2000) and 4u (3000).
+      DEF_PHI2(6, 43u, 3u,  5u),    // Merge 2u (2000) and 4u (3000), high word.
+  };
+
+  PrepareMIRs(mirs);
+  PerformGVN();
+  ASSERT_EQ(arraysize(mirs), value_names_.size());
+  EXPECT_EQ(value_names_[0], value_names_[7]);
+  EXPECT_EQ(value_names_[0], value_names_[9]);
+  EXPECT_EQ(value_names_[0], value_names_[11]);
+  EXPECT_NE(value_names_[13], value_names_[0]);
+  EXPECT_NE(value_names_[13], value_names_[1]);
+  EXPECT_NE(value_names_[13], value_names_[2]);
+  EXPECT_EQ(value_names_[13], value_names_[15]);
+  EXPECT_EQ(value_names_[13], value_names_[17]);
+  EXPECT_EQ(value_names_[13], value_names_[19]);
+  EXPECT_NE(value_names_[21], value_names_[0]);
+  EXPECT_NE(value_names_[21], value_names_[1]);
+  EXPECT_NE(value_names_[21], value_names_[2]);
+  EXPECT_NE(value_names_[21], value_names_[13]);
+  EXPECT_EQ(value_names_[21], value_names_[23]);
+  EXPECT_EQ(value_names_[21], value_names_[25]);
+  EXPECT_EQ(value_names_[21], value_names_[27]);
+  EXPECT_NE(value_names_[29], value_names_[0]);
+  EXPECT_NE(value_names_[29], value_names_[1]);
+  EXPECT_NE(value_names_[29], value_names_[2]);
+  EXPECT_NE(value_names_[29], value_names_[13]);
+  EXPECT_NE(value_names_[29], value_names_[21]);
+  EXPECT_EQ(value_names_[29], value_names_[31]);
+  EXPECT_EQ(value_names_[29], value_names_[33]);
+  EXPECT_EQ(value_names_[29], value_names_[35]);
+  // High words should get kNoValue.
+  EXPECT_EQ(value_names_[8], kNoValue);
+  EXPECT_EQ(value_names_[10], kNoValue);
+  EXPECT_EQ(value_names_[12], kNoValue);
+  EXPECT_EQ(value_names_[14], kNoValue);
+  EXPECT_EQ(value_names_[16], kNoValue);
+  EXPECT_EQ(value_names_[18], kNoValue);
+  EXPECT_EQ(value_names_[20], kNoValue);
+  EXPECT_EQ(value_names_[22], kNoValue);
+  EXPECT_EQ(value_names_[24], kNoValue);
+  EXPECT_EQ(value_names_[26], kNoValue);
+  EXPECT_EQ(value_names_[28], kNoValue);
+  EXPECT_EQ(value_names_[30], kNoValue);
+  EXPECT_EQ(value_names_[32], kNoValue);
+  EXPECT_EQ(value_names_[34], kNoValue);
+  EXPECT_EQ(value_names_[36], kNoValue);
+}
+
 TEST_F(GlobalValueNumberingTestLoop, NonAliasingIFields) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Int.
-      { 4u, 1u, 4u, false },  // Int.
-      { 5u, 1u, 5u, false },  // Short.
-      { 6u, 1u, 6u, false },  // Char.
-      { 7u, 0u, 0u, false },  // Unresolved, Short.
-      { 8u, 1u, 8u, false },  // Int.
-      { 9u, 0u, 0u, false },  // Unresolved, Int.
-      { 10u, 1u, 10u, false },  // Int.
-      { 11u, 1u, 11u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
+      { 4u, 1u, 4u, false, kDexMemAccessWord },
+      { 5u, 1u, 5u, false, kDexMemAccessShort },
+      { 6u, 1u, 6u, false, kDexMemAccessChar },
+      { 7u, 0u, 0u, false, kDexMemAccessShort },   // Unresolved.
+      { 8u, 1u, 8u, false, kDexMemAccessWord },
+      { 9u, 0u, 0u, false, kDexMemAccessWord },    // Unresolved.
+      { 10u, 1u, 10u, false, kDexMemAccessWord },
+      { 11u, 1u, 11u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -1107,14 +1211,14 @@
 
 TEST_F(GlobalValueNumberingTestLoop, AliasingIFieldsSingleObject) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Int.
-      { 4u, 1u, 4u, false },  // Int.
-      { 5u, 1u, 5u, false },  // Short.
-      { 6u, 1u, 6u, false },  // Char.
-      { 7u, 0u, 0u, false },  // Unresolved, Short.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
+      { 4u, 1u, 4u, false, kDexMemAccessWord },
+      { 5u, 1u, 5u, false, kDexMemAccessShort },
+      { 6u, 1u, 6u, false, kDexMemAccessChar },
+      { 7u, 0u, 0u, false, kDexMemAccessShort },   // Unresolved.
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -1178,14 +1282,14 @@
 
 TEST_F(GlobalValueNumberingTestLoop, AliasingIFieldsTwoObjects) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
-      { 3u, 1u, 3u, false },  // Short.
-      { 4u, 1u, 4u, false },  // Char.
-      { 5u, 0u, 0u, false },  // Unresolved, Short.
-      { 6u, 1u, 6u, false },  // Int.
-      { 7u, 1u, 7u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
+      { 3u, 1u, 3u, false, kDexMemAccessShort },
+      { 4u, 1u, 4u, false, kDexMemAccessChar },
+      { 5u, 0u, 0u, false, kDexMemAccessShort },   // Unresolved.
+      { 6u, 1u, 6u, false, kDexMemAccessWord },
+      { 7u, 1u, 7u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -1247,7 +1351,7 @@
 
 TEST_F(GlobalValueNumberingTestLoop, IFieldToBaseDependency) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // For the IGET that loads sreg 3u using base 2u, the following IPUT creates a dependency
@@ -1272,9 +1376,9 @@
 
 TEST_F(GlobalValueNumberingTestLoop, SFields) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
-      { 2u, 1u, 2u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
@@ -1468,8 +1572,8 @@
 
 TEST_F(GlobalValueNumberingTestCatch, IFields) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },
-      { 1u, 1u, 1u, false },
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 200u),
@@ -1514,8 +1618,8 @@
 
 TEST_F(GlobalValueNumberingTestCatch, SFields) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },
-      { 1u, 1u, 1u, false },
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_SGET(3, Instruction::SGET, 0u, 0u),
@@ -1637,8 +1741,8 @@
 
 TEST_F(GlobalValueNumberingTest, NullCheckIFields) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Object.
-      { 1u, 1u, 1u, false },  // Object.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },  // Object.
+      { 1u, 1u, 1u, false, kDexMemAccessObject },  // Object.
   };
   static const BBDef bbs[] = {
       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
@@ -1686,8 +1790,8 @@
 
 TEST_F(GlobalValueNumberingTest, NullCheckSFields) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },  // Object.
-      { 1u, 1u, 1u, false },  // Object.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
+      { 1u, 1u, 1u, false, kDexMemAccessObject },
   };
   static const BBDef bbs[] = {
       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
@@ -1813,12 +1917,12 @@
 
 TEST_F(GlobalValueNumberingTestDiamond, MergeSameValueInDifferentMemoryLocations) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },  // Int.
-      { 1u, 1u, 1u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessWord },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 100u),
@@ -1883,7 +1987,7 @@
   // LVN's aliasing_array_value_map_'s load_value_map for BBs #9, #4, #5, #7 because of the
   // DFS ordering of LVN evaluation.
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Object.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
   };
   static const BBDef bbs[] = {
       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
@@ -1921,7 +2025,7 @@
 
 TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, IFieldAndPhi) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
   };
   static const MIRDef mirs[] = {
       DEF_MOVE(3, Instruction::MOVE_OBJECT, 0u, 100u),
@@ -1958,10 +2062,10 @@
 
 TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, NullCheck) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
   };
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
   };
   static const MIRDef mirs[] = {
       DEF_MOVE(3, Instruction::MOVE_OBJECT, 0u, 100u),
@@ -2049,7 +2153,7 @@
 
 TEST_F(GlobalValueNumberingTestTwoNestedLoops, IFieldAndPhi) {
   static const IFieldDef ifields[] = {
-      { 0u, 1u, 0u, false },  // Int.
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
   };
   static const MIRDef mirs[] = {
       DEF_MOVE(3, Instruction::MOVE_OBJECT, 0u, 100u),
@@ -2119,4 +2223,45 @@
   PerformGVN();
 }
 
+TEST_F(GlobalValueNumberingTestDiamond, DivZeroCheckDiamond) {
+  static const MIRDef mirs[] = {
+      DEF_DIV_REM(3u, Instruction::DIV_INT, 1u, 20u, 21u),
+      DEF_DIV_REM(3u, Instruction::DIV_INT, 2u, 24u, 21u),
+      DEF_DIV_REM(3u, Instruction::DIV_INT, 3u, 20u, 23u),
+      DEF_DIV_REM(4u, Instruction::DIV_INT, 4u, 24u, 22u),
+      DEF_DIV_REM(4u, Instruction::DIV_INT, 9u, 24u, 25u),
+      DEF_DIV_REM(5u, Instruction::DIV_INT, 5u, 24u, 21u),
+      DEF_DIV_REM(5u, Instruction::DIV_INT, 10u, 24u, 26u),
+      DEF_PHI2(6u, 27u, 25u, 26u),
+      DEF_DIV_REM(6u, Instruction::DIV_INT, 12u, 20u, 27u),
+      DEF_DIV_REM(6u, Instruction::DIV_INT, 6u, 24u, 21u),
+      DEF_DIV_REM(6u, Instruction::DIV_INT, 7u, 20u, 23u),
+      DEF_DIV_REM(6u, Instruction::DIV_INT, 8u, 20u, 22u),
+  };
+
+  static const bool expected_ignore_div_zero_check[] = {
+      false,  // New divisor seen.
+      true,   // Eliminated since it has first divisor as first one.
+      false,  // New divisor seen.
+      false,  // New divisor seen.
+      false,  // New divisor seen.
+      true,   // Eliminated in dominating block.
+      false,  // New divisor seen.
+      false,  // Phi node.
+      true,   // Eliminated on both sides of diamond and merged via phi.
+      true,   // Eliminated in dominating block.
+      true,   // Eliminated in dominating block.
+      false,  // Only eliminated on one path of diamond.
+  };
+
+  PrepareMIRs(mirs);
+  PerformGVN();
+  PerformGVNCodeModifications();
+  ASSERT_EQ(arraysize(expected_ignore_div_zero_check), mir_count_);
+  for (size_t i = 0u; i != mir_count_; ++i) {
+    int expected = expected_ignore_div_zero_check[i] ? MIR_IGNORE_DIV_ZERO_CHECK : 0u;
+    EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
+  }
+}
+
 }  // namespace art
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index e411164..114346d 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -56,7 +56,7 @@
  public:
   static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
                                      uint16_t field_id) {
-    uint16_t type = gvn->GetFieldType(field_id);
+    uint16_t type = gvn->GetIFieldType(field_id);
     return gvn->LookupValue(kAliasingIFieldStartVersionOp, field_id,
                             lvn->global_memory_version_, lvn->unresolved_ifield_version_[type]);
   }
@@ -75,7 +75,7 @@
   static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
                                    uint16_t field_id, uint16_t base) {
     // If the base/field_id is non-aliasing in lvn, use the non-aliasing value.
-    uint16_t type = gvn->GetFieldType(field_id);
+    uint16_t type = gvn->GetIFieldType(field_id);
     if (lvn->IsNonAliasingIField(base, field_id, type)) {
       uint16_t loc = gvn->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
       auto lb = lvn->non_aliasing_ifield_value_map_.find(loc);
@@ -89,7 +89,7 @@
 
   static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
                                 uint16_t field_id) {
-    uint16_t type = gvn->GetFieldType(field_id);
+    uint16_t type = gvn->GetIFieldType(field_id);
     return lvn->unresolved_ifield_version_[type] == lvn->merge_new_memory_version_ ||
         lvn->global_memory_version_ == lvn->merge_new_memory_version_;
   }
@@ -107,7 +107,8 @@
 
 class LocalValueNumbering::NonAliasingArrayVersions {
  public:
-  static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
+  static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn,
+                                     const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
                                      uint16_t array) {
     return gvn->LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, kNoValue);
   }
@@ -129,8 +130,9 @@
         gvn, lvn, &lvn->non_aliasing_array_value_map_, array, index);
   }
 
-  static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
-                                uint16_t array) {
+  static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
+                                const LocalValueNumbering* lvn ATTRIBUTE_UNUSED,
+                                uint16_t array ATTRIBUTE_UNUSED) {
     return false;  // Not affected by global_memory_version_.
   }
 
@@ -164,8 +166,9 @@
     return gvn->LookupValue(kAliasingArrayOp, type, location, memory_version);
   }
 
-  static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
-                                   uint16_t type, uint16_t location) {
+  static uint16_t LookupMergeValue(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
+                                   const LocalValueNumbering* lvn,
+                                   uint16_t type ATTRIBUTE_UNUSED, uint16_t location) {
     // If the location is non-aliasing in lvn, use the non-aliasing value.
     uint16_t array = gvn->GetArrayLocationBase(location);
     if (lvn->IsNonAliasingArray(array, type)) {
@@ -176,8 +179,11 @@
         gvn, lvn, &lvn->aliasing_array_value_map_, type, location);
   }
 
-  static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn,
-                                uint16_t type) {
+  static bool HasNewBaseVersion(GlobalValueNumbering* gvn ATTRIBUTE_UNUSED,
+                                const LocalValueNumbering* lvn,
+                                uint16_t type ATTRIBUTE_UNUSED) {
+    UNUSED(gvn);
+    UNUSED(type);
     return lvn->global_memory_version_ == lvn->merge_new_memory_version_;
   }
 
@@ -333,11 +339,12 @@
       escaped_array_clobber_set_(EscapedArrayClobberKeyComparator(), allocator->Adapter()),
       range_checked_(RangeCheckKeyComparator() , allocator->Adapter()),
       null_checked_(std::less<uint16_t>(), allocator->Adapter()),
+      div_zero_checked_(std::less<uint16_t>(), allocator->Adapter()),
       merge_names_(allocator->Adapter()),
       merge_map_(std::less<ScopedArenaVector<BasicBlockId>>(), allocator->Adapter()),
       merge_new_memory_version_(kNoValue) {
-  std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u);
-  std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u);
+  std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_), 0u);
+  std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_), 0u);
 }
 
 bool LocalValueNumbering::Equals(const LocalValueNumbering& other) const {
@@ -356,7 +363,8 @@
       escaped_ifield_clobber_set_ == other.escaped_ifield_clobber_set_ &&
       escaped_array_clobber_set_ == other.escaped_array_clobber_set_ &&
       range_checked_ == other.range_checked_ &&
-      null_checked_ == other.null_checked_;
+      null_checked_ == other.null_checked_ &&
+      div_zero_checked_ == other.div_zero_checked_;
 }
 
 void LocalValueNumbering::MergeOne(const LocalValueNumbering& other, MergeType merge_type) {
@@ -373,20 +381,31 @@
   non_aliasing_refs_ = other.non_aliasing_refs_;
   range_checked_ = other.range_checked_;
   null_checked_ = other.null_checked_;
+  div_zero_checked_ = other.div_zero_checked_;
+
+  const BasicBlock* pred_bb = gvn_->GetBasicBlock(other.Id());
+  if (GlobalValueNumbering::HasNullCheckLastInsn(pred_bb, Id())) {
+    int s_reg = pred_bb->last_mir_insn->ssa_rep->uses[0];
+    null_checked_.insert(other.GetOperandValue(s_reg));
+  }
 
   if (merge_type == kCatchMerge) {
     // Memory is clobbered. Use new memory version and don't merge aliasing locations.
     global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
-    std::fill_n(unresolved_sfield_version_, kFieldTypeCount, global_memory_version_);
-    std::fill_n(unresolved_ifield_version_, kFieldTypeCount, global_memory_version_);
+    std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_),
+                global_memory_version_);
+    std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_),
+                global_memory_version_);
     PruneNonAliasingRefsForCatch();
     return;
   }
 
   DCHECK(merge_type == kNormalMerge);
   global_memory_version_ = other.global_memory_version_;
-  std::copy_n(other.unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
-  std::copy_n(other.unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
+  std::copy_n(other.unresolved_ifield_version_, arraysize(unresolved_sfield_version_),
+              unresolved_ifield_version_);
+  std::copy_n(other.unresolved_sfield_version_, arraysize(unresolved_ifield_version_),
+              unresolved_sfield_version_);
   sfield_value_map_ = other.sfield_value_map_;
   CopyAliasingValuesMap(&aliasing_ifield_value_map_, other.aliasing_ifield_value_map_);
   CopyAliasingValuesMap(&aliasing_array_value_map_, other.aliasing_array_value_map_);
@@ -398,9 +417,11 @@
 bool LocalValueNumbering::SameMemoryVersion(const LocalValueNumbering& other) const {
   return
       global_memory_version_ == other.global_memory_version_ &&
-      std::equal(unresolved_ifield_version_, unresolved_ifield_version_ + kFieldTypeCount,
+      std::equal(unresolved_ifield_version_,
+                 unresolved_ifield_version_ + arraysize(unresolved_ifield_version_),
                  other.unresolved_ifield_version_) &&
-      std::equal(unresolved_sfield_version_, unresolved_sfield_version_ + kFieldTypeCount,
+      std::equal(unresolved_sfield_version_,
+                 unresolved_sfield_version_ + arraysize(unresolved_sfield_version_),
                  other.unresolved_sfield_version_);
 }
 
@@ -427,18 +448,22 @@
   }
   if (new_global_version) {
     global_memory_version_ = NewMemoryVersion(&merge_new_memory_version_);
-    std::fill_n(unresolved_sfield_version_, kFieldTypeCount, merge_new_memory_version_);
-    std::fill_n(unresolved_ifield_version_, kFieldTypeCount, merge_new_memory_version_);
+    std::fill_n(unresolved_sfield_version_, arraysize(unresolved_sfield_version_),
+                merge_new_memory_version_);
+    std::fill_n(unresolved_ifield_version_, arraysize(unresolved_ifield_version_),
+                merge_new_memory_version_);
   } else {
     // Initialize with a copy of memory versions from the comparison LVN.
     global_memory_version_ = cmp->global_memory_version_;
-    std::copy_n(cmp->unresolved_ifield_version_, kFieldTypeCount, unresolved_ifield_version_);
-    std::copy_n(cmp->unresolved_sfield_version_, kFieldTypeCount, unresolved_sfield_version_);
+    std::copy_n(cmp->unresolved_ifield_version_, arraysize(unresolved_sfield_version_),
+                unresolved_ifield_version_);
+    std::copy_n(cmp->unresolved_sfield_version_, arraysize(unresolved_ifield_version_),
+                unresolved_sfield_version_);
     for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
       if (lvn == cmp) {
         continue;
       }
-      for (size_t i = 0; i != kFieldTypeCount; ++i) {
+      for (size_t i = 0; i != kDexMemAccessTypeCount; ++i) {
         if (lvn->unresolved_ifield_version_[i] != cmp->unresolved_ifield_version_[i]) {
           unresolved_ifield_version_[i] = NewMemoryVersion(&merge_new_memory_version_);
         }
@@ -465,10 +490,7 @@
     DCHECK(mir != nullptr);
     // Only INVOKEs can leak and clobber non-aliasing references if they throw.
     if ((mir->dalvikInsn.FlagsOf() & Instruction::kInvoke) != 0) {
-      for (uint16_t i = 0u; i != mir->ssa_rep->num_uses; ++i) {
-        uint16_t value_name = lvn->GetOperandValue(mir->ssa_rep->uses[i]);
-        non_aliasing_refs_.erase(value_name);
-      }
+      HandleInvokeArgs(mir, lvn);
     }
   }
 }
@@ -681,7 +703,7 @@
   const BasicBlock* least_entries_bb = gvn_->GetBasicBlock(least_entries_lvn->Id());
   if (gvn_->HasNullCheckLastInsn(least_entries_bb, id_)) {
     int s_reg = least_entries_bb->last_mir_insn->ssa_rep->uses[0];
-    uint32_t value_name = least_entries_lvn->GetSRegValueName(s_reg);
+    uint32_t value_name = least_entries_lvn->GetOperandValue(s_reg);
     merge_names_.clear();
     merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
     if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
@@ -690,6 +712,28 @@
   }
 }
 
+void LocalValueNumbering::MergeDivZeroChecked() {
+  DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
+
+  // Find the LVN with the least entries in the set.
+  const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
+  for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
+    if (lvn->div_zero_checked_.size() < least_entries_lvn->div_zero_checked_.size()) {
+      least_entries_lvn = lvn;
+    }
+  }
+
+  // For each div-zero value name check if it's div-zero checked in all the LVNs.
+  for (const auto& value_name : least_entries_lvn->div_zero_checked_) {
+    // Merge null_checked_ for this ref.
+    merge_names_.clear();
+    merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
+    if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
+      div_zero_checked_.insert(div_zero_checked_.end(), value_name);
+    }
+  }
+}
+
 void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& entry,
                                             SFieldToValueMap::iterator hint) {
   uint16_t field_id = entry.first;
@@ -702,7 +746,7 @@
     if (it != lvn->sfield_value_map_.end()) {
       value_name = it->second;
     } else {
-      uint16_t type = gvn_->GetFieldType(field_id);
+      uint16_t type = gvn_->GetSFieldType(field_id);
       value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id,
                                      lvn->unresolved_sfield_version_[type],
                                      lvn->global_memory_version_);
@@ -778,9 +822,9 @@
   if (same_version) {
     // Find the first non-null values.
     for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
-      auto it = (lvn->*map_ptr).find(key);
-      if (it != (lvn->*map_ptr).end()) {
-        cmp_values = &it->second;
+      auto value = (lvn->*map_ptr).find(key);
+      if (value != (lvn->*map_ptr).end()) {
+        cmp_values = &value->second;
         break;
       }
     }
@@ -790,21 +834,21 @@
     // field version and the values' memory_version_before_stores, last_stored_value
     // and store_loc_set are identical.
     for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
-      auto it = (lvn->*map_ptr).find(key);
-      if (it == (lvn->*map_ptr).end()) {
+      auto value = (lvn->*map_ptr).find(key);
+      if (value == (lvn->*map_ptr).end()) {
         if (cmp_values->memory_version_before_stores != kNoValue) {
           same_version = false;
           break;
         }
-      } else if (cmp_values->last_stored_value != it->second.last_stored_value ||
-          cmp_values->memory_version_before_stores != it->second.memory_version_before_stores ||
-          cmp_values->store_loc_set != it->second.store_loc_set) {
+      } else if (cmp_values->last_stored_value != value->second.last_stored_value ||
+          cmp_values->memory_version_before_stores != value->second.memory_version_before_stores ||
+          cmp_values->store_loc_set != value->second.store_loc_set) {
         same_version = false;
         break;
-      } else if (it->second.last_load_memory_version != kNoValue) {
+      } else if (value->second.last_load_memory_version != kNoValue) {
         DCHECK(load_memory_version_for_same_version == kNoValue ||
-               load_memory_version_for_same_version == it->second.last_load_memory_version);
-        load_memory_version_for_same_version = it->second.last_load_memory_version;
+               load_memory_version_for_same_version == value->second.last_load_memory_version);
+        load_memory_version_for_same_version = value->second.last_load_memory_version;
       }
     }
   }
@@ -819,12 +863,12 @@
     if (!cmp_values->load_value_map.empty()) {
       my_values->load_value_map = cmp_values->load_value_map;
       for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
-        auto it = (lvn->*map_ptr).find(key);
-        if (it == (lvn->*map_ptr).end() || it->second.load_value_map.empty()) {
+        auto value = (lvn->*map_ptr).find(key);
+        if (value == (lvn->*map_ptr).end() || value->second.load_value_map.empty()) {
           my_values->load_value_map.clear();
           break;
         }
-        InPlaceIntersectMaps(&my_values->load_value_map, it->second.load_value_map);
+        InPlaceIntersectMaps(&my_values->load_value_map, value->second.load_value_map);
         if (my_values->load_value_map.empty()) {
           break;
         }
@@ -838,20 +882,20 @@
     // Calculate the locations that have been either read from or written to in each incoming LVN.
     bool first_lvn = true;
     for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
-      auto it = (lvn->*map_ptr).find(key);
-      if (it == (lvn->*map_ptr).end()) {
+      auto value = (lvn->*map_ptr).find(key);
+      if (value == (lvn->*map_ptr).end()) {
         my_values->load_value_map.clear();
         break;
       }
       if (first_lvn) {
         first_lvn = false;
         // Copy the first LVN's locations. Values will be overwritten later.
-        my_values->load_value_map = it->second.load_value_map;
-        for (uint16_t location : it->second.store_loc_set) {
+        my_values->load_value_map = value->second.load_value_map;
+        for (uint16_t location : value->second.store_loc_set) {
           my_values->load_value_map.Put(location, 0u);
         }
       } else {
-        IntersectAliasingValueLocations(my_values, &it->second);
+        IntersectAliasingValueLocations(my_values, &value->second);
       }
     }
     // Calculate merged values for the intersection.
@@ -922,6 +966,9 @@
   // Merge null_checked_. We may later insert more, such as merged object field values.
   MergeNullChecked();
 
+  // Now merge the div_zero_checked_.
+  MergeDivZeroChecked();
+
   if (merge_type == kCatchMerge) {
     // Memory is clobbered. New memory version already created, don't merge aliasing locations.
     return;
@@ -953,6 +1000,26 @@
                 AliasingArrayVersions>>();
 }
 
+void LocalValueNumbering::PrepareEntryBlock() {
+  uint32_t vreg = gvn_->GetMirGraph()->GetFirstInVR();
+  CompilationUnit* cu = gvn_->GetCompilationUnit();
+  const char* shorty = cu->shorty;
+  ++shorty;  // Skip return value.
+  if ((cu->access_flags & kAccStatic) == 0) {
+    // If non-static method, mark "this" as non-null
+    uint16_t value_name = GetOperandValue(vreg);
+    ++vreg;
+    null_checked_.insert(value_name);
+  }
+  for ( ; *shorty != 0; ++shorty, ++vreg) {
+    if (*shorty == 'J' || *shorty == 'D') {
+      uint16_t value_name = GetOperandValueWide(vreg);
+      SetOperandValueWide(vreg, value_name);
+      ++vreg;
+    }
+  }
+}
+
 uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
   uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
   DCHECK(null_checked_.find(res) == null_checked_.end());
@@ -1025,10 +1092,30 @@
   }
 }
 
+void LocalValueNumbering::HandleDivZeroCheck(MIR* mir, uint16_t reg) {
+  auto lb = div_zero_checked_.lower_bound(reg);
+  if (lb != div_zero_checked_.end() && *lb == reg) {
+    if (LIKELY(gvn_->CanModify())) {
+      if (gvn_->GetCompilationUnit()->verbose) {
+        LOG(INFO) << "Removing div zero check for 0x" << std::hex << mir->offset;
+      }
+      mir->optimization_flags |= MIR_IGNORE_DIV_ZERO_CHECK;
+    }
+  } else {
+    div_zero_checked_.insert(lb, reg);
+  }
+}
+
 void LocalValueNumbering::HandlePutObject(MIR* mir) {
   // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
   uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
   HandleEscapingRef(base);
+  if (gvn_->CanModify() && null_checked_.count(base) != 0u) {
+    if (gvn_->GetCompilationUnit()->verbose) {
+      LOG(INFO) << "Removing GC card mark value null check for 0x" << std::hex << mir->offset;
+    }
+    mir->optimization_flags |= MIR_STORE_NON_NULL_VALUE;
+  }
 }
 
 void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
@@ -1039,12 +1126,30 @@
   }
 }
 
+void LocalValueNumbering::HandleInvokeArgs(const MIR* mir, const LocalValueNumbering* mir_lvn) {
+  const int32_t* uses = mir->ssa_rep->uses;
+  const int32_t* uses_end = uses + mir->ssa_rep->num_uses;
+  while (uses != uses_end) {
+    uint16_t sreg = *uses;
+    ++uses;
+    // Avoid LookupValue() so that we don't store new values in the global value map.
+    auto local_it = mir_lvn->sreg_value_map_.find(sreg);
+    if (local_it != mir_lvn->sreg_value_map_.end()) {
+      non_aliasing_refs_.erase(local_it->second);
+    } else {
+      uint16_t value_name = gvn_->FindValue(kNoValue, sreg, kNoValue, kNoValue);
+      if (value_name != kNoValue) {
+        non_aliasing_refs_.erase(value_name);
+      }
+    }
+  }
+}
+
 uint16_t LocalValueNumbering::HandlePhi(MIR* mir) {
   if (gvn_->merge_lvns_.empty()) {
     // Running LVN without a full GVN?
     return kNoValue;
   }
-  int16_t num_uses = mir->ssa_rep->num_uses;
   int32_t* uses = mir->ssa_rep->uses;
   // Try to find out if this is merging wide regs.
   if (mir->ssa_rep->defs[0] != 0 &&
@@ -1052,18 +1157,20 @@
     // This is the high part of a wide reg. Ignore the Phi.
     return kNoValue;
   }
-  bool wide = false;
-  for (int16_t i = 0; i != num_uses; ++i) {
-    if (sreg_wide_value_map_.count(uses[i]) != 0u) {
-      wide = true;
-      break;
-    }
+  BasicBlockId* incoming = mir->meta.phi_incoming;
+  int16_t pos = 0;
+  // Check if we're merging a wide value based on the first merged LVN.
+  const LocalValueNumbering* first_lvn = gvn_->merge_lvns_[0];
+  DCHECK_LT(pos, mir->ssa_rep->num_uses);
+  while (incoming[pos] != first_lvn->Id()) {
+    ++pos;
+    DCHECK_LT(pos, mir->ssa_rep->num_uses);
   }
+  int first_s_reg = uses[pos];
+  bool wide = (first_lvn->sreg_wide_value_map_.count(first_s_reg) != 0u);
   // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN.
   uint16_t value_name = kNoValue;
   merge_names_.clear();
-  BasicBlockId* incoming = mir->meta.phi_incoming;
-  int16_t pos = 0;
   bool same_values = true;
   for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
     DCHECK_LT(pos, mir->ssa_rep->num_uses);
@@ -1090,6 +1197,9 @@
       if (!wide && gvn_->NullCheckedInAllPredecessors(merge_names_)) {
         null_checked_.insert(value_name);
       }
+      if (gvn_->DivZeroCheckedInAllPredecessors(merge_names_)) {
+        div_zero_checked_.insert(value_name);
+      }
     }
   }
   if (wide) {
@@ -1101,12 +1211,11 @@
 }
 
 uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
-  // uint16_t type = opcode - Instruction::AGET;
   uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
   HandleNullCheck(mir, array);
   uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
   HandleRangeCheck(mir, array, index);
-  uint16_t type = opcode - Instruction::AGET;
+  uint16_t type = AGetMemAccessType(static_cast<Instruction::Code>(opcode));
   // Establish value number for loaded register.
   uint16_t res;
   if (IsNonAliasingArray(array, type)) {
@@ -1133,7 +1242,7 @@
   uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
   HandleRangeCheck(mir, array, index);
 
-  uint16_t type = opcode - Instruction::APUT;
+  uint16_t type = APutMemAccessType(static_cast<Instruction::Code>(opcode));
   uint16_t value = (opcode == Instruction::APUT_WIDE)
                    ? GetOperandValueWide(mir->ssa_rep->uses[0])
                    : GetOperandValue(mir->ssa_rep->uses[0]);
@@ -1175,8 +1284,8 @@
     // Use result s_reg - will be unique.
     res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
   } else {
-    uint16_t type = opcode - Instruction::IGET;
-    uint16_t field_id = gvn_->GetFieldId(field_info, type);
+    uint16_t type = IGetMemAccessType(static_cast<Instruction::Code>(opcode));
+    uint16_t field_id = gvn_->GetIFieldId(mir);
     if (IsNonAliasingIField(base, field_id, type)) {
       uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type);
       auto lb = non_aliasing_ifield_value_map_.lower_bound(loc);
@@ -1200,10 +1309,10 @@
 }
 
 void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
-  uint16_t type = opcode - Instruction::IPUT;
   int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
   uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
   HandleNullCheck(mir, base);
+  uint16_t type = IPutMemAccessType(static_cast<Instruction::Code>(opcode));
   const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
   if (!field_info.IsResolved()) {
     // Unresolved fields always alias with everything of the same type.
@@ -1223,7 +1332,7 @@
     // Aliasing fields of the same type may have been overwritten.
     auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end();
     while (it != end) {
-      if (gvn_->GetFieldType(it->first) != type) {
+      if (gvn_->GetIFieldType(it->first) != type) {
         ++it;
       } else {
         it = aliasing_ifield_value_map_.erase(it);
@@ -1233,7 +1342,7 @@
     // Nothing to do, resolved volatile fields always get a new memory version anyway and
     // can't alias with resolved non-volatile fields.
   } else {
-    uint16_t field_id = gvn_->GetFieldId(field_info, type);
+    uint16_t field_id = gvn_->GetIFieldId(mir);
     uint16_t value = (opcode == Instruction::IPUT_WIDE)
                      ? GetOperandValueWide(mir->ssa_rep->uses[0])
                      : GetOperandValue(mir->ssa_rep->uses[0]);
@@ -1271,7 +1380,8 @@
 uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
   const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
   if (!field_info.IsResolved() || field_info.IsVolatile() ||
-      (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0)) {
+      (!field_info.IsClassInitialized() &&
+       (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0)) {
     // Volatile SGETs (and unresolved fields are potentially volatile) have acquire semantics
     // and class initialization can call arbitrary functions, we need to wipe aliasing values.
     HandleInvokeOrClInitOrAcquireOp(mir);
@@ -1283,8 +1393,8 @@
     // Use result s_reg - will be unique.
     res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
   } else {
-    uint16_t type = opcode - Instruction::SGET;
-    uint16_t field_id = gvn_->GetFieldId(field_info, type);
+    uint16_t type = SGetMemAccessType(static_cast<Instruction::Code>(opcode));
+    uint16_t field_id = gvn_->GetSFieldId(mir);
     auto lb = sfield_value_map_.lower_bound(field_id);
     if (lb != sfield_value_map_.end() && lb->first == field_id) {
       res = lb->second;
@@ -1307,11 +1417,12 @@
 
 void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
   const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
-  if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
+  if (!field_info.IsClassInitialized() &&
+      (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
     // Class initialization can call arbitrary functions, we need to wipe aliasing values.
     HandleInvokeOrClInitOrAcquireOp(mir);
   }
-  uint16_t type = opcode - Instruction::SPUT;
+  uint16_t type = SPutMemAccessType(static_cast<Instruction::Code>(opcode));
   if (!field_info.IsResolved()) {
     // Unresolved fields always alias with everything of the same type.
     // Use mir->offset as modifier; without elaborate inlining, it will be unique.
@@ -1322,7 +1433,7 @@
     // Nothing to do, resolved volatile fields always get a new memory version anyway and
     // can't alias with resolved non-volatile fields.
   } else {
-    uint16_t field_id = gvn_->GetFieldId(field_info, type);
+    uint16_t field_id = gvn_->GetSFieldId(mir);
     uint16_t value = (opcode == Instruction::SPUT_WIDE)
                      ? GetOperandValueWide(mir->ssa_rep->uses[0])
                      : GetOperandValue(mir->ssa_rep->uses[0]);
@@ -1346,7 +1457,7 @@
 void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) {
   // Erase all static fields of this type from the sfield_value_map_.
   for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) {
-    if (gvn_->GetFieldType(it->first) == type) {
+    if (gvn_->GetSFieldType(it->first) == type) {
       it = sfield_value_map_.erase(it);
     } else {
       ++it;
@@ -1413,8 +1524,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 +1559,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:
@@ -1460,14 +1575,11 @@
         uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
         HandleNullCheck(mir, reg);
       }
-      // Intentional fall-through.
+      FALLTHROUGH_INTENDED;
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE:
       // Make ref args aliasing.
-      for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
-        uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
-        non_aliasing_refs_.erase(reg);
-      }
+      HandleInvokeArgs(mir, this);
       HandleInvokeOrClInitOrAcquireOp(mir);
       break;
 
@@ -1583,7 +1695,7 @@
         uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
         HandleNullCheck(mir, reg);
       }
-      // Intentional fall-through.
+      FALLTHROUGH_INTENDED;
     case Instruction::NEG_INT:
     case Instruction::NOT_INT:
     case Instruction::NEG_FLOAT:
@@ -1610,7 +1722,6 @@
       }
       break;
 
-
     case Instruction::DOUBLE_TO_LONG:
     case Instruction::LONG_TO_DOUBLE:
     case Instruction::NEG_LONG:
@@ -1645,6 +1756,13 @@
       }
       break;
 
+    case Instruction::DIV_INT:
+    case Instruction::DIV_INT_2ADDR:
+    case Instruction::REM_INT:
+    case Instruction::REM_INT_2ADDR:
+      HandleDivZeroCheck(mir, GetOperandValue(mir->ssa_rep->uses[1]));
+      FALLTHROUGH_INTENDED;
+
     case Instruction::CMPG_FLOAT:
     case Instruction::CMPL_FLOAT:
     case Instruction::ADD_INT:
@@ -1659,10 +1777,6 @@
     case Instruction::XOR_INT_2ADDR:
     case Instruction::SUB_INT:
     case Instruction::SUB_INT_2ADDR:
-    case Instruction::DIV_INT:
-    case Instruction::DIV_INT_2ADDR:
-    case Instruction::REM_INT:
-    case Instruction::REM_INT_2ADDR:
     case Instruction::SHL_INT:
     case Instruction::SHL_INT_2ADDR:
     case Instruction::SHR_INT:
@@ -1677,19 +1791,22 @@
       }
       break;
 
+    case Instruction::DIV_LONG:
+    case Instruction::REM_LONG:
+    case Instruction::DIV_LONG_2ADDR:
+    case Instruction::REM_LONG_2ADDR:
+      HandleDivZeroCheck(mir, GetOperandValueWide(mir->ssa_rep->uses[2]));
+      FALLTHROUGH_INTENDED;
+
     case Instruction::ADD_LONG:
     case Instruction::SUB_LONG:
     case Instruction::MUL_LONG:
-    case Instruction::DIV_LONG:
-    case Instruction::REM_LONG:
     case Instruction::AND_LONG:
     case Instruction::OR_LONG:
     case Instruction::XOR_LONG:
     case Instruction::ADD_LONG_2ADDR:
     case Instruction::SUB_LONG_2ADDR:
     case Instruction::MUL_LONG_2ADDR:
-    case Instruction::DIV_LONG_2ADDR:
-    case Instruction::REM_LONG_2ADDR:
     case Instruction::AND_LONG_2ADDR:
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
@@ -1782,7 +1899,7 @@
 
     case Instruction::APUT_OBJECT:
       HandlePutObject(mir);
-      // Intentional fall-through.
+      FALLTHROUGH_INTENDED;
     case Instruction::APUT:
     case Instruction::APUT_WIDE:
     case Instruction::APUT_BYTE:
@@ -1804,7 +1921,7 @@
 
     case Instruction::IPUT_OBJECT:
       HandlePutObject(mir);
-      // Intentional fall-through.
+      FALLTHROUGH_INTENDED;
     case Instruction::IPUT:
     case Instruction::IPUT_WIDE:
     case Instruction::IPUT_BOOLEAN:
@@ -1826,7 +1943,7 @@
 
     case Instruction::SPUT_OBJECT:
       HandlePutObject(mir);
-      // Intentional fall-through.
+      FALLTHROUGH_INTENDED;
     case Instruction::SPUT:
     case Instruction::SPUT_WIDE:
     case Instruction::SPUT_BOOLEAN:
diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h
index c60da32..9b89c95 100644
--- a/compiler/dex/local_value_numbering.h
+++ b/compiler/dex/local_value_numbering.h
@@ -21,8 +21,8 @@
 
 #include "compiler_internals.h"
 #include "global_value_numbering.h"
-#include "utils/scoped_arena_allocator.h"
-#include "utils/scoped_arena_containers.h"
+#include "utils/arena_object.h"
+#include "utils/dex_instruction_utils.h"
 
 namespace art {
 
@@ -31,7 +31,7 @@
 // Enable/disable tracking values stored in the FILLED_NEW_ARRAY result.
 static constexpr bool kLocalValueNumberingEnableFilledNewArrayTracking = true;
 
-class LocalValueNumbering {
+class LocalValueNumbering : public DeletableArenaObject<kArenaAllocMisc> {
  private:
   static constexpr uint16_t kNoValue = GlobalValueNumbering::kNoValue;
 
@@ -44,18 +44,14 @@
 
   bool Equals(const LocalValueNumbering& other) const;
 
-  uint16_t GetSRegValueName(uint16_t s_reg) const {
-    return GetOperandValue(s_reg);
-  }
-
-  void SetValueNameNullChecked(uint16_t value_name) {
-    null_checked_.insert(value_name);
-  }
-
   bool IsValueNullChecked(uint16_t value_name) const {
     return null_checked_.find(value_name) != null_checked_.end();
   }
 
+  bool IsValueDivZeroChecked(uint16_t value_name) const {
+    return div_zero_checked_.find(value_name) != div_zero_checked_.end();
+  }
+
   bool IsSregValue(uint16_t s_reg, uint16_t value_name) const {
     auto it = sreg_value_map_.find(s_reg);
     if (it != sreg_value_map_.end()) {
@@ -73,32 +69,14 @@
 
   void MergeOne(const LocalValueNumbering& other, MergeType merge_type);
   void Merge(MergeType merge_type);  // Merge gvn_->merge_lvns_.
+  void PrepareEntryBlock();
 
   uint16_t GetValueNumber(MIR* mir);
 
-  // LocalValueNumbering should be allocated on the ArenaStack (or the native stack).
-  static void* operator new(size_t size, ScopedArenaAllocator* allocator) {
-    return allocator->Alloc(sizeof(LocalValueNumbering), kArenaAllocMisc);
-  }
-
-  // Allow delete-expression to destroy a LocalValueNumbering object without deallocation.
-  static void operator delete(void* ptr) { UNUSED(ptr); }
-
  private:
   // A set of value names.
   typedef GlobalValueNumbering::ValueNameSet ValueNameSet;
 
-  // Field types correspond to the ordering of GET/PUT instructions; this order is the same
-  // for IGET, IPUT, SGET, SPUT, AGET and APUT:
-  // op         0
-  // op_WIDE    1
-  // op_OBJECT  2
-  // op_BOOLEAN 3
-  // op_BYTE    4
-  // op_CHAR    5
-  // op_SHORT   6
-  static constexpr size_t kFieldTypeCount = 7;
-
   // Key is s_reg, value is value name.
   typedef ScopedArenaSafeMap<uint16_t, uint16_t> SregValueMap;
 
@@ -121,18 +99,22 @@
   }
 
   void SetOperandValue(uint16_t s_reg, uint16_t value) {
+    DCHECK_EQ(sreg_wide_value_map_.count(s_reg), 0u);
     SetOperandValueImpl(s_reg, value, &sreg_value_map_);
   }
 
   uint16_t GetOperandValue(int s_reg) const {
+    DCHECK_EQ(sreg_wide_value_map_.count(s_reg), 0u);
     return GetOperandValueImpl(s_reg, &sreg_value_map_);
   }
 
   void SetOperandValueWide(uint16_t s_reg, uint16_t value) {
+    DCHECK_EQ(sreg_value_map_.count(s_reg), 0u);
     SetOperandValueImpl(s_reg, value, &sreg_wide_value_map_);
   }
 
   uint16_t GetOperandValueWide(int s_reg) const {
+    DCHECK_EQ(sreg_value_map_.count(s_reg), 0u);
     return GetOperandValueImpl(s_reg, &sreg_wide_value_map_);
   }
 
@@ -298,8 +280,10 @@
   bool IsNonAliasingArray(uint16_t reg, uint16_t type) const;
   void HandleNullCheck(MIR* mir, uint16_t reg);
   void HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index);
+  void HandleDivZeroCheck(MIR* mir, uint16_t reg);
   void HandlePutObject(MIR* mir);
   void HandleEscapingRef(uint16_t base);
+  void HandleInvokeArgs(const MIR* mir, const LocalValueNumbering* mir_lvn);
   uint16_t HandlePhi(MIR* mir);
   uint16_t HandleAGet(MIR* mir, uint16_t opcode);
   void HandleAPut(MIR* mir, uint16_t opcode);
@@ -348,6 +332,7 @@
   void MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
                                     IFieldLocToValueMap::iterator hint);
   void MergeNullChecked();
+  void MergeDivZeroChecked();
 
   template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
   void MergeAliasingValues(const typename Map::value_type& entry, typename Map::iterator hint);
@@ -355,7 +340,7 @@
   GlobalValueNumbering* gvn_;
 
   // We're using the block id as a 16-bit operand value for some lookups.
-  COMPILE_ASSERT(sizeof(BasicBlockId) == sizeof(uint16_t), BasicBlockId_must_be_16_bit);
+  static_assert(sizeof(BasicBlockId) == sizeof(uint16_t), "BasicBlockId must be 16 bit");
   BasicBlockId id_;
 
   SregValueMap sreg_value_map_;
@@ -369,8 +354,8 @@
 
   // Data for dealing with memory clobbering and store/load aliasing.
   uint16_t global_memory_version_;
-  uint16_t unresolved_sfield_version_[kFieldTypeCount];
-  uint16_t unresolved_ifield_version_[kFieldTypeCount];
+  uint16_t unresolved_sfield_version_[kDexMemAccessTypeCount];
+  uint16_t unresolved_ifield_version_[kDexMemAccessTypeCount];
   // Value names of references to objects that cannot be reached through a different value name.
   ValueNameSet non_aliasing_refs_;
   // Previously non-aliasing refs that escaped but can still be used for non-aliasing AGET/IGET.
@@ -382,6 +367,7 @@
   // Range check and null check elimination.
   RangeCheckSet range_checked_;
   ValueNameSet null_checked_;
+  ValueNameSet div_zero_checked_;
 
   // Reuse one vector for all merges to avoid leaking too much memory on the ArenaStack.
   ScopedArenaVector<BasicBlockId> merge_names_;
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index 067bea2..0fcb584 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -15,6 +15,7 @@
  */
 
 #include "compiler_internals.h"
+#include "dex/mir_field_info.h"
 #include "global_value_numbering.h"
 #include "local_value_numbering.h"
 #include "gtest/gtest.h"
@@ -28,6 +29,7 @@
     uintptr_t declaring_dex_file;
     uint16_t declaring_field_idx;
     bool is_volatile;
+    DexMemAccessType type;
   };
 
   struct SFieldDef {
@@ -35,6 +37,7 @@
     uintptr_t declaring_dex_file;
     uint16_t declaring_field_idx;
     bool is_volatile;
+    DexMemAccessType type;
   };
 
   struct MIRDef {
@@ -84,18 +87,21 @@
     { opcode, 0u, 0u, 1, { reg }, 0, { } }
 #define DEF_UNIQUE_REF(opcode, reg) \
     { opcode, 0u, 0u, 0, { }, 1, { reg } }  // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
+#define DEF_DIV_REM(opcode, result, dividend, divisor) \
+    { opcode, 0u, 0u, 2, { dividend, divisor }, 1, { result } }
+#define DEF_DIV_REM_WIDE(opcode, result, dividend, divisor) \
+    { opcode, 0u, 0u, 4, { dividend, dividend + 1, divisor, divisor + 1 }, 2, { result, result + 1 } }
 
   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);
+      MirIFieldLoweringInfo field_info(def->field_idx, def->type);
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
-        field_info.flags_ = 0u |  // Without kFlagIsStatic.
-            (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u);
+        field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile);
       }
       cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
     }
@@ -111,14 +117,14 @@
     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);
+      MirSFieldLoweringInfo field_info(def->field_idx, def->type);
       // Mark even unresolved fields as initialized.
-      field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic |
-          MirSFieldLoweringInfo::kFlagIsInitialized;
+      field_info.flags_ |= MirSFieldLoweringInfo::kFlagClassIsInitialized;
+      // NOTE: MirSFieldLoweringInfo::kFlagClassIsInDexCache isn't used by LVN.
       if (def->declaring_dex_file != 0u) {
         field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
         field_info.declaring_field_idx_ = def->declaring_field_idx;
-        field_info.flags_ |= (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u);
+        field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile);
       }
       cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
     }
@@ -139,12 +145,16 @@
       mir->dalvikInsn.opcode = def->opcode;
       mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
       mir->dalvikInsn.vB_wide = def->value;
-      if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
+      if (IsInstructionIGetOrIPut(def->opcode)) {
         ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size());
         mir->meta.ifield_lowering_info = def->field_info;
-      } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
+        ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_info].MemAccessType(),
+                  IGetOrIPutMemAccessType(def->opcode));
+      } else if (IsInstructionSGetOrSPut(def->opcode)) {
         ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size());
         mir->meta.sfield_lowering_info = def->field_info;
+        ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_info].MemAccessType(),
+                  SGetOrSPutMemAccessType(def->opcode));
       }
       mir->ssa_rep = &ssa_reps_[i];
       mir->ssa_rep->num_uses = def->num_uses;
@@ -172,10 +182,17 @@
   void MakeSFieldUninitialized(uint32_t sfield_index) {
     CHECK_LT(sfield_index, cu_.mir_graph->sfield_lowering_infos_.size());
     cu_.mir_graph->sfield_lowering_infos_[sfield_index].flags_ &=
-        ~MirSFieldLoweringInfo::kFlagIsInitialized;
+        ~MirSFieldLoweringInfo::kFlagClassIsInitialized;
   }
 
   void PerformLVN() {
+    cu_.mir_graph->temp_.gvn.ifield_ids_ =  GlobalValueNumbering::PrepareGvnFieldIds(
+        allocator_.get(), cu_.mir_graph->ifield_lowering_infos_);
+    cu_.mir_graph->temp_.gvn.sfield_ids_ =  GlobalValueNumbering::PrepareGvnFieldIds(
+        allocator_.get(), cu_.mir_graph->sfield_lowering_infos_);
+    gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(),
+                                                           GlobalValueNumbering::kModeLvn));
+    lvn_.reset(new (allocator_.get()) LocalValueNumbering(gvn_.get(), 0u, allocator_.get()));
     value_names_.resize(mir_count_);
     for (size_t i = 0; i != mir_count_; ++i) {
       value_names_[i] =  lvn_->GetValueNumber(&mirs_[i]);
@@ -195,9 +212,6 @@
         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()));
-    lvn_.reset(new (allocator_.get()) LocalValueNumbering(gvn_.get(), 0u, allocator_.get()));
-    gvn_->AllowModifications();
   }
 
   ArenaPool pool_;
@@ -213,7 +227,7 @@
 
 TEST_F(LocalValueNumberingTest, IGetIGetInvokeIGet) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_IGET(Instruction::IGET, 0u, 10u, 0u),
@@ -236,8 +250,8 @@
 
 TEST_F(LocalValueNumberingTest, IGetIPutIGetIGetIGet) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
-      { 2u, 1u, 2u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessObject },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_IGET(Instruction::IGET_OBJECT, 0u, 10u, 0u),
@@ -261,7 +275,7 @@
 
 TEST_F(LocalValueNumberingTest, UniquePreserve1) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
@@ -283,7 +297,7 @@
 
 TEST_F(LocalValueNumberingTest, UniquePreserve2) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u),
@@ -305,7 +319,7 @@
 
 TEST_F(LocalValueNumberingTest, UniquePreserveAndEscape) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u),
@@ -330,8 +344,8 @@
 
 TEST_F(LocalValueNumberingTest, Volatile) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
-      { 2u, 1u, 2u, true },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, true, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_IGET(Instruction::IGET, 0u, 10u, 1u),  // Volatile.
@@ -357,9 +371,9 @@
 
 TEST_F(LocalValueNumberingTest, UnresolvedIField) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },  // Resolved field #1.
-      { 2u, 1u, 2u, false },  // Resolved field #2.
-      { 3u, 0u, 0u, false },  // Unresolved field.
+      { 1u, 1u, 1u, false, kDexMemAccessWord },  // Resolved field #1.
+      { 2u, 1u, 2u, false, kDexMemAccessWide },  // Resolved field #2.
+      { 3u, 0u, 0u, false, kDexMemAccessWord },  // Unresolved field.
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u),
@@ -406,9 +420,9 @@
 
 TEST_F(LocalValueNumberingTest, UnresolvedSField) {
   static const SFieldDef sfields[] = {
-      { 1u, 1u, 1u, false },  // Resolved field #1.
-      { 2u, 1u, 2u, false },  // Resolved field #2.
-      { 3u, 0u, 0u, false },  // Unresolved field.
+      { 1u, 1u, 1u, false, kDexMemAccessWord },  // Resolved field #1.
+      { 2u, 1u, 2u, false, kDexMemAccessWide },  // Resolved field #2.
+      { 3u, 0u, 0u, false, kDexMemAccessWord },  // Unresolved field.
   };
   static const MIRDef mirs[] = {
       DEF_SGET(Instruction::SGET, 0u, 0u),            // Resolved field #1.
@@ -437,11 +451,11 @@
 
 TEST_F(LocalValueNumberingTest, UninitializedSField) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },  // Resolved field #1.
+      { 1u, 1u, 1u, false, kDexMemAccessWord },  // Resolved field #1.
   };
   static const SFieldDef sfields[] = {
-      { 1u, 1u, 1u, false },  // Resolved field #1.
-      { 2u, 1u, 2u, false },  // Resolved field #2; uninitialized.
+      { 1u, 1u, 1u, false, kDexMemAccessWord },  // Resolved field #1.
+      { 2u, 1u, 2u, false, kDexMemAccessWord },  // Resolved field #2; uninitialized.
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 200u),
@@ -486,11 +500,11 @@
 
 TEST_F(LocalValueNumberingTest, SameValueInDifferentMemoryLocations) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
-      { 2u, 1u, 2u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
   };
   static const SFieldDef sfields[] = {
-      { 3u, 1u, 3u, false },
+      { 3u, 1u, 3u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 201u),
@@ -550,12 +564,12 @@
 
 TEST_F(LocalValueNumberingTest, EscapingRefs) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },  // Field #1.
-      { 2u, 1u, 2u, false },  // Field #2.
-      { 3u, 1u, 3u, false },  // Reference field for storing escaping refs.
-      { 4u, 1u, 4u, false },  // Wide.
-      { 5u, 0u, 0u, false },  // Unresolved field, int.
-      { 6u, 0u, 0u, false },  // Unresolved field, wide.
+      { 1u, 1u, 1u, false, kDexMemAccessWord },    // Field #1.
+      { 2u, 1u, 2u, false, kDexMemAccessWord },    // Field #2.
+      { 3u, 1u, 3u, false, kDexMemAccessObject },  // For storing escaping refs.
+      { 4u, 1u, 4u, false, kDexMemAccessWide },    // Wide.
+      { 5u, 0u, 0u, false, kDexMemAccessWord },    // Unresolved field, int.
+      { 6u, 0u, 0u, false, kDexMemAccessWide },    // Unresolved field, wide.
   };
   static const MIRDef mirs[] = {
       DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u),
@@ -593,7 +607,9 @@
   EXPECT_NE(value_names_[13], value_names_[16]);  // New value.
   EXPECT_NE(value_names_[14], value_names_[17]);  // New value.
   for (size_t i = 0u; i != mir_count_; ++i) {
-    int expected = (i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0;
+    int expected =
+        ((i != 0u && i != 3u && i != 6u) ? MIR_IGNORE_NULL_CHECK : 0) |
+        ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
     EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
   }
 }
@@ -626,18 +642,19 @@
   for (size_t i = 0u; i != mir_count_; ++i) {
     int expected =
         ((i != 0u && i != 3u && i != 6u && i != 9u) ? MIR_IGNORE_NULL_CHECK : 0u) |
-        ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u);
+        ((i >= 4 && i != 6u && i != 9u) ? MIR_IGNORE_RANGE_CHECK : 0u) |
+        ((i == 3u) ? MIR_STORE_NON_NULL_VALUE: 0);
     EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
   }
 }
 
 TEST_F(LocalValueNumberingTest, StoringSameValueKeepsMemoryVersion) {
   static const IFieldDef ifields[] = {
-      { 1u, 1u, 1u, false },
-      { 2u, 1u, 2u, false },
+      { 1u, 1u, 1u, false, kDexMemAccessWord },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
   };
   static const SFieldDef sfields[] = {
-      { 2u, 1u, 2u, false },
+      { 2u, 1u, 2u, false, kDexMemAccessWord },
   };
   static const MIRDef mirs[] = {
       DEF_IGET(Instruction::IGET, 0u, 30u, 0u),
@@ -715,8 +732,8 @@
 
 TEST_F(LocalValueNumberingTest, ClInitOnSget) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, false },
-      { 1u, 2u, 1u, false },
+      { 0u, 1u, 0u, false, kDexMemAccessObject },
+      { 1u, 2u, 1u, false, kDexMemAccessObject },
   };
   static const MIRDef mirs[] = {
       DEF_SGET(Instruction::SGET_OBJECT, 0u, 0u),
@@ -734,4 +751,26 @@
   EXPECT_NE(value_names_[0], value_names_[3]);
 }
 
+TEST_F(LocalValueNumberingTest, DivZeroCheck) {
+  static const MIRDef mirs[] = {
+      DEF_DIV_REM(Instruction::DIV_INT, 1u, 10u, 20u),
+      DEF_DIV_REM(Instruction::DIV_INT, 2u, 20u, 20u),
+      DEF_DIV_REM(Instruction::DIV_INT_2ADDR, 3u, 10u, 1u),
+      DEF_DIV_REM(Instruction::REM_INT, 4u, 30u, 20u),
+      DEF_DIV_REM_WIDE(Instruction::REM_LONG, 5u, 12u, 14u),
+      DEF_DIV_REM_WIDE(Instruction::DIV_LONG_2ADDR, 7u, 16u, 14u),
+  };
+
+  static const bool expected_ignore_div_zero_check[] = {
+      false, true, false, true, false, true,
+  };
+
+  PrepareMIRs(mirs);
+  PerformLVN();
+  for (size_t i = 0u; i != mir_count_; ++i) {
+    int expected = expected_ignore_div_zero_check[i] ? MIR_IGNORE_DIV_ZERO_CHECK : 0u;
+    EXPECT_EQ(expected, mirs_[i].optimization_flags) << i;
+  }
+}
+
 }  // namespace art
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index ee48796..0f0846c 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -21,6 +21,7 @@
 #include "dataflow_iterator-inl.h"
 #include "dex_instruction.h"
 #include "dex_instruction-inl.h"
+#include "dex/mir_field_info.h"
 #include "dex/verified_method.h"
 #include "dex/quick/dex_file_method_inliner.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
@@ -1112,14 +1113,11 @@
     return true;
   }
 
-  if (!compiler_options.IsCompilationEnabled()) {
-    *skip_message = "Compilation disabled";
-    return true;
-  }
+  DCHECK(compiler_options.IsCompilationEnabled());
 
   // Set up compilation cutoffs based on current filter mode.
-  size_t small_cutoff = 0;
-  size_t default_cutoff = 0;
+  size_t small_cutoff;
+  size_t default_cutoff;
   switch (compiler_filter) {
     case CompilerOptions::kBalanced:
       small_cutoff = compiler_options.GetSmallMethodThreshold();
@@ -1136,6 +1134,7 @@
       break;
     default:
       LOG(FATAL) << "Unexpected compiler_filter_: " << compiler_filter;
+      UNREACHABLE();
   }
 
   // If size < cutoff, assume we'll compile - but allow removal.
@@ -1152,7 +1151,7 @@
     skip_compilation = true;
     *skip_message = "Huge method: " + std::to_string(GetNumDalvikInsns());
     // If we're got a huge number of basic blocks, don't bother with further analysis.
-    if (static_cast<size_t>(num_blocks_) > (compiler_options.GetHugeMethodThreshold() / 2)) {
+    if (static_cast<size_t>(GetNumBlocks()) > (compiler_options.GetHugeMethodThreshold() / 2)) {
       return true;
     }
   } else if (compiler_options.IsLargeMethod(GetNumDalvikInsns()) &&
@@ -1206,6 +1205,8 @@
   ScopedArenaAllocator allocator(&cu_->arena_stack);
   uint16_t* field_idxs =
       reinterpret_cast<uint16_t*>(allocator.Alloc(max_refs * sizeof(uint16_t), kArenaAllocMisc));
+  DexMemAccessType* field_types = reinterpret_cast<DexMemAccessType*>(
+      allocator.Alloc(max_refs * sizeof(DexMemAccessType), kArenaAllocMisc));
 
   // Find IGET/IPUT/SGET/SPUT insns, store IGET/IPUT fields at the beginning, SGET/SPUT at the end.
   size_t ifield_pos = 0u;
@@ -1216,38 +1217,41 @@
       continue;
     }
     for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
-      if (mir->dalvikInsn.opcode >= Instruction::IGET &&
-          mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) {
-        // Get field index and try to find it among existing indexes. If found, it's usually among
-        // the last few added, so we'll start the search from ifield_pos/sfield_pos. Though this
-        // is a linear search, it actually performs much better than map based approach.
-        if (mir->dalvikInsn.opcode <= Instruction::IPUT_SHORT) {
-          uint16_t field_idx = mir->dalvikInsn.vC;
-          size_t i = ifield_pos;
-          while (i != 0u && field_idxs[i - 1] != field_idx) {
-            --i;
-          }
-          if (i != 0u) {
-            mir->meta.ifield_lowering_info = i - 1;
-          } else {
-            mir->meta.ifield_lowering_info = ifield_pos;
-            field_idxs[ifield_pos++] = field_idx;
-          }
-        } else {
-          uint16_t field_idx = mir->dalvikInsn.vB;
-          size_t i = sfield_pos;
-          while (i != max_refs && field_idxs[i] != field_idx) {
-            ++i;
-          }
-          if (i != max_refs) {
-            mir->meta.sfield_lowering_info = max_refs - i - 1u;
-          } else {
-            mir->meta.sfield_lowering_info = max_refs - sfield_pos;
-            field_idxs[--sfield_pos] = field_idx;
-          }
+      // Get field index and try to find it among existing indexes. If found, it's usually among
+      // the last few added, so we'll start the search from ifield_pos/sfield_pos. Though this
+      // is a linear search, it actually performs much better than map based approach.
+      if (IsInstructionIGetOrIPut(mir->dalvikInsn.opcode)) {
+        uint16_t field_idx = mir->dalvikInsn.vC;
+        size_t i = ifield_pos;
+        while (i != 0u && field_idxs[i - 1] != field_idx) {
+          --i;
         }
-        DCHECK_LE(ifield_pos, sfield_pos);
+        if (i != 0u) {
+          mir->meta.ifield_lowering_info = i - 1;
+          DCHECK_EQ(field_types[i - 1], IGetOrIPutMemAccessType(mir->dalvikInsn.opcode));
+        } else {
+          mir->meta.ifield_lowering_info = ifield_pos;
+          field_idxs[ifield_pos] = field_idx;
+          field_types[ifield_pos] = IGetOrIPutMemAccessType(mir->dalvikInsn.opcode);
+          ++ifield_pos;
+        }
+      } else if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) {
+        uint16_t field_idx = mir->dalvikInsn.vB;
+        size_t i = sfield_pos;
+        while (i != max_refs && field_idxs[i] != field_idx) {
+          ++i;
+        }
+        if (i != max_refs) {
+          mir->meta.sfield_lowering_info = max_refs - i - 1u;
+          DCHECK_EQ(field_types[i], SGetOrSPutMemAccessType(mir->dalvikInsn.opcode));
+        } else {
+          mir->meta.sfield_lowering_info = max_refs - sfield_pos;
+          --sfield_pos;
+          field_idxs[sfield_pos] = field_idx;
+          field_types[sfield_pos] = SGetOrSPutMemAccessType(mir->dalvikInsn.opcode);
+        }
       }
+      DCHECK_LE(ifield_pos, sfield_pos);
     }
   }
 
@@ -1256,7 +1260,7 @@
     DCHECK_EQ(ifield_lowering_infos_.size(), 0u);
     ifield_lowering_infos_.reserve(ifield_pos);
     for (size_t pos = 0u; pos != ifield_pos; ++pos) {
-      ifield_lowering_infos_.push_back(MirIFieldLoweringInfo(field_idxs[pos]));
+      ifield_lowering_infos_.push_back(MirIFieldLoweringInfo(field_idxs[pos], field_types[pos]));
     }
     MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(),
                                    ifield_lowering_infos_.data(), ifield_pos);
@@ -1268,7 +1272,7 @@
     sfield_lowering_infos_.reserve(max_refs - sfield_pos);
     for (size_t pos = max_refs; pos != sfield_pos;) {
       --pos;
-      sfield_lowering_infos_.push_back(MirSFieldLoweringInfo(field_idxs[pos]));
+      sfield_lowering_infos_.push_back(MirSFieldLoweringInfo(field_idxs[pos], field_types[pos]));
     }
     MirSFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(),
                                    sfield_lowering_infos_.data(), max_refs - sfield_pos);
@@ -1331,19 +1335,10 @@
       continue;
     }
     for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
-      if (mir->dalvikInsn.opcode >= Instruction::INVOKE_VIRTUAL &&
-          mir->dalvikInsn.opcode <= Instruction::INVOKE_INTERFACE_RANGE &&
-          mir->dalvikInsn.opcode != Instruction::RETURN_VOID_BARRIER) {
+      if (IsInstructionInvoke(mir->dalvikInsn.opcode)) {
         // Decode target method index and invoke type.
-        uint16_t target_method_idx;
-        uint16_t invoke_type_idx;
-        if (mir->dalvikInsn.opcode <= Instruction::INVOKE_INTERFACE) {
-          target_method_idx = mir->dalvikInsn.vB;
-          invoke_type_idx = mir->dalvikInsn.opcode - Instruction::INVOKE_VIRTUAL;
-        } else {
-          target_method_idx = mir->dalvikInsn.vB;
-          invoke_type_idx = mir->dalvikInsn.opcode - Instruction::INVOKE_VIRTUAL_RANGE;
-        }
+        uint16_t target_method_idx = mir->dalvikInsn.vB;
+        DexInvokeType invoke_type_idx = InvokeInstructionType(mir->dalvikInsn.opcode);
 
         // Find devirtualization target.
         // TODO: The devirt map is ordered by the dex pc here. Is there a way to get INVOKEs
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 51b6709..6704112 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,130 +235,130 @@
   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,
+  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 61 SGET_WIDE vAA, field@BBBB
-  DF_DA | DF_A_WIDE | DF_SFIELD | DF_UMS,
+  DF_DA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 62 SGET_OBJECT vAA, field@BBBB
-  DF_DA | DF_REF_A | DF_SFIELD | DF_UMS,
+  DF_DA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 63 SGET_BOOLEAN vAA, field@BBBB
-  DF_DA | DF_SFIELD | DF_UMS,
+  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 64 SGET_BYTE vAA, field@BBBB
-  DF_DA | DF_SFIELD | DF_UMS,
+  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 65 SGET_CHAR vAA, field@BBBB
-  DF_DA | DF_SFIELD | DF_UMS,
+  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 66 SGET_SHORT vAA, field@BBBB
-  DF_DA | DF_SFIELD | DF_UMS,
+  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 67 SPUT vAA, field@BBBB
-  DF_UA | DF_SFIELD | DF_UMS,
+  DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 68 SPUT_WIDE vAA, field@BBBB
-  DF_UA | DF_A_WIDE | DF_SFIELD | DF_UMS,
+  DF_UA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 69 SPUT_OBJECT vAA, field@BBBB
-  DF_UA | DF_REF_A | DF_SFIELD | DF_UMS,
+  DF_UA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 6A SPUT_BOOLEAN vAA, field@BBBB
-  DF_UA | DF_SFIELD | DF_UMS,
+  DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 6B SPUT_BYTE vAA, field@BBBB
-  DF_UA | DF_SFIELD | DF_UMS,
+  DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 6C SPUT_CHAR vAA, field@BBBB
-  DF_UA | DF_SFIELD | DF_UMS,
+  DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 6D SPUT_SHORT vAA, field@BBBB
-  DF_UA | DF_SFIELD | DF_UMS,
+  DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // 6E INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
   DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
@@ -370,7 +370,7 @@
   DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
 
   // 71 INVOKE_STATIC {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_UMS,
+  DF_FORMAT_35C | DF_CLINIT | DF_UMS,
 
   // 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
   DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
@@ -388,7 +388,7 @@
   DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
 
   // 77 INVOKE_STATIC_RANGE {vCCCC .. vNNNN}
-  DF_FORMAT_3RC | DF_UMS,
+  DF_FORMAT_3RC | DF_CLINIT | DF_UMS,
 
   // 78 INVOKE_INTERFACE_RANGE {vCCCC .. vNNNN}
   DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
@@ -712,31 +712,31 @@
   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,
+  DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // E6 SPUT_VOLATILE
-  DF_UA | DF_SFIELD | DF_UMS,
+  DF_UA | DF_SFIELD | DF_CLINIT | 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,
+  DF_DA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // EB SPUT_WIDE_VOLATILE
-  DF_UA | DF_A_WIDE | DF_SFIELD | DF_UMS,
+  DF_UA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // EC BREAKPOINT
   DF_NOP,
@@ -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,13 +787,13 @@
   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,
+  DF_DA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // FE SPUT_OBJECT_VOLATILE
-  DF_UA | DF_REF_A | DF_SFIELD | DF_UMS,
+  DF_UA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS,
 
   // FF UNUSED_FF
   DF_NOP,
@@ -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,22 @@
   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,
+
+  // 121 MirOpMaddInt
+  DF_FORMAT_EXTENDED,
+
+  // 122 MirOpMsubInt
+  DF_FORMAT_EXTENDED,
+
+  // 123 MirOpMaddLong
+  DF_FORMAT_EXTENDED,
+
+  // 124 MirOpMsubLong
+  DF_FORMAT_EXTENDED,
 };
 
 /* Return the base virtual register for a SSA name */
@@ -906,7 +918,7 @@
 
 /* Any register that is used before being defined is considered live-in */
 void MIRGraph::HandleLiveInUse(ArenaBitVector* use_v, ArenaBitVector* def_v,
-                            ArenaBitVector* live_in_v, int dalvik_reg_id) {
+                               ArenaBitVector* live_in_v, int dalvik_reg_id) {
   use_v->SetBit(dalvik_reg_id);
   if (!def_v->IsBitSet(dalvik_reg_id)) {
     live_in_v->SetBit(dalvik_reg_id);
@@ -919,8 +931,8 @@
 }
 
 void MIRGraph::HandleExtended(ArenaBitVector* use_v, ArenaBitVector* def_v,
-                            ArenaBitVector* live_in_v,
-                            const MIR::DecodedInstruction& d_insn) {
+                              ArenaBitVector* live_in_v,
+                              const MIR::DecodedInstruction& d_insn) {
   // For vector MIRs, vC contains type information
   bool is_vector_type_wide = false;
   int type_size = d_insn.vC >> 16;
@@ -951,6 +963,24 @@
         HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vB + 1);
       }
       break;
+    case kMirOpMaddInt:
+    case kMirOpMsubInt:
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vB);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vC);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.arg[0]);
+      HandleDef(def_v, d_insn.vA);
+      break;
+    case kMirOpMaddLong:
+    case kMirOpMsubLong:
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vB);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vB + 1);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vC);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.vC + 1);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.arg[0]);
+      HandleLiveInUse(use_v, def_v, live_in_v, d_insn.arg[0] + 1);
+      HandleDef(def_v, d_insn.vA);
+      HandleDef(def_v, d_insn.vA + 1);
+      break;
     default:
       LOG(ERROR) << "Unexpected Extended Opcode " << d_insn.opcode;
       break;
@@ -1139,6 +1169,28 @@
         HandleSSAUse(mir->ssa_rep->uses, d_insn.vB + 1, 1);
       }
       break;
+    case kMirOpMaddInt:
+    case kMirOpMsubInt:
+      AllocateSSAUseData(mir, 3);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.vB, 0);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.vC, 1);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.arg[0], 2);
+      AllocateSSADefData(mir, 1);
+      HandleSSADef(mir->ssa_rep->defs, d_insn.vA, 0);
+      break;
+    case kMirOpMaddLong:
+    case kMirOpMsubLong:
+      AllocateSSAUseData(mir, 6);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.vB, 0);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.vB + 1, 1);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.vC, 2);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.vC + 1, 3);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.arg[0], 4);
+      HandleSSAUse(mir->ssa_rep->uses, d_insn.arg[0] + 1, 5);
+      AllocateSSADefData(mir, 2);
+      HandleSSADef(mir->ssa_rep->defs, d_insn.vA, 0);
+      HandleSSADef(mir->ssa_rep->defs, d_insn.vA + 1, 1);
+      break;
     default:
       LOG(ERROR) << "Missing case for extended MIR: " << mir->dalvikInsn.opcode;
       break;
@@ -1343,7 +1395,7 @@
  * counts explicitly used s_regs.  A later phase will add implicit
  * counts for things such as Method*, null-checked references, etc.
  */
-void MIRGraph::CountUses(struct BasicBlock* bb) {
+void MIRGraph::CountUses(BasicBlock* bb) {
   if (bb->block_type != kDalvikByteCode) {
     return;
   }
@@ -1403,7 +1455,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.cc b/compiler/dex/mir_field_info.cc
index 68247b7..53afcad 100644
--- a/compiler/dex/mir_field_info.cc
+++ b/compiler/dex/mir_field_info.cc
@@ -35,7 +35,7 @@
     DCHECK(field_infos != nullptr);
     DCHECK_NE(count, 0u);
     for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
-      MirIFieldLoweringInfo unresolved(it->field_idx_);
+      MirIFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType());
       DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0);
     }
   }
@@ -62,10 +62,11 @@
     compiler_driver->GetResolvedFieldDexFileLocation(resolved_field,
         &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_field_idx_);
     bool is_volatile = compiler_driver->IsFieldVolatile(resolved_field);
-    it->field_offset_ = resolved_field->GetOffset();
+    it->field_offset_ = compiler_driver->GetFieldOffset(resolved_field);
     std::pair<bool, bool> fast_path = compiler_driver->IsFastInstanceField(
         dex_cache.Get(), referrer_class.Get(), resolved_field, field_idx);
     it->flags_ = 0u |  // Without kFlagIsStatic.
+        (it->flags_ & (kMemAccessTypeMask << kBitMemAccessTypeBegin)) |
         (is_volatile ? kFlagIsVolatile : 0u) |
         (fast_path.first ? kFlagFastGet : 0u) |
         (fast_path.second ? kFlagFastPut : 0u);
@@ -79,7 +80,7 @@
     DCHECK(field_infos != nullptr);
     DCHECK_NE(count, 0u);
     for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
-      MirSFieldLoweringInfo unresolved(it->field_idx_);
+      MirSFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType());
       // In 64-bit builds, there's padding after storage_index_, don't include it in memcmp.
       size_t size = OFFSETOF_MEMBER(MirSFieldLoweringInfo, storage_index_) +
           sizeof(it->storage_index_);
@@ -94,7 +95,7 @@
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
   Handle<mirror::ClassLoader> class_loader(
       hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
-  Handle<mirror::Class> referrer_class(hs.NewHandle(
+  Handle<mirror::Class> referrer_class_handle(hs.NewHandle(
       compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
   // definition) we still want to resolve fields and record all available info.
@@ -110,16 +111,28 @@
         &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_field_idx_);
     bool is_volatile = compiler_driver->IsFieldVolatile(resolved_field) ? 1u : 0u;
 
-    bool is_referrers_class, is_initialized;
+    mirror::Class* referrer_class = referrer_class_handle.Get();
     std::pair<bool, bool> fast_path = compiler_driver->IsFastStaticField(
-        dex_cache.Get(), referrer_class.Get(), resolved_field, field_idx, &it->field_offset_,
-        &it->storage_index_, &is_referrers_class, &is_initialized);
-    it->flags_ = kFlagIsStatic |
+        dex_cache.Get(), referrer_class, resolved_field, field_idx, &it->storage_index_);
+    uint16_t flags = kFlagIsStatic |
+        (it->flags_ & (kMemAccessTypeMask << kBitMemAccessTypeBegin)) |
         (is_volatile ? kFlagIsVolatile : 0u) |
         (fast_path.first ? kFlagFastGet : 0u) |
-        (fast_path.second ? kFlagFastPut : 0u) |
-        (is_referrers_class ? kFlagIsReferrersClass : 0u) |
-        (is_initialized ? kFlagIsInitialized : 0u);
+        (fast_path.second ? kFlagFastPut : 0u);
+    if (fast_path.first) {
+      it->field_offset_ = compiler_driver->GetFieldOffset(resolved_field);
+      bool is_referrers_class =
+          compiler_driver->IsStaticFieldInReferrerClass(referrer_class, resolved_field);
+      bool is_class_initialized =
+          compiler_driver->IsStaticFieldsClassInitialized(referrer_class, resolved_field);
+      bool is_class_in_dex_cache = !is_referrers_class &&  // If referrer's class, we don't care.
+          compiler_driver->CanAssumeTypeIsPresentInDexCache(*dex_cache->GetDexFile(),
+                                                            it->storage_index_);
+      flags |= (is_referrers_class ? kFlagIsReferrersClass : 0u) |
+          (is_class_initialized ? kFlagClassIsInitialized : 0u) |
+          (is_class_in_dex_cache ? kFlagClassIsInDexCache : 0u);
+    }
+    it->flags_ = flags;
   }
 }
 
diff --git a/compiler/dex/mir_field_info.h b/compiler/dex/mir_field_info.h
index 9745c41..ff427f8 100644
--- a/compiler/dex/mir_field_info.h
+++ b/compiler/dex/mir_field_info.h
@@ -20,6 +20,7 @@
 #include "base/macros.h"
 #include "dex_file.h"
 #include "offsets.h"
+#include "utils/dex_instruction_utils.h"
 
 namespace art {
 
@@ -63,18 +64,27 @@
     return (flags_ & kFlagIsVolatile) != 0u;
   }
 
+  DexMemAccessType MemAccessType() const {
+    return static_cast<DexMemAccessType>((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask);
+  }
+
  protected:
   enum {
     kBitIsStatic = 0,
     kBitIsVolatile,
-    kFieldInfoBitEnd
+    kBitMemAccessTypeBegin,
+    kBitMemAccessTypeEnd = kBitMemAccessTypeBegin + 3,  // 3 bits for raw type.
+    kFieldInfoBitEnd = kBitMemAccessTypeEnd
   };
   static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile;
   static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic;
+  static constexpr uint16_t kMemAccessTypeMask = 7u;
+  static_assert((1u << (kBitMemAccessTypeEnd - kBitMemAccessTypeBegin)) - 1u == kMemAccessTypeMask,
+                "Invalid raw type mask");
 
-  MirFieldInfo(uint16_t field_idx, uint16_t flags)
+  MirFieldInfo(uint16_t field_idx, uint16_t flags, DexMemAccessType type)
       : field_idx_(field_idx),
-        flags_(flags),
+        flags_(flags | static_cast<uint16_t>(type) << kBitMemAccessTypeBegin),
         declaring_field_idx_(0u),
         declaring_class_idx_(0u),
         declaring_dex_file_(nullptr) {
@@ -107,8 +117,8 @@
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Construct an unresolved instance field lowering info.
-  explicit MirIFieldLoweringInfo(uint16_t field_idx)
-      : MirFieldInfo(field_idx, kFlagIsVolatile),  // Without kFlagIsStatic.
+  explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type)
+      : MirFieldInfo(field_idx, kFlagIsVolatile, type),  // Without kFlagIsStatic.
         field_offset_(0u) {
   }
 
@@ -130,13 +140,14 @@
     kBitFastPut,
     kIFieldLoweringInfoBitEnd
   };
-  COMPILE_ASSERT(kIFieldLoweringInfoBitEnd <= 16, too_many_flags);
+  static_assert(kIFieldLoweringInfoBitEnd <= 16, "Too many flags");
   static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet;
   static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut;
 
   // The member offset of the field, 0u if unresolved.
   MemberOffset field_offset_;
 
+  friend class NullCheckEliminationTest;
   friend class GlobalValueNumberingTest;
   friend class LocalValueNumberingTest;
 };
@@ -154,8 +165,8 @@
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Construct an unresolved static field lowering info.
-  explicit MirSFieldLoweringInfo(uint16_t field_idx)
-      : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic),
+  explicit MirSFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type)
+      : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic, type),
         field_offset_(0u),
         storage_index_(DexFile::kDexNoIndex) {
   }
@@ -172,8 +183,12 @@
     return (flags_ & kFlagIsReferrersClass) != 0u;
   }
 
-  bool IsInitialized() const {
-    return (flags_ & kFlagIsInitialized) != 0u;
+  bool IsClassInitialized() const {
+    return (flags_ & kFlagClassIsInitialized) != 0u;
+  }
+
+  bool IsClassInDexCache() const {
+    return (flags_ & kFlagClassIsInDexCache) != 0u;
   }
 
   MemberOffset FieldOffset() const {
@@ -189,14 +204,16 @@
     kBitFastGet = kFieldInfoBitEnd,
     kBitFastPut,
     kBitIsReferrersClass,
-    kBitIsInitialized,
+    kBitClassIsInitialized,
+    kBitClassIsInDexCache,
     kSFieldLoweringInfoBitEnd
   };
-  COMPILE_ASSERT(kSFieldLoweringInfoBitEnd <= 16, too_many_flags);
+  static_assert(kSFieldLoweringInfoBitEnd <= 16, "Too many flags");
   static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet;
   static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut;
   static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass;
-  static constexpr uint16_t kFlagIsInitialized = 1u << kBitIsInitialized;
+  static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized;
+  static constexpr uint16_t kFlagClassIsInDexCache = 1u << kBitClassIsInDexCache;
 
   // The member offset of the field, 0u if unresolved.
   MemberOffset field_offset_;
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index bcbfb5a..abd3482 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -18,6 +18,7 @@
 
 #include <inttypes.h>
 #include <queue>
+#include <unistd.h>
 
 #include "base/bit_vector-inl.h"
 #include "base/stl_util.h"
@@ -70,6 +71,10 @@
   "MemBarrier",
   "PackedArrayGet",
   "PackedArrayPut",
+  "MaddInt",
+  "MsubInt",
+  "MaddLong",
+  "MsubLong",
 };
 
 MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena)
@@ -86,6 +91,10 @@
       raw_use_counts_(arena->Adapter()),
       num_reachable_blocks_(0),
       max_num_reachable_blocks_(0),
+      dfs_orders_up_to_date_(false),
+      domination_up_to_date_(false),
+      mir_ssa_rep_up_to_date_(false),
+      topological_order_up_to_date_(false),
       dfs_order_(arena->Adapter(kArenaAllocDfsPreOrder)),
       dfs_post_order_(arena->Adapter(kArenaAllocDfsPostOrder)),
       dom_post_order_traversal_(arena->Adapter(kArenaAllocDomPostOrder)),
@@ -93,18 +102,13 @@
       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),
-      def_block_matrix_(NULL),
       temp_scoped_alloc_(),
-      temp_insn_data_(nullptr),
-      temp_bit_vector_size_(0u),
-      temp_bit_vector_(nullptr),
-      temp_gvn_(),
       block_list_(arena->Adapter(kArenaAllocBBList)),
       try_block_addr_(NULL),
       entry_block_(NULL),
       exit_block_(NULL),
-      num_blocks_(0),
       current_code_item_(NULL),
       dex_pc_to_block_map_(arena->Adapter()),
       m_units_(arena->Adapter()),
@@ -130,7 +134,8 @@
       ifield_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)),
       sfield_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)),
       method_lowering_infos_(arena->Adapter(kArenaAllocLoweringInfo)),
-      gen_suspend_test_list_(arena->Adapter()) {
+      suspend_checks_in_loops_(nullptr) {
+  memset(&temp_, 0, sizeof(temp_));
   use_counts_.reserve(256);
   raw_use_counts_.reserve(256);
   block_list_.reserve(100);
@@ -178,7 +183,7 @@
                                  BasicBlock* orig_block, BasicBlock** immed_pred_block_p) {
   DCHECK_GT(code_offset, orig_block->start_offset);
   MIR* insn = orig_block->first_mir_insn;
-  MIR* prev = NULL;
+  MIR* prev = NULL;  // Will be set to instruction before split.
   while (insn) {
     if (insn->offset == code_offset) break;
     prev = insn;
@@ -187,6 +192,10 @@
   if (insn == NULL) {
     LOG(FATAL) << "Break split failed";
   }
+  // Now insn is at the instruction where we want to split, namely
+  // insn will be the first instruction of the "bottom" block.
+  // Similarly, prev will be the last instruction of the "top" block
+
   BasicBlock* bottom_block = CreateNewBB(kDalvikByteCode);
 
   bottom_block->start_offset = code_offset;
@@ -256,10 +265,11 @@
   DCHECK(insn != orig_block->first_mir_insn);
   DCHECK(insn == bottom_block->first_mir_insn);
   DCHECK_EQ(insn->offset, bottom_block->start_offset);
-  DCHECK(static_cast<int>(insn->dalvikInsn.opcode) == kMirOpCheck ||
-         !MIR::DecodedInstruction::IsPseudoMirOp(insn->dalvikInsn.opcode));
   DCHECK_EQ(dex_pc_to_block_map_[insn->offset], orig_block->id);
+  // Scan the "bottom" instructions, remapping them to the
+  // newly created "bottom" block.
   MIR* p = insn;
+  p->bb = bottom_block->id;
   dex_pc_to_block_map_[p->offset] = bottom_block->id;
   while (p != bottom_block->last_mir_insn) {
     p = p->next;
@@ -273,7 +283,11 @@
      * the first in a BasicBlock, we can't hit it here.
      */
     if ((opcode == kMirOpCheck) || !MIR::DecodedInstruction::IsPseudoMirOp(opcode)) {
-      DCHECK_EQ(dex_pc_to_block_map_[p->offset], orig_block->id);
+      BasicBlockId mapped_id = dex_pc_to_block_map_[p->offset];
+      // At first glance the instructions should all be mapped to orig_block.
+      // However, multiple instructions may correspond to the same dex, hence an earlier
+      // instruction may have already moved the mapping for dex to bottom_block.
+      DCHECK((mapped_id == orig_block->id) || (mapped_id == bottom_block->id));
       dex_pc_to_block_map_[p->offset] = bottom_block->id;
     }
   }
@@ -289,28 +303,28 @@
  * (by the caller)
  * Utilizes a map for fast lookup of the typical cases.
  */
-BasicBlock* MIRGraph::FindBlock(DexOffset code_offset, bool split, bool create,
+BasicBlock* MIRGraph::FindBlock(DexOffset code_offset, bool create,
                                 BasicBlock** immed_pred_block_p) {
   if (code_offset >= current_code_item_->insns_size_in_code_units_) {
-    return NULL;
+    return nullptr;
   }
 
   int block_id = dex_pc_to_block_map_[code_offset];
   BasicBlock* bb = GetBasicBlock(block_id);
 
-  if ((bb != NULL) && (bb->start_offset == code_offset)) {
+  if ((bb != nullptr) && (bb->start_offset == code_offset)) {
     // Does this containing block start with the desired instruction?
     return bb;
   }
 
   // No direct hit.
   if (!create) {
-    return NULL;
+    return nullptr;
   }
 
-  if (bb != NULL) {
+  if (bb != nullptr) {
     // The target exists somewhere in an existing block.
-    return SplitBlock(code_offset, bb, bb == *immed_pred_block_p ?  immed_pred_block_p : NULL);
+    return SplitBlock(code_offset, bb, bb == *immed_pred_block_p ?  immed_pred_block_p : nullptr);
   }
 
   // Create a new block.
@@ -341,14 +355,13 @@
   }
 
   // Iterate over each of the handlers to enqueue the empty Catch blocks.
-  const byte* handlers_ptr = DexFile::GetCatchHandlerData(*current_code_item_, 0);
+  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*current_code_item_, 0);
   uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
   for (uint32_t idx = 0; idx < handlers_size; idx++) {
     CatchHandlerIterator iterator(handlers_ptr);
     for (; iterator.HasNext(); iterator.Next()) {
       uint32_t address = iterator.GetHandlerAddress();
-      FindBlock(address, false /* split */, true /*create*/,
-                /* immed_pred_block_p */ NULL);
+      FindBlock(address, true /*create*/, /* immed_pred_block_p */ nullptr);
     }
     handlers_ptr = iterator.EndDataPointer();
   }
@@ -380,7 +393,7 @@
     switch (check_insn->Opcode()) {
       case Instruction::MOVE_WIDE:
         wide = true;
-        // Intentional fall-through.
+        FALLTHROUGH_INTENDED;
       case Instruction::MOVE_OBJECT:
       case Instruction::MOVE:
         dest = check_insn->VRegA_12x();
@@ -388,7 +401,7 @@
 
       case Instruction::MOVE_WIDE_FROM16:
         wide = true;
-        // Intentional fall-through.
+        FALLTHROUGH_INTENDED;
       case Instruction::MOVE_OBJECT_FROM16:
       case Instruction::MOVE_FROM16:
         dest = check_insn->VRegA_22x();
@@ -396,7 +409,7 @@
 
       case Instruction::MOVE_WIDE_16:
         wide = true;
-        // Intentional fall-through.
+        FALLTHROUGH_INTENDED;
       case Instruction::MOVE_OBJECT_16:
       case Instruction::MOVE_16:
         dest = check_insn->VRegA_32x();
@@ -406,7 +419,7 @@
       case Instruction::GOTO_16:
       case Instruction::GOTO_32:
         check_insn = check_insn->RelativeAt(check_insn->GetTargetOffset());
-        // Intentional fall-through.
+        FALLTHROUGH_INTENDED;
       default:
         return check_insn->Opcode() == Instruction::MONITOR_EXIT &&
             check_insn->VRegA_11x() == monitor_reg;
@@ -453,7 +466,7 @@
       LOG(FATAL) << "Unexpected opcode(" << insn->dalvikInsn.opcode << ") with kBranch set";
   }
   CountBranch(target);
-  BasicBlock* taken_block = FindBlock(target, /* split */ true, /* create */ true,
+  BasicBlock* taken_block = FindBlock(target, /* create */ true,
                                       /* immed_pred_block_p */ &cur_block);
   cur_block->taken = taken_block->id;
   taken_block->predecessors.push_back(cur_block->id);
@@ -461,19 +474,6 @@
   /* Always terminate the current block for conditional branches */
   if (flags & Instruction::kContinue) {
     BasicBlock* fallthrough_block = FindBlock(cur_offset +  width,
-                                             /*
-                                              * If the method is processed
-                                              * in sequential order from the
-                                              * beginning, we don't need to
-                                              * specify split for continue
-                                              * blocks. However, this
-                                              * routine can be called by
-                                              * compileLoop, which starts
-                                              * parsing the method from an
-                                              * arbitrary address in the
-                                              * method body.
-                                              */
-                                             true,
                                              /* create */
                                              true,
                                              /* immed_pred_block_p */
@@ -481,8 +481,7 @@
     cur_block->fall_through = fallthrough_block->id;
     fallthrough_block->predecessors.push_back(cur_block->id);
   } else if (code_ptr < code_end) {
-    FindBlock(cur_offset + width, /* split */ false, /* create */ true,
-                /* immed_pred_block_p */ NULL);
+    FindBlock(cur_offset + width, /* create */ true, /* immed_pred_block_p */ nullptr);
   }
   return cur_block;
 }
@@ -490,6 +489,7 @@
 /* Process instructions with the kSwitch flag */
 BasicBlock* MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset,
                                        int width, int flags) {
+  UNUSED(flags);
   const uint16_t* switch_data =
       reinterpret_cast<const uint16_t*>(GetCurrentInsns() + cur_offset + insn->dalvikInsn.vB);
   int size;
@@ -541,8 +541,8 @@
   cur_block->successor_blocks.reserve(size);
 
   for (i = 0; i < size; i++) {
-    BasicBlock* case_block = FindBlock(cur_offset + target_table[i], /* split */ true,
-                                      /* create */ true, /* immed_pred_block_p */ &cur_block);
+    BasicBlock* case_block = FindBlock(cur_offset + target_table[i],  /* create */ true,
+                                       /* immed_pred_block_p */ &cur_block);
     SuccessorBlockInfo* successor_block_info =
         static_cast<SuccessorBlockInfo*>(arena_->Alloc(sizeof(SuccessorBlockInfo),
                                                        kArenaAllocSuccessor));
@@ -555,8 +555,8 @@
   }
 
   /* Fall-through case */
-  BasicBlock* fallthrough_block = FindBlock(cur_offset +  width, /* split */ false,
-                                            /* create */ true, /* immed_pred_block_p */ NULL);
+  BasicBlock* fallthrough_block = FindBlock(cur_offset +  width, /* create */ true,
+                                            /* immed_pred_block_p */ nullptr);
   cur_block->fall_through = fallthrough_block->id;
   fallthrough_block->predecessors.push_back(cur_block->id);
   return cur_block;
@@ -566,6 +566,7 @@
 BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset,
                                       int width, int flags, ArenaBitVector* try_block_addr,
                                       const uint16_t* code_ptr, const uint16_t* code_end) {
+  UNUSED(flags);
   bool in_try_block = try_block_addr->IsBitSet(cur_offset);
   bool is_throw = (insn->dalvikInsn.opcode == Instruction::THROW);
 
@@ -580,8 +581,8 @@
     }
 
     for (; iterator.HasNext(); iterator.Next()) {
-      BasicBlock* catch_block = FindBlock(iterator.GetHandlerAddress(), false /* split*/,
-                                         false /* creat */, NULL  /* immed_pred_block_p */);
+      BasicBlock* catch_block = FindBlock(iterator.GetHandlerAddress(), false /* create */,
+                                          nullptr /* immed_pred_block_p */);
       if (insn->dalvikInsn.opcode == Instruction::MONITOR_EXIT &&
           IsBadMonitorExitCatch(insn->offset, catch_block->start_offset)) {
         // Don't allow monitor-exit to catch its own exception, http://b/15745363 .
@@ -616,8 +617,7 @@
     cur_block->explicit_throw = true;
     if (code_ptr < code_end) {
       // Force creation of new block following THROW via side-effect.
-      FindBlock(cur_offset + width, /* split */ false, /* create */ true,
-                /* immed_pred_block_p */ NULL);
+      FindBlock(cur_offset + width, /* create */ true, /* immed_pred_block_p */ nullptr);
     }
     if (!in_try_block) {
        // Don't split a THROW that can't rethrow - we're done.
@@ -694,7 +694,7 @@
   if (current_method_ == 0) {
     DCHECK(entry_block_ == NULL);
     DCHECK(exit_block_ == NULL);
-    DCHECK_EQ(num_blocks_, 0U);
+    DCHECK_EQ(GetNumBlocks(), 0U);
     // Use id 0 to represent a null block.
     BasicBlock* null_block = CreateNewBB(kNullBlock);
     DCHECK_EQ(null_block->id, NullBasicBlockId);
@@ -772,8 +772,9 @@
       } else {
         DCHECK(cur_block->fall_through == NullBasicBlockId);
         DCHECK(cur_block->taken == NullBasicBlockId);
-        // Unreachable instruction, mark for no continuation.
+        // Unreachable instruction, mark for no continuation and end basic block.
         flags &= ~Instruction::kContinue;
+        FindBlock(current_offset_ + width, /* create */ true, /* immed_pred_block_p */ nullptr);
       }
     } else {
       cur_block->AppendMIR(insn);
@@ -800,8 +801,7 @@
          * Create a fallthrough block for real instructions
          * (incl. NOP).
          */
-         FindBlock(current_offset_ + width, /* split */ false, /* create */ true,
-                   /* immed_pred_block_p */ NULL);
+         FindBlock(current_offset_ + width, /* create */ true, /* immed_pred_block_p */ nullptr);
       }
     } else if (flags & Instruction::kThrow) {
       cur_block = ProcessCanThrow(cur_block, insn, current_offset_, width, flags, try_block_addr_,
@@ -824,8 +824,8 @@
       }
     }
     current_offset_ += width;
-    BasicBlock* next_block = FindBlock(current_offset_, /* split */ false, /* create */
-                                      false, /* immed_pred_block_p */ NULL);
+    BasicBlock* next_block = FindBlock(current_offset_, /* create */ false,
+                                       /* immed_pred_block_p */ nullptr);
     if (next_block) {
       /*
        * The next instruction could be the target of a previously parsed
@@ -877,6 +877,34 @@
   return GetDataFlowAttributes(opcode);
 }
 
+// The path can easily surpass FS limits because of parameters etc. Use pathconf to get FS
+// restrictions here. Note that a successful invocation will return an actual value. If the path
+// is too long for some reason, the return will be ENAMETOOLONG. Then cut off part of the name.
+//
+// It's possible the path is not valid, or some other errors appear. In that case return false.
+static bool CreateDumpFile(std::string& fname, const char* dir_prefix, NarrowDexOffset start_offset,
+                           const char *suffix, int nr, std::string* output) {
+  std::string dir = StringPrintf("./%s", dir_prefix);
+  int64_t max_name_length = pathconf(dir.c_str(), _PC_NAME_MAX);
+  if (max_name_length <= 0) {
+    PLOG(ERROR) << "Could not get file name restrictions for " << dir;
+    return false;
+  }
+
+  std::string name = StringPrintf("%s%x%s_%d.dot", fname.c_str(), start_offset,
+                                  suffix == nullptr ? "" : suffix, nr);
+  std::string fpath;
+  if (static_cast<int64_t>(name.size()) > max_name_length) {
+    std::string suffix_str = StringPrintf("_%d.dot", nr);
+    name = name.substr(0, static_cast<size_t>(max_name_length) - suffix_str.size()) + suffix_str;
+  }
+  // Sanity check.
+  DCHECK_LE(name.size(), static_cast<size_t>(max_name_length));
+
+  *output = StringPrintf("%s%s", dir_prefix, name.c_str());
+  return true;
+}
+
 // TODO: use a configurable base prefix, and adjust callers to supply pass name.
 /* Dump the CFG into a DOT graph */
 void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks, const char *suffix) {
@@ -885,15 +913,19 @@
 
   // Increment counter to get a unique file number.
   cnt++;
+  int nr = cnt.LoadRelaxed();
 
   std::string fname(PrettyMethod(cu_->method_idx, *cu_->dex_file));
   ReplaceSpecialChars(fname);
-  fname = StringPrintf("%s%s%x%s_%d.dot", dir_prefix, fname.c_str(),
-                      GetBasicBlock(GetEntryBlock()->fall_through)->start_offset,
-                      suffix == nullptr ? "" : suffix,
-                      cnt.LoadRelaxed());
-  file = fopen(fname.c_str(), "w");
+  std::string fpath;
+  if (!CreateDumpFile(fname, dir_prefix, GetBasicBlock(GetEntryBlock()->fall_through)->start_offset,
+                      suffix, nr, &fpath)) {
+    LOG(ERROR) << "Could not create dump file name for " << fname;
+    return;
+  }
+  file = fopen(fpath.c_str(), "w");
   if (file == NULL) {
+    PLOG(ERROR) << "Could not open " << fpath << " for DumpCFG.";
     return;
   }
   fprintf(file, "digraph G {\n");
@@ -921,7 +953,7 @@
                 bb->first_mir_insn ? " | " : " ");
         for (mir = bb->first_mir_insn; mir; mir = mir->next) {
             int opcode = mir->dalvikInsn.opcode;
-            fprintf(file, "    {%04x %s %s %s %s %s %s %s\\l}%s\\\n", mir->offset,
+            fprintf(file, "    {%04x %s %s %s %s %s %s %s %s %s\\l}%s\\\n", mir->offset,
                       mir->ssa_rep ? GetDalvikDisassembly(mir) :
                       !MIR::DecodedInstruction::IsPseudoMirOp(opcode) ?
                         Instruction::Name(mir->dalvikInsn.opcode) :
@@ -931,7 +963,9 @@
                       (mir->optimization_flags & MIR_IGNORE_SUSPEND_CHECK) != 0 ? " no_suspendcheck" : " ",
                       (mir->optimization_flags & MIR_STORE_NON_TEMPORAL) != 0 ? " non_temporal" : " ",
                       (mir->optimization_flags & MIR_CALLEE) != 0 ? " inlined" : " ",
-                      (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) != 0 ? " no_clinit" : " ",
+                      (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0 ? " cl_inited" : " ",
+                      (mir->optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0 ? " cl_in_cache" : " ",
+                      (mir->optimization_flags & MIR_IGNORE_DIV_ZERO_CHECK) != 0 ? " no_div_check" : " ",
                       mir->next ? " | " : " ");
         }
         fprintf(file, "  }\"];\n\n");
@@ -1174,6 +1208,14 @@
   return true;
 }
 
+MIR* BasicBlock::GetFirstNonPhiInsn() {
+  MIR* mir = first_mir_insn;
+  while (mir != nullptr && static_cast<int>(mir->dalvikInsn.opcode) == kMirOpPhi) {
+    mir = mir->next;
+  }
+  return mir;
+}
+
 MIR* BasicBlock::GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current) {
   MIR* next_mir = nullptr;
 
@@ -1214,6 +1256,10 @@
   int defs = (ssa_rep != nullptr) ? ssa_rep->num_defs : 0;
   int uses = (ssa_rep != nullptr) ? ssa_rep->num_uses : 0;
 
+  if (opcode < kMirOpFirst) {
+    return;  // It is not an extended instruction.
+  }
+
   decoded_mir->append(extended_mir_op_names_[opcode - kMirOpFirst]);
 
   switch (opcode) {
@@ -1349,9 +1395,10 @@
           decoded_mir->append(", ");
           decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[1], false));
         }
-        decoded_mir->append(StringPrintf(" = vect%d", mir->dalvikInsn.vB));
+        decoded_mir->append(StringPrintf(" = vect%d (extr_idx:%d)", mir->dalvikInsn.vB, mir->dalvikInsn.arg[0]));
       } else {
-        decoded_mir->append(StringPrintf(" v%d = vect%d", mir->dalvikInsn.vA, mir->dalvikInsn.vB));
+        decoded_mir->append(StringPrintf(" v%d = vect%d (extr_idx:%d)", mir->dalvikInsn.vA,
+                                         mir->dalvikInsn.vB, mir->dalvikInsn.arg[0]));
       }
       FillTypeSizeString(mir->dalvikInsn.vC, decoded_mir);
       break;
@@ -1378,6 +1425,27 @@
       }
       FillTypeSizeString(mir->dalvikInsn.arg[0], decoded_mir);
       break;
+    case kMirOpMaddInt:
+    case kMirOpMsubInt:
+    case kMirOpMaddLong:
+    case kMirOpMsubLong:
+      if (ssa_rep != nullptr) {
+        decoded_mir->append(" ");
+        decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[0], false));
+        if (defs > 1) {
+          decoded_mir->append(", ");
+          decoded_mir->append(GetSSANameWithConst(ssa_rep->defs[1], false));
+        }
+        for (int i = 0; i < uses; i++) {
+          decoded_mir->append(", ");
+          decoded_mir->append(GetSSANameWithConst(ssa_rep->uses[i], false));
+        }
+      } else {
+        decoded_mir->append(StringPrintf(" v%d, v%d, v%d, v%d",
+                                         mir->dalvikInsn.vA, mir->dalvikInsn.vB,
+                                         mir->dalvikInsn.vC, mir->dalvikInsn.arg[0]));
+      }
+      break;
     default:
       break;
   }
@@ -1537,7 +1605,8 @@
     return GetSSAName(ssa_reg);
   }
   if (IsConst(reg_location_[ssa_reg])) {
-    if (!singles_only && reg_location_[ssa_reg].wide) {
+    if (!singles_only && reg_location_[ssa_reg].wide &&
+        !reg_location_[ssa_reg].high_word) {
       return StringPrintf("v%d_%d#0x%" PRIx64, SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg),
                           ConstantValueWide(reg_location_[ssa_reg]));
     } else {
@@ -1581,6 +1650,12 @@
   return cu_->dex_file->GetShorty(method_id.proto_idx_);
 }
 
+const char* MIRGraph::GetShortyFromMethodReference(const MethodReference& target_method) {
+  const DexFile::MethodId& method_id =
+      target_method.dex_file->GetMethodId(target_method.dex_method_index);
+  return target_method.dex_file->GetShorty(method_id.proto_idx_);
+}
+
 /* Debug Utility - dump a compilation unit */
 void MIRGraph::DumpMIRGraph() {
   const char* block_type_names[] = {
@@ -1681,9 +1756,9 @@
 void MIRGraph::SSATransformationStart() {
   DCHECK(temp_scoped_alloc_.get() == nullptr);
   temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
-  temp_bit_vector_size_ = GetNumOfCodeAndTempVRs();
-  temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
-      temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapRegisterV);
+  temp_.ssa.num_vregs = GetNumOfCodeAndTempVRs();
+  temp_.ssa.work_live_vregs = new (temp_scoped_alloc_.get()) ArenaBitVector(
+      temp_scoped_alloc_.get(), temp_.ssa.num_vregs, false, kBitMapRegisterV);
 }
 
 void MIRGraph::SSATransformationEnd() {
@@ -1692,13 +1767,17 @@
     VerifyDataflow();
   }
 
-  temp_bit_vector_size_ = 0u;
-  temp_bit_vector_ = nullptr;
+  temp_.ssa.num_vregs = 0u;
+  temp_.ssa.work_live_vregs = nullptr;
+  temp_.ssa.def_block_matrix = nullptr;
   DCHECK(temp_scoped_alloc_.get() != nullptr);
   temp_scoped_alloc_.reset();
 
   // Update the maximum number of reachable blocks.
   max_num_reachable_blocks_ = num_reachable_blocks_;
+
+  // Mark MIR SSA representations as up to date.
+  mir_ssa_rep_up_to_date_ = true;
 }
 
 size_t MIRGraph::GetNumDalvikInsns() const {
@@ -1931,6 +2010,7 @@
     DCHECK_EQ(bb->hidden, false);
     DCHECK_EQ(bb->visited, false);
     bb->visited = true;
+    bb->nesting_depth = loop_head_stack.size();
 
     // Now add the basic block.
     uint16_t idx = static_cast<uint16_t>(topological_order_.size());
@@ -1962,6 +2042,8 @@
   // 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;
+  topological_order_up_to_date_ = true;
 }
 
 bool BasicBlock::IsExceptionBlock() const {
@@ -1971,24 +2053,6 @@
   return false;
 }
 
-bool MIRGraph::HasSuspendTestBetween(BasicBlock* source, BasicBlockId target_id) {
-  BasicBlock* target = GetBasicBlock(target_id);
-
-  if (source == nullptr || target == nullptr)
-    return false;
-
-  int idx;
-  for (idx = gen_suspend_test_list_.size() - 1; idx >= 0; idx--) {
-    BasicBlock* bb = gen_suspend_test_list_[idx];
-    if (bb == source)
-      return true;  // The block has been inserted by a suspend check before.
-    if (source->dominators->IsBitSet(bb->id) && bb->dominators->IsBitSet(target_id))
-      return true;
-  }
-
-  return false;
-}
-
 ChildBlockIterator::ChildBlockIterator(BasicBlock* bb, MIRGraph* mir_graph)
     : basic_block_(bb), mir_graph_(mir_graph), visited_fallthrough_(false),
       visited_taken_(false), have_successors_(false) {
@@ -2211,11 +2275,18 @@
   }
 }
 
-void BasicBlock::Hide(CompilationUnit* c_unit) {
-  // First lets make it a dalvik bytecode block so it doesn't have any special meaning.
-  block_type = kDalvikByteCode;
+void BasicBlock::Kill(MIRGraph* mir_graph) {
+  for (BasicBlockId pred_id : predecessors) {
+    BasicBlock* pred_bb = mir_graph->GetBasicBlock(pred_id);
+    DCHECK(pred_bb != nullptr);
 
-  // Mark it as hidden.
+    // Sadly we have to go through the children by hand here.
+    pred_bb->ReplaceChild(id, NullBasicBlockId);
+  }
+  predecessors.clear();
+
+  // 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
@@ -2226,27 +2297,25 @@
   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);
+  data_flow_info = nullptr;
 
-    // Sadly we have to go through the children by hand here.
-    pred_bb->ReplaceChild(id, NullBasicBlockId);
+  // 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);
   }
 
-  // Iterate through children of bb we are hiding.
-  ChildBlockIterator successorChildIter(this, mir_graph);
-
-  for (BasicBlock* childPtr = successorChildIter.Next(); childPtr != 0; childPtr = successorChildIter.Next()) {
-    // Erase this predecessor from child.
-    childPtr->ErasePredecessor(id);
-  }
-
-  // Remove link to children.
-  taken = NullBasicBlockId;
+  // 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) {
@@ -2320,24 +2389,42 @@
 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;
   }
 }
 
 // Create a new basic block with block_id as num_blocks_ that is
 // post-incremented.
 BasicBlock* MIRGraph::CreateNewBB(BBType block_type) {
-  BasicBlock* res = NewMemBB(block_type, num_blocks_++);
+  BasicBlockId id = static_cast<BasicBlockId>(block_list_.size());
+  BasicBlock* res = NewMemBB(block_type, id);
   block_list_.push_back(res);
   return res;
 }
@@ -2347,10 +2434,6 @@
   driver.Launch();
 }
 
-void MIRGraph::InitializeBasicBlockData() {
-  num_blocks_ = block_list_.size();
-}
-
 int MIR::DecodedInstruction::FlagsOf() const {
   // Calculate new index.
   int idx = static_cast<int>(opcode) - kNumPackedOpcodes;
@@ -2428,6 +2511,11 @@
       return Instruction::kContinue | Instruction::kThrow;
     case kMirOpPackedArrayPut:
       return Instruction::kContinue | Instruction::kThrow;
+    case kMirOpMaddInt:
+    case kMirOpMsubInt:
+    case kMirOpMaddLong:
+    case kMirOpMsubLong:
+      return Instruction::kContinue;
     default:
       LOG(WARNING) << "ExtendedFlagsOf: Unhandled case: " << static_cast<int> (opcode);
       return 0;
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index f14b187..af97f51 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -34,6 +34,7 @@
 
 namespace art {
 
+class DexFileMethodInliner;
 class GlobalValueNumbering;
 
 enum DataFlowAttributePos {
@@ -49,17 +50,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,
@@ -72,6 +70,7 @@
   kUsesMethodStar,       // Implicit use of Method*.
   kUsesIField,           // Accesses an instance field (IGET/IPUT).
   kUsesSField,           // Accesses a static field (SGET/SPUT).
+  kCanInitializeClass,   // Can trigger class initialization (SGET/SPUT/INVOKE_STATIC).
   kDoLVN,                // Worth computing local value numbers.
 };
 
@@ -88,17 +87,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)
@@ -111,20 +107,18 @@
 #define DF_UMS                  (UINT64_C(1) << kUsesMethodStar)
 #define DF_IFIELD               (UINT64_C(1) << kUsesIField)
 #define DF_SFIELD               (UINT64_C(1) << kUsesSField)
+#define DF_CLINIT               (UINT64_C(1) << kCanInitializeClass)
 #define DF_LVN                  (UINT64_C(1) << kDoLVN)
 
 #define DF_HAS_USES             (DF_UA | DF_UB | DF_UC)
 
 #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,16 +126,15 @@
 #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.
 };
 
 #define METHOD_IS_LEAF          (1 << kIsLeaf)
-#define METHOD_HAS_LOOP         (1 << kHasLoop)
 
 // Minimum field size to contain Dalvik v_reg number.
 #define VREG_NUM_WIDTH 16
@@ -151,15 +144,17 @@
 #define INVALID_OFFSET (0xDEADF00FU)
 
 #define MIR_IGNORE_NULL_CHECK           (1 << kMIRIgnoreNullCheck)
-#define MIR_NULL_CHECK_ONLY             (1 << kMIRNullCheckOnly)
 #define MIR_IGNORE_RANGE_CHECK          (1 << kMIRIgnoreRangeCheck)
-#define MIR_RANGE_CHECK_ONLY            (1 << kMIRRangeCheckOnly)
-#define MIR_IGNORE_CLINIT_CHECK         (1 << kMIRIgnoreClInitCheck)
+#define MIR_STORE_NON_NULL_VALUE        (1 << kMIRStoreNonNullValue)
+#define MIR_CLASS_IS_INITIALIZED        (1 << kMIRClassIsInitialized)
+#define MIR_CLASS_IS_IN_DEX_CACHE       (1 << kMIRClassIsInDexCache)
+#define MIR_IGNORE_DIV_ZERO_CHECK       (1 << kMirIgnoreDivZeroCheck)
 #define MIR_INLINED                     (1 << kMIRInlined)
 #define MIR_INLINED_PRED                (1 << kMIRInlinedPred)
 #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
@@ -198,9 +193,7 @@
   ArenaBitVector* use_v;
   ArenaBitVector* def_v;
   ArenaBitVector* live_in_v;
-  ArenaBitVector* phi_v;
   int32_t* vreg_to_ssa_map_exit;
-  ArenaBitVector* ending_check_v;  // For null check and class init check elimination.
 };
 
 /*
@@ -233,7 +226,8 @@
  * The Midlevel Intermediate Representation node, which may be largely considered a
  * wrapper around a Dalvik byte code.
  */
-struct MIR {
+class MIR : public ArenaObject<kArenaAllocMIR> {
+ public:
   /*
    * TODO: remove embedded DecodedInstruction to save space, keeping only opcode.  Recover
    * additional fields on as-needed basis.  Question: how to support MIR Pseudo-ops; probably
@@ -338,7 +332,7 @@
     uint32_t method_lowering_info;
   } meta;
 
-  explicit MIR():offset(0), optimization_flags(0), m_unit_index(0), bb(NullBasicBlockId),
+  explicit MIR() : offset(0), optimization_flags(0), m_unit_index(0), bb(NullBasicBlockId),
                  next(nullptr), ssa_rep(nullptr) {
     memset(&meta, 0, sizeof(meta));
   }
@@ -349,16 +343,12 @@
 
   MIR* Copy(CompilationUnit *c_unit);
   MIR* Copy(MIRGraph* mir_Graph);
-
-  static void* operator new(size_t size, ArenaAllocator* arena) {
-    return arena->Alloc(sizeof(MIR), kArenaAllocMIR);
-  }
-  static void operator delete(void* p) {}  // Nop.
 };
 
 struct SuccessorBlockInfo;
 
-struct BasicBlock {
+class BasicBlock : public DeletableArenaObject<kArenaAllocBB> {
+ public:
   BasicBlock(BasicBlockId block_id, BBType type, ArenaAllocator* allocator)
       : id(block_id),
         dfs_id(), start_offset(), fall_through(), taken(), i_dom(), nesting_depth(),
@@ -419,12 +409,11 @@
   void ResetOptimizationFlags(uint16_t reset_flags);
 
   /**
-   * @brief Hide the BasicBlock.
-   * @details Set it to kDalvikByteCode, set hidden to true, remove all MIRs,
-   *          remove itself from any predecessor edges, remove itself from any
-   *          child's predecessor array.
+   * @brief Kill the BasicBlock.
+   * @details Unlink predecessors and successors, remove all MIRs, set the block type to kDead
+   *          and set hidden to true.
    */
-  void Hide(CompilationUnit* c_unit);
+  void Kill(MIRGraph* mir_graph);
 
   /**
    * @brief Is ssa_reg the last SSA definition of that VR in the block?
@@ -447,6 +436,11 @@
   void UpdatePredecessor(BasicBlockId old_pred, BasicBlockId new_pred);
 
   /**
+   * @brief Return first non-Phi insn.
+   */
+  MIR* GetFirstNonPhiInsn();
+
+  /**
    * @brief Used to obtain the next MIR that follows unconditionally.
    * @details The implementation does not guarantee that a MIR does not
    * follow even if this method returns nullptr.
@@ -457,10 +451,8 @@
   MIR* GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current);
   bool IsExceptionBlock() const;
 
-  static void* operator new(size_t size, ArenaAllocator* arena) {
-    return arena->Alloc(sizeof(BasicBlock), kArenaAllocBB);
-  }
-  static void operator delete(void* p) {}  // Nop.
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicBlock);
 };
 
 /*
@@ -548,7 +540,7 @@
 
   /* Find existing block */
   BasicBlock* FindBlock(DexOffset code_offset) {
-    return FindBlock(code_offset, false, false, NULL);
+    return FindBlock(code_offset, false, NULL);
   }
 
   const uint16_t* GetCurrentInsns() const {
@@ -572,11 +564,11 @@
    * @return Returns the raw table pointer.
    */
   const uint16_t* GetTable(MIR* mir, uint32_t table_offset) const {
-    return GetInsns(mir->m_unit_index) + mir->offset + table_offset;
+    return GetInsns(mir->m_unit_index) + mir->offset + static_cast<int32_t>(table_offset);
   }
 
   unsigned int GetNumBlocks() const {
-    return num_blocks_;
+    return block_list_.size();
   }
 
   /**
@@ -627,7 +619,7 @@
     return def_count_;
   }
 
-  ArenaAllocator* GetArena() {
+  ArenaAllocator* GetArena() const {
     return arena_;
   }
 
@@ -666,13 +658,29 @@
   void DoCacheFieldLoweringInfo();
 
   const MirIFieldLoweringInfo& GetIFieldLoweringInfo(MIR* mir) const {
-    DCHECK_LT(mir->meta.ifield_lowering_info, ifield_lowering_infos_.size());
-    return ifield_lowering_infos_[mir->meta.ifield_lowering_info];
+    return GetIFieldLoweringInfo(mir->meta.ifield_lowering_info);
+  }
+
+  const MirIFieldLoweringInfo& GetIFieldLoweringInfo(uint32_t lowering_info) const {
+    DCHECK_LT(lowering_info, ifield_lowering_infos_.size());
+    return ifield_lowering_infos_[lowering_info];
+  }
+
+  size_t GetIFieldLoweringInfoCount() const {
+    return ifield_lowering_infos_.size();
   }
 
   const MirSFieldLoweringInfo& GetSFieldLoweringInfo(MIR* mir) const {
-    DCHECK_LT(mir->meta.sfield_lowering_info, sfield_lowering_infos_.size());
-    return sfield_lowering_infos_[mir->meta.sfield_lowering_info];
+    return GetSFieldLoweringInfo(mir->meta.sfield_lowering_info);
+  }
+
+  const MirSFieldLoweringInfo& GetSFieldLoweringInfo(uint32_t lowering_info) const {
+    DCHECK_LT(lowering_info, sfield_lowering_infos_.size());
+    return sfield_lowering_infos_[lowering_info];
+  }
+
+  size_t GetSFieldLoweringInfoCount() const {
+    return sfield_lowering_infos_.size();
   }
 
   void DoCacheMethodLoweringInfo();
@@ -690,7 +698,9 @@
 
   void DumpRegLocTable(RegLocation* table, int count);
 
+  void BasicBlockOptimizationStart();
   void BasicBlockOptimization();
+  void BasicBlockOptimizationEnd();
 
   const ArenaVector<BasicBlockId>& GetTopologicalSortOrder() {
     DCHECK(!topological_order_.empty());
@@ -712,6 +722,14 @@
     return &topological_order_loop_head_stack_;
   }
 
+  size_t GetMaxNestedLoops() const {
+    return max_nested_loops_;
+  }
+
+  bool IsLoopHead(BasicBlockId bb_id) {
+    return topological_order_loop_ends_[topological_order_indexes_[bb_id]] != 0u;
+  }
+
   bool IsConst(int32_t s_reg) const {
     return is_constant_v_->IsBitSet(s_reg);
   }
@@ -950,13 +968,23 @@
     return reg_location_[method_sreg_];
   }
 
-  bool IsBackedge(BasicBlock* branch_bb, BasicBlockId target_bb_id) {
-    return ((target_bb_id != NullBasicBlockId) &&
-            (GetBasicBlock(target_bb_id)->start_offset <= branch_bb->start_offset));
+  bool IsBackEdge(BasicBlock* branch_bb, BasicBlockId target_bb_id) {
+    DCHECK_NE(target_bb_id, NullBasicBlockId);
+    DCHECK_LT(target_bb_id, topological_order_indexes_.size());
+    DCHECK_LT(branch_bb->id, topological_order_indexes_.size());
+    return topological_order_indexes_[target_bb_id] <= topological_order_indexes_[branch_bb->id];
   }
 
-  bool IsBackwardsBranch(BasicBlock* branch_bb) {
-    return IsBackedge(branch_bb, branch_bb->taken) || IsBackedge(branch_bb, branch_bb->fall_through);
+  bool IsSuspendCheckEdge(BasicBlock* branch_bb, BasicBlockId target_bb_id) {
+    if (!IsBackEdge(branch_bb, target_bb_id)) {
+      return false;
+    }
+    if (suspend_checks_in_loops_ == nullptr) {
+      // We didn't run suspend check elimination.
+      return true;
+    }
+    uint16_t target_depth = GetBasicBlock(target_bb_id)->nesting_depth;
+    return (suspend_checks_in_loops_[branch_bb->id] & (1u << (target_depth - 1u))) == 0;
   }
 
   void CountBranch(DexOffset target_offset) {
@@ -1017,20 +1045,43 @@
     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;
   void VerifyDataflow();
   void CheckForDominanceFrontier(BasicBlock* dom_bb, const BasicBlock* succ_bb);
-  void EliminateNullChecksAndInferTypesStart();
-  bool EliminateNullChecksAndInferTypes(BasicBlock* bb);
-  void EliminateNullChecksAndInferTypesEnd();
+  bool EliminateNullChecksGate();
+  bool EliminateNullChecks(BasicBlock* bb);
+  void EliminateNullChecksEnd();
+  bool InferTypes(BasicBlock* bb);
   bool EliminateClassInitChecksGate();
   bool EliminateClassInitChecks(BasicBlock* bb);
   void EliminateClassInitChecksEnd();
   bool ApplyGlobalValueNumberingGate();
   bool ApplyGlobalValueNumbering(BasicBlock* bb);
   void ApplyGlobalValueNumberingEnd();
+  bool EliminateSuspendChecksGate();
+  bool EliminateSuspendChecks(BasicBlock* bb);
+  void EliminateSuspendChecksEnd();
+
+  uint16_t GetGvnIFieldId(MIR* mir) const {
+    DCHECK(IsInstructionIGetOrIPut(mir->dalvikInsn.opcode));
+    DCHECK_LT(mir->meta.ifield_lowering_info, ifield_lowering_infos_.size());
+    DCHECK(temp_.gvn.ifield_ids_ != nullptr);
+    return temp_.gvn.ifield_ids_[mir->meta.ifield_lowering_info];
+  }
+
+  uint16_t GetGvnSFieldId(MIR* mir) const {
+    DCHECK(IsInstructionSGetOrSPut(mir->dalvikInsn.opcode));
+    DCHECK_LT(mir->meta.sfield_lowering_info, sfield_lowering_infos_.size());
+    DCHECK(temp_.gvn.sfield_ids_ != nullptr);
+    return temp_.gvn.sfield_ids_[mir->meta.sfield_lowering_info];
+  }
+
   /*
    * Type inference handling helpers.  Because Dalvik's bytecode is not fully typed,
    * we have to do some work to figure out the sreg type.  For some operations it is
@@ -1074,6 +1125,7 @@
   std::string GetSSANameWithConst(int ssa_reg, bool singles_only);
   void GetBlockName(BasicBlock* bb, char* name);
   const char* GetShortyFromTargetIdx(int);
+  const char* GetShortyFromMethodReference(const MethodReference& target_method);
   void DumpMIRGraph();
   CallInfo* NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range);
   BasicBlock* NewMemBB(BBType block_type, int block_id);
@@ -1126,7 +1178,7 @@
    * @brief Count the uses in the BasicBlock
    * @param bb the BasicBlock
    */
-  void CountUses(struct BasicBlock* bb);
+  void CountUses(BasicBlock* bb);
 
   static uint64_t GetDataFlowAttributes(Instruction::Code opcode);
   static uint64_t GetDataFlowAttributes(MIR* mir);
@@ -1142,7 +1194,6 @@
   void AllocateSSAUseData(MIR *mir, int num_uses);
   void AllocateSSADefData(MIR *mir, int num_defs);
   void CalculateBasicBlockInformation();
-  void InitializeBasicBlockData();
   void ComputeDFSOrders();
   void ComputeDefBlockMatrix();
   void ComputeDominators();
@@ -1151,6 +1202,22 @@
   void InsertPhiNodes();
   void DoDFSPreOrderSSARename(BasicBlock* block);
 
+  bool DfsOrdersUpToDate() const {
+    return dfs_orders_up_to_date_;
+  }
+
+  bool DominationUpToDate() const {
+    return domination_up_to_date_;
+  }
+
+  bool MirSsaRepUpToDate() const {
+    return mir_ssa_rep_up_to_date_;
+  }
+
+  bool TopologicalOrderUpToDate() const {
+    return topological_order_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.
@@ -1166,20 +1233,6 @@
   void HandleSSADef(int* defs, int dalvik_reg, int reg_index);
   bool InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed);
 
-  // Used for removing redudant suspend tests
-  void AppendGenSuspendTestList(BasicBlock* bb) {
-    if (gen_suspend_test_list_.size() == 0 ||
-        gen_suspend_test_list_.back() != bb) {
-      gen_suspend_test_list_.push_back(bb);
-    }
-  }
-
-  /* This is used to check if there is already a method call dominating the
-   * source basic block of a backedge and being dominated by the target basic
-   * block of the backedge.
-   */
-  bool HasSuspendTestBetween(BasicBlock* source, BasicBlockId target_id);
-
  protected:
   int FindCommonParent(int block1, int block2);
   void ComputeSuccLineIn(ArenaBitVector* dest, const ArenaBitVector* src1,
@@ -1195,8 +1248,7 @@
   bool ContentIsInsn(const uint16_t* code_ptr);
   BasicBlock* SplitBlock(DexOffset code_offset, BasicBlock* orig_block,
                          BasicBlock** immed_pred_block_p);
-  BasicBlock* FindBlock(DexOffset code_offset, bool split, bool create,
-                        BasicBlock** immed_pred_block_p);
+  BasicBlock* FindBlock(DexOffset code_offset, bool create, BasicBlock** immed_pred_block_p);
   void ProcessTryCatchBlocks();
   bool IsBadMonitorExitCatch(NarrowDexOffset monitor_exit_offset, NarrowDexOffset catch_offset);
   BasicBlock* ProcessCanBranch(BasicBlock* cur_block, MIR* insn, DexOffset cur_offset, int width,
@@ -1220,7 +1272,35 @@
   void ComputeDomPostOrderTraversal(BasicBlock* bb);
   int GetSSAUseCount(int s_reg);
   bool BasicBlockOpt(BasicBlock* bb);
-  bool BuildExtendedBBList(struct BasicBlock* bb);
+  void MultiplyAddOpt(BasicBlock* bb);
+
+  /**
+   * @brief Check whether the given MIR is possible to throw an exception.
+   * @param mir The mir to check.
+   * @return Returns 'true' if the given MIR might throw an exception.
+   */
+  bool CanThrow(MIR* mir);
+  /**
+   * @brief Combine multiply and add/sub MIRs into corresponding extended MAC MIR.
+   * @param mul_mir The multiply MIR to be combined.
+   * @param add_mir The add/sub MIR to be combined.
+   * @param mul_is_first_addend 'true' if multiply product is the first addend of add operation.
+   * @param is_wide 'true' if the operations are long type.
+   * @param is_sub 'true' if it is a multiply-subtract operation.
+   */
+  void CombineMultiplyAdd(MIR* mul_mir, MIR* add_mir, bool mul_is_first_addend,
+                          bool is_wide, bool is_sub);
+  /*
+   * @brief Check whether the first MIR anti-depends on the second MIR.
+   * @details To check whether one of first MIR's uses of vregs is redefined by the second MIR,
+   * i.e. there is a write-after-read dependency.
+   * @param first The first MIR.
+   * @param second The second MIR.
+   * @param Returns true if there is a write-after-read dependency.
+   */
+  bool HasAntiDependency(MIR* first, MIR* second);
+
+  bool BuildExtendedBBList(class BasicBlock* bb);
   bool FillDefBlockMatrix(BasicBlock* bb);
   void InitializeDominationInfo(BasicBlock* bb);
   bool ComputeblockIDom(BasicBlock* bb);
@@ -1247,31 +1327,68 @@
   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_;
+  bool domination_up_to_date_;
+  bool mir_ssa_rep_up_to_date_;
+  bool topological_order_up_to_date_;
   ArenaVector<BasicBlockId> dfs_order_;
   ArenaVector<BasicBlockId> dfs_post_order_;
   ArenaVector<BasicBlockId> dom_post_order_traversal_;
   ArenaVector<BasicBlockId> topological_order_;
   // Indexes in topological_order_ need to be only as big as the BasicBlockId.
-  COMPILE_ASSERT(sizeof(BasicBlockId) == sizeof(uint16_t), assuming_16_bit_BasicBlockId);
+  static_assert(sizeof(BasicBlockId) == sizeof(uint16_t), "Assuming 16 bit BasicBlockId");
   // For each loop head, remember the past-the-end index of the end of the loop. 0 if not loop head.
   ArenaVector<uint16_t> topological_order_loop_ends_;
   // Map BB ids to topological_order_ indexes. 0xffff if not included (hidden or null block).
   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_;
-  ArenaBitVector** def_block_matrix_;    // original num registers x num_blocks.
   std::unique_ptr<ScopedArenaAllocator> temp_scoped_alloc_;
-  uint16_t* temp_insn_data_;
-  uint32_t temp_bit_vector_size_;
-  ArenaBitVector* temp_bit_vector_;
-  std::unique_ptr<GlobalValueNumbering> temp_gvn_;
+  // Union of temporaries used by different passes.
+  union {
+    // Class init check elimination.
+    struct {
+      size_t num_class_bits;  // 2 bits per class: class initialized and class in dex cache.
+      ArenaBitVector* work_classes_to_check;
+      ArenaBitVector** ending_classes_to_check_matrix;  // num_blocks_ x num_class_bits.
+      uint16_t* indexes;
+    } cice;
+    // Null check elimination.
+    struct {
+      size_t num_vregs;
+      ArenaBitVector* work_vregs_to_check;
+      ArenaBitVector** ending_vregs_to_check_matrix;  // num_blocks_ x num_vregs.
+    } nce;
+    // Special method inlining.
+    struct {
+      size_t num_indexes;
+      ArenaBitVector* processed_indexes;
+      uint16_t* lowering_infos;
+    } smi;
+    // SSA transformation.
+    struct {
+      size_t num_vregs;
+      ArenaBitVector* work_live_vregs;
+      ArenaBitVector** def_block_matrix;  // num_vregs x num_blocks_.
+    } ssa;
+    // Global value numbering.
+    struct {
+      GlobalValueNumbering* gvn;
+      uint16_t* ifield_ids_;  // Part of GVN/LVN but cached here for LVN to avoid recalculation.
+      uint16_t* sfield_ids_;  // Ditto.
+    } gvn;
+    // Suspend check elimination.
+    struct {
+      DexFileMethodInliner* inliner;
+    } sce;
+  } temp_;
   static const int kInvalidEntry = -1;
   ArenaVector<BasicBlock*> block_list_;
   ArenaBitVector* try_block_addr_;
   BasicBlock* entry_block_;
   BasicBlock* exit_block_;
-  unsigned int num_blocks_;
   const DexFile::CodeItem* current_code_item_;
   ArenaVector<uint16_t> dex_pc_to_block_map_;    // FindBlock lookup cache.
   ArenaVector<DexCompilationUnit*> m_units_;     // List of methods included in this graph
@@ -1286,7 +1403,7 @@
   int method_sreg_;
   unsigned int attributes_;
   Checkstats* checkstats_;
-  ArenaAllocator* arena_;
+  ArenaAllocator* const arena_;
   int backward_branches_;
   int forward_branches_;
   size_t num_non_special_compiler_temps_;  // Keeps track of allocated non-special compiler temps. These are VRs that are in compiler temp region on stack.
@@ -1300,10 +1417,20 @@
   ArenaVector<MirIFieldLoweringInfo> ifield_lowering_infos_;
   ArenaVector<MirSFieldLoweringInfo> sfield_lowering_infos_;
   ArenaVector<MirMethodLoweringInfo> method_lowering_infos_;
-  static const uint64_t oat_data_flow_attributes_[kMirOpLast];
-  ArenaVector<BasicBlock*> gen_suspend_test_list_;  // List of blocks containing suspend tests
 
+  // In the suspend check elimination pass we determine for each basic block and enclosing
+  // loop whether there's guaranteed to be a suspend check on the path from the loop head
+  // to this block. If so, we can eliminate the back-edge suspend check.
+  // The bb->id is index into suspend_checks_in_loops_ and the loop head's depth is bit index
+  // in a suspend_checks_in_loops_[bb->id].
+  uint32_t* suspend_checks_in_loops_;
+
+  static const uint64_t oat_data_flow_attributes_[kMirOpLast];
+
+  friend class MirOptimizationTest;
   friend class ClassInitCheckEliminationTest;
+  friend class SuspendCheckEliminationTest;
+  friend class NullCheckEliminationTest;
   friend class GlobalValueNumberingTest;
   friend class LocalValueNumberingTest;
   friend class TopologicalSortOrderTest;
diff --git a/compiler/dex/mir_graph_test.cc b/compiler/dex/mir_graph_test.cc
index a96cd84..8a7e71f 100644
--- a/compiler/dex/mir_graph_test.cc
+++ b/compiler/dex/mir_graph_test.cc
@@ -89,7 +89,6 @@
             cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
       }
     }
-    cu_.mir_graph->num_blocks_ = count;
     ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
     cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
     ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
diff --git a/compiler/dex/mir_method_info.cc b/compiler/dex/mir_method_info.cc
index cc2bd95..b234950 100644
--- a/compiler/dex/mir_method_info.cc
+++ b/compiler/dex/mir_method_info.cc
@@ -76,14 +76,16 @@
     int fast_path_flags = compiler_driver->IsFastInvoke(
         soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method, &invoke_type,
         &target_method, devirt_target, &it->direct_code_, &it->direct_method_);
-    bool needs_clinit =
-        compiler_driver->NeedsClassInitialization(referrer_class.Get(), resolved_method);
+    bool is_referrers_class = (referrer_class.Get() == resolved_method->GetDeclaringClass());
+    bool is_class_initialized =
+        compiler_driver->IsMethodsClassInitialized(referrer_class.Get(), resolved_method);
     uint16_t other_flags = it->flags_ &
-        ~(kFlagFastPath | kFlagNeedsClassInitialization | (kInvokeTypeMask << kBitSharpTypeBegin));
+        ~(kFlagFastPath | kFlagClassIsInitialized | (kInvokeTypeMask << kBitSharpTypeBegin));
     it->flags_ = other_flags |
         (fast_path_flags != 0 ? kFlagFastPath : 0u) |
         (static_cast<uint16_t>(invoke_type) << kBitSharpTypeBegin) |
-        (needs_clinit ? kFlagNeedsClassInitialization : 0u);
+        (is_referrers_class ? kFlagIsReferrersClass : 0u) |
+        (is_class_initialized ? kFlagClassIsInitialized : 0u);
     it->target_dex_file_ = target_method.dex_file;
     it->target_method_idx_ = target_method.dex_method_index;
     it->stats_flags_ = fast_path_flags;
diff --git a/compiler/dex/mir_method_info.h b/compiler/dex/mir_method_info.h
index efe92f3..08fb103 100644
--- a/compiler/dex/mir_method_info.h
+++ b/compiler/dex/mir_method_info.h
@@ -60,7 +60,7 @@
     kBitIsStatic = 0,
     kMethodInfoBitEnd
   };
-  COMPILE_ASSERT(kMethodInfoBitEnd <= 16, too_many_flags);
+  static_assert(kMethodInfoBitEnd <= 16, "Too many flags");
   static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic;
 
   MirMethodInfo(uint16_t method_idx, uint16_t flags)
@@ -123,8 +123,12 @@
     return (flags_ & kFlagFastPath) != 0u;
   }
 
-  bool NeedsClassInitialization() const {
-    return (flags_ & kFlagNeedsClassInitialization) != 0u;
+  bool IsReferrersClass() const {
+    return (flags_ & kFlagIsReferrersClass) != 0;
+  }
+
+  bool IsClassInitialized() const {
+    return (flags_ & kFlagClassIsInitialized) != 0u;
   }
 
   InvokeType GetInvokeType() const {
@@ -162,17 +166,19 @@
     kBitInvokeTypeEnd = kBitInvokeTypeBegin + 3,  // 3 bits for invoke type.
     kBitSharpTypeBegin,
     kBitSharpTypeEnd = kBitSharpTypeBegin + 3,  // 3 bits for sharp type.
-    kBitNeedsClassInitialization = kBitSharpTypeEnd,
-    kMethodLoweringInfoEnd
+    kBitIsReferrersClass = kBitSharpTypeEnd,
+    kBitClassIsInitialized,
+    kMethodLoweringInfoBitEnd
   };
-  COMPILE_ASSERT(kMethodLoweringInfoEnd <= 16, too_many_flags);
+  static_assert(kMethodLoweringInfoBitEnd <= 16, "Too many flags");
   static constexpr uint16_t kFlagFastPath = 1u << kBitFastPath;
-  static constexpr uint16_t kFlagNeedsClassInitialization = 1u << kBitNeedsClassInitialization;
+  static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass;
+  static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized;
   static constexpr uint16_t kInvokeTypeMask = 7u;
-  COMPILE_ASSERT((1u << (kBitInvokeTypeEnd - kBitInvokeTypeBegin)) - 1u == kInvokeTypeMask,
-                 assert_invoke_type_bits_ok);
-  COMPILE_ASSERT((1u << (kBitSharpTypeEnd - kBitSharpTypeBegin)) - 1u == kInvokeTypeMask,
-                 assert_sharp_type_bits_ok);
+  static_assert((1u << (kBitInvokeTypeEnd - kBitInvokeTypeBegin)) - 1u == kInvokeTypeMask,
+                "assert invoke type bits failed");
+  static_assert((1u << (kBitSharpTypeEnd - kBitSharpTypeBegin)) - 1u == kInvokeTypeMask,
+                "assert sharp type bits failed");
 
   uintptr_t direct_code_;
   uintptr_t direct_method_;
@@ -185,7 +191,7 @@
   uint16_t vtable_idx_;
   int stats_flags_;
 
-  friend class ClassInitCheckEliminationTest;
+  friend class MirOptimizationTest;
 };
 
 }  // namespace art
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index dac71f6..ebbd28f 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -16,12 +16,12 @@
 
 #include "base/bit_vector-inl.h"
 #include "compiler_internals.h"
+#include "dataflow_iterator-inl.h"
 #include "global_value_numbering.h"
 #include "local_value_numbering.h"
-#include "dataflow_iterator-inl.h"
-#include "dex/global_value_numbering.h"
-#include "dex/quick/dex_file_method_inliner.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "mir_field_info.h"
+#include "quick/dex_file_method_inliner.h"
+#include "quick/dex_file_to_method_inliner_map.h"
 #include "stack.h"
 #include "utils/scoped_arena_containers.h"
 
@@ -35,6 +35,7 @@
 void MIRGraph::SetConstant(int32_t ssa_reg, int32_t value) {
   is_constant_v_->SetBit(ssa_reg);
   constant_values_[ssa_reg] = value;
+  reg_location_[ssa_reg].is_const = true;
 }
 
 void MIRGraph::SetConstantWide(int32_t ssa_reg, int64_t value) {
@@ -42,6 +43,8 @@
   is_constant_v_->SetBit(ssa_reg + 1);
   constant_values_[ssa_reg] = Low32Bits(value);
   constant_values_[ssa_reg + 1] = High32Bits(value);
+  reg_location_[ssa_reg].is_const = true;
+  reg_location_[ssa_reg + 1].is_const = true;
 }
 
 void MIRGraph::DoConstantPropagation(BasicBlock* bb) {
@@ -186,6 +189,10 @@
 }
 
 static SelectInstructionKind SelectKind(MIR* mir) {
+  // Work with the case when mir is nullptr.
+  if (mir == nullptr) {
+    return kSelectNone;
+  }
   switch (mir->dalvikInsn.opcode) {
     case Instruction::MOVE:
     case Instruction::MOVE_OBJECT:
@@ -211,23 +218,19 @@
     kCondEq, kCondNe, kCondLt, kCondGe, kCondGt, kCondLe
 };
 
-COMPILE_ASSERT(arraysize(kIfCcZConditionCodes) == Instruction::IF_LEZ - Instruction::IF_EQZ + 1,
-               if_ccz_ccodes_size1);
-
-static constexpr bool IsInstructionIfCcZ(Instruction::Code opcode) {
-  return Instruction::IF_EQZ <= opcode && opcode <= Instruction::IF_LEZ;
-}
+static_assert(arraysize(kIfCcZConditionCodes) == Instruction::IF_LEZ - Instruction::IF_EQZ + 1,
+              "if_ccz_ccodes_size1");
 
 static constexpr ConditionCode ConditionCodeForIfCcZ(Instruction::Code opcode) {
   return kIfCcZConditionCodes[opcode - Instruction::IF_EQZ];
 }
 
-COMPILE_ASSERT(ConditionCodeForIfCcZ(Instruction::IF_EQZ) == kCondEq, check_if_eqz_ccode);
-COMPILE_ASSERT(ConditionCodeForIfCcZ(Instruction::IF_NEZ) == kCondNe, check_if_nez_ccode);
-COMPILE_ASSERT(ConditionCodeForIfCcZ(Instruction::IF_LTZ) == kCondLt, check_if_ltz_ccode);
-COMPILE_ASSERT(ConditionCodeForIfCcZ(Instruction::IF_GEZ) == kCondGe, check_if_gez_ccode);
-COMPILE_ASSERT(ConditionCodeForIfCcZ(Instruction::IF_GTZ) == kCondGt, check_if_gtz_ccode);
-COMPILE_ASSERT(ConditionCodeForIfCcZ(Instruction::IF_LEZ) == kCondLe, check_if_lez_ccode);
+static_assert(ConditionCodeForIfCcZ(Instruction::IF_EQZ) == kCondEq, "if_eqz ccode");
+static_assert(ConditionCodeForIfCcZ(Instruction::IF_NEZ) == kCondNe, "if_nez ccode");
+static_assert(ConditionCodeForIfCcZ(Instruction::IF_LTZ) == kCondLt, "if_ltz ccode");
+static_assert(ConditionCodeForIfCcZ(Instruction::IF_GEZ) == kCondGe, "if_gez ccode");
+static_assert(ConditionCodeForIfCcZ(Instruction::IF_GTZ) == kCondGt, "if_gtz ccode");
+static_assert(ConditionCodeForIfCcZ(Instruction::IF_LEZ) == kCondLe, "if_lez ccode");
 
 int MIRGraph::GetSSAUseCount(int s_reg) {
   DCHECK_LT(static_cast<size_t>(s_reg), ssa_subscripts_.size());
@@ -399,19 +402,45 @@
   return compiler_temp;
 }
 
+static bool EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) {
+  bool is_taken;
+  switch (opcode) {
+    case Instruction::IF_EQ: is_taken = (src1 == src2); break;
+    case Instruction::IF_NE: is_taken = (src1 != src2); break;
+    case Instruction::IF_LT: is_taken = (src1 < src2); break;
+    case Instruction::IF_GE: is_taken = (src1 >= src2); break;
+    case Instruction::IF_GT: is_taken = (src1 > src2); break;
+    case Instruction::IF_LE: is_taken = (src1 <= src2); break;
+    case Instruction::IF_EQZ: is_taken = (src1 == 0); break;
+    case Instruction::IF_NEZ: is_taken = (src1 != 0); break;
+    case Instruction::IF_LTZ: is_taken = (src1 < 0); break;
+    case Instruction::IF_GEZ: is_taken = (src1 >= 0); break;
+    case Instruction::IF_GTZ: is_taken = (src1 > 0); break;
+    case Instruction::IF_LEZ: is_taken = (src1 <= 0); break;
+    default:
+      LOG(FATAL) << "Unexpected opcode " << opcode;
+      UNREACHABLE();
+  }
+  return is_taken;
+}
+
 /* Do some MIR-level extended basic block optimizations */
 bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
   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;
+  // Currently multiply-accumulate backend supports are only available on arm32 and arm64.
+  if (cu_->instruction_set == kArm64 || cu_->instruction_set == kThumb2) {
+    MultiplyAddOpt(bb);
+  }
+  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()));
   }
@@ -424,6 +453,48 @@
       // Look for interesting opcodes, skip otherwise
       Instruction::Code opcode = mir->dalvikInsn.opcode;
       switch (opcode) {
+        case Instruction::IF_EQ:
+        case Instruction::IF_NE:
+        case Instruction::IF_LT:
+        case Instruction::IF_GE:
+        case Instruction::IF_GT:
+        case Instruction::IF_LE:
+          if (!IsConst(mir->ssa_rep->uses[1])) {
+            break;
+          }
+          FALLTHROUGH_INTENDED;
+        case Instruction::IF_EQZ:
+        case Instruction::IF_NEZ:
+        case Instruction::IF_LTZ:
+        case Instruction::IF_GEZ:
+        case Instruction::IF_GTZ:
+        case Instruction::IF_LEZ:
+          // Result known at compile time?
+          if (IsConst(mir->ssa_rep->uses[0])) {
+            int32_t rhs = (mir->ssa_rep->num_uses == 2) ? ConstantValue(mir->ssa_rep->uses[1]) : 0;
+            bool is_taken = EvaluateBranch(opcode, ConstantValue(mir->ssa_rep->uses[0]), rhs);
+            BasicBlockId edge_to_kill = is_taken ? bb->fall_through : bb->taken;
+            if (is_taken) {
+              // Replace with GOTO.
+              bb->fall_through = NullBasicBlockId;
+              mir->dalvikInsn.opcode = Instruction::GOTO;
+              mir->dalvikInsn.vA =
+                  IsInstructionIfCc(opcode) ? mir->dalvikInsn.vC : mir->dalvikInsn.vB;
+            } else {
+              // Make NOP.
+              bb->taken = NullBasicBlockId;
+              mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+            }
+            mir->ssa_rep->num_uses = 0;
+            BasicBlock* successor_to_unlink = GetBasicBlock(edge_to_kill);
+            successor_to_unlink->ErasePredecessor(bb->id);
+            // We have changed the graph structure.
+            dfs_orders_up_to_date_ = false;
+            domination_up_to_date_ = false;
+            topological_order_up_to_date_ = false;
+            // Keep MIR SSA rep, the worst that can happen is a Phi with just 1 input.
+          }
+          break;
         case Instruction::CMPL_FLOAT:
         case Instruction::CMPL_DOUBLE:
         case Instruction::CMPG_FLOAT:
@@ -464,6 +535,9 @@
                 default: LOG(ERROR) << "Unexpected opcode: " << opcode;
               }
               mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+              // Clear use count of temp VR.
+              use_counts_[mir->ssa_rep->defs[0]] = 0;
+              raw_use_counts_[mir->ssa_rep->defs[0]] = 0;
               // Copy the SSA information that is relevant.
               mir_next->ssa_rep->num_uses = mir->ssa_rep->num_uses;
               mir_next->ssa_rep->uses = mir->ssa_rep->uses;
@@ -477,40 +551,13 @@
             }
           }
           break;
-        case Instruction::GOTO:
-        case Instruction::GOTO_16:
-        case Instruction::GOTO_32:
-        case Instruction::IF_EQ:
-        case Instruction::IF_NE:
-        case Instruction::IF_LT:
-        case Instruction::IF_GE:
-        case Instruction::IF_GT:
-        case Instruction::IF_LE:
-        case Instruction::IF_EQZ:
-        case Instruction::IF_NEZ:
-        case Instruction::IF_LTZ:
-        case Instruction::IF_GEZ:
-        case Instruction::IF_GTZ:
-        case Instruction::IF_LEZ:
-          // If we've got a backwards branch to return, no need to suspend check.
-          if ((IsBackedge(bb, bb->taken) && GetBasicBlock(bb->taken)->dominates_return) ||
-              (IsBackedge(bb, bb->fall_through) &&
-                          GetBasicBlock(bb->fall_through)->dominates_return)) {
-            mir->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK;
-            if (cu_->verbose) {
-              LOG(INFO) << "Suppressed suspend check on branch to return at 0x" << std::hex
-                        << mir->offset;
-            }
-          }
-          break;
         default:
           break;
       }
       // Is this the select pattern?
       // TODO: flesh out support for Mips.  NOTE: llvm's select op doesn't quite work here.
       // TUNING: expand to support IF_xx compare & branches
-      if (!cu_->compiler->IsPortable() &&
-          (cu_->instruction_set == kArm64 || cu_->instruction_set == kThumb2 ||
+      if ((cu_->instruction_set == kArm64 || cu_->instruction_set == kThumb2 ||
            cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) &&
           IsInstructionIfCcZ(mir->dalvikInsn.opcode)) {
         BasicBlock* ft = GetBasicBlock(bb->fall_through);
@@ -531,12 +578,8 @@
         if ((tk_ft == NULL) && (ft_tk == NULL) && (tk_tk == ft_ft) &&
             (Predecessors(tk) == 1) && (Predecessors(ft) == 1)) {
           /*
-           * Okay - we have the basic diamond shape.  At the very least, we can eliminate the
-           * suspend check on the taken-taken branch back to the join point.
+           * Okay - we have the basic diamond shape.
            */
-          if (SelectKind(tk->last_mir_insn) == kSelectGoto) {
-              tk->last_mir_insn->optimization_flags |= (MIR_IGNORE_SUSPEND_CHECK);
-          }
 
           // TODO: Add logic for LONG.
           // Are the block bodies something we can handle?
@@ -611,36 +654,36 @@
                * Phi node only contains our two cases as input, we will use the result
                * SSA name of the Phi node as our select result and delete the Phi.  If
                * the Phi node has more than two operands, we will arbitrarily use the SSA
-               * name of the "true" path, delete the SSA name of the "false" path from the
+               * name of the "false" path, delete the SSA name of the "true" path from the
                * Phi node (and fix up the incoming arc list).
                */
               if (phi->ssa_rep->num_uses == 2) {
                 mir->ssa_rep->defs[0] = phi->ssa_rep->defs[0];
-                phi->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+                // Rather than changing the Phi to kMirOpNop, remove it completely.
+                // This avoids leaving other Phis after kMirOpNop (i.e. a non-Phi) insn.
+                tk_tk->RemoveMIR(phi);
+                int dead_false_def = if_false->ssa_rep->defs[0];
+                raw_use_counts_[dead_false_def] = use_counts_[dead_false_def] = 0;
               } else {
-                int dead_def = if_false->ssa_rep->defs[0];
-                int live_def = if_true->ssa_rep->defs[0];
+                int live_def = if_false->ssa_rep->defs[0];
                 mir->ssa_rep->defs[0] = live_def;
-                BasicBlockId* incoming = phi->meta.phi_incoming;
-                for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
-                  if (phi->ssa_rep->uses[i] == live_def) {
-                    incoming[i] = bb->id;
-                  }
-                }
-                for (int i = 0; i < phi->ssa_rep->num_uses; i++) {
-                  if (phi->ssa_rep->uses[i] == dead_def) {
-                    int last_slot = phi->ssa_rep->num_uses - 1;
-                    phi->ssa_rep->uses[i] = phi->ssa_rep->uses[last_slot];
-                    incoming[i] = incoming[last_slot];
-                  }
-                }
               }
-              phi->ssa_rep->num_uses--;
-              bb->taken = NullBasicBlockId;
-              tk->block_type = kDead;
-              for (MIR* tmir = ft->first_mir_insn; tmir != NULL; tmir = tmir->next) {
-                tmir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
-              }
+              int dead_true_def = if_true->ssa_rep->defs[0];
+              raw_use_counts_[dead_true_def] = use_counts_[dead_true_def] = 0;
+              // We want to remove ft and tk and link bb directly to ft_ft. First, we need
+              // to update all Phi inputs correctly with UpdatePredecessor(ft->id, bb->id)
+              // since the live_def above comes from ft->first_mir_insn (if_false).
+              DCHECK(if_false == ft->first_mir_insn);
+              ft_ft->UpdatePredecessor(ft->id, bb->id);
+              // Correct the rest of the links between bb, ft and ft_ft.
+              ft->ErasePredecessor(bb->id);
+              ft->fall_through = NullBasicBlockId;
+              bb->fall_through = ft_ft->id;
+              // Now we can kill tk and ft.
+              tk->Kill(this);
+              ft->Kill(this);
+              // NOTE: DFS order, domination info and topological order are still usable
+              // despite the newly dead blocks.
             }
           }
         }
@@ -656,7 +699,7 @@
 }
 
 /* Collect stats on number of checks removed */
-void MIRGraph::CountChecks(struct BasicBlock* bb) {
+void MIRGraph::CountChecks(class BasicBlock* bb) {
   if (bb->data_flow_info != NULL) {
     for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
       if (mir->ssa_rep == NULL) {
@@ -737,62 +780,72 @@
       break;
     }
     walker = prev;
-
-    if (walker->visited) {
-      break;
-    }
   }
   return false;
 }
 
 /* Combine any basic blocks terminated by instructions that we now know can't throw */
-void MIRGraph::CombineBlocks(struct BasicBlock* bb) {
+void MIRGraph::CombineBlocks(class 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);
+
+    // Get the paired insn and check if it can still throw.
+    MIR* throw_insn = mir->meta.throw_insn;
+    if (CanThrow(throw_insn)) {
       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);
+
+    // Now move instructions from bb_next to bb. Start off with doing a sanity check
+    // that kMirOpCheck's throw instruction is first one in the bb_next.
     DCHECK_EQ(bb_next->first_mir_insn, throw_insn);
-    *bb->last_mir_insn = *throw_insn;
+    // Now move all instructions (throw instruction to last one) from bb_next to bb.
+    MIR* last_to_move = bb_next->last_mir_insn;
+    bb_next->RemoveMIRList(throw_insn, last_to_move);
+    bb->InsertMIRListAfter(bb->last_mir_insn, throw_insn, last_to_move);
+    // The kMirOpCheck instruction is not needed anymore.
+    mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+    bb->RemoveMIR(mir);
+
+    // 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);
+        }
+      }
+    }
     // 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,
@@ -801,144 +854,160 @@
     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, domination and topological order are not up to date anymore.
+    dfs_orders_up_to_date_ = false;
+    domination_up_to_date_ = false;
+    topological_order_up_to_date_ = false;
 
     // Now, loop back and see if we can keep going
   }
 }
 
-void MIRGraph::EliminateNullChecksAndInferTypesStart() {
-  if ((cu_->disable_opt & (1 << kNullCheckElimination)) == 0) {
-    if (kIsDebugBuild) {
-      AllNodesIterator iter(this);
-      for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
-        CHECK(bb->data_flow_info == nullptr || bb->data_flow_info->ending_check_v == nullptr);
-      }
-    }
-
-    DCHECK(temp_scoped_alloc_.get() == nullptr);
-    temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
-    temp_bit_vector_size_ = GetNumSSARegs();
-    temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
-        temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapTempSSARegisterV);
+bool MIRGraph::EliminateNullChecksGate() {
+  if ((cu_->disable_opt & (1 << kNullCheckElimination)) != 0 ||
+      (merged_df_flags_ & DF_HAS_NULL_CHKS) == 0) {
+    return false;
   }
+
+  DCHECK(temp_scoped_alloc_.get() == nullptr);
+  temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
+  temp_.nce.num_vregs = GetNumOfCodeAndTempVRs();
+  temp_.nce.work_vregs_to_check = new (temp_scoped_alloc_.get()) ArenaBitVector(
+      temp_scoped_alloc_.get(), temp_.nce.num_vregs, false, kBitMapNullCheck);
+  temp_.nce.ending_vregs_to_check_matrix = static_cast<ArenaBitVector**>(
+      temp_scoped_alloc_->Alloc(sizeof(ArenaBitVector*) * GetNumBlocks(), kArenaAllocMisc));
+  std::fill_n(temp_.nce.ending_vregs_to_check_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;
 }
 
 /*
- * Eliminate unnecessary null checks for a basic block.   Also, while we're doing
- * an iterative walk go ahead and perform type and size inference.
+ * Eliminate unnecessary null checks for a basic block.
  */
-bool MIRGraph::EliminateNullChecksAndInferTypes(BasicBlock* bb) {
-  if (bb->data_flow_info == NULL) return false;
-  bool infer_changed = false;
-  bool do_nce = ((cu_->disable_opt & (1 << kNullCheckElimination)) == 0);
+bool MIRGraph::EliminateNullChecks(BasicBlock* bb) {
+  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_;
-  if (do_nce) {
-    /*
-     * Set initial state. Catch blocks don't need any special treatment.
-     */
-    if (bb->block_type == kEntryBlock) {
-      ssa_regs_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);
+  ArenaBitVector* vregs_to_check = temp_.nce.work_vregs_to_check;
+  /*
+   * Set initial state. Catch blocks don't need any special treatment.
+   */
+  if (bb->block_type == kEntryBlock) {
+    vregs_to_check->ClearAllBits();
+    // Assume all ins are objects.
+    for (uint16_t in_reg = GetFirstInVR();
+         in_reg < GetNumOfCodeVRs(); in_reg++) {
+      vregs_to_check->SetBit(in_reg);
+    }
+    if ((cu_->access_flags & kAccStatic) == 0) {
+      // If non-static method, mark "this" as non-null.
+      int this_reg = GetFirstInVR();
+      vregs_to_check->ClearBit(this_reg);
+    }
+  } 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_.nce.ending_vregs_to_check_matrix[pred_id] == nullptr) {
+        continue;
       }
-      if ((cu_->access_flags & kAccStatic) == 0) {
-        // If non-static method, mark "this" as non-null
-        int this_reg = GetFirstInVR();
-        ssa_regs_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(pred_bb->data_flow_info->ending_check_v != nullptr);
-      ssa_regs_to_check->Copy(pred_bb->data_flow_info->ending_check_v);
+      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) {
-            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]);
+          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 (pred_bb->data_flow_info->ending_check_v == nullptr) {
-          continue;
-        }
-        if (!copied_first) {
-          copied_first = true;
-          ssa_regs_to_check->Copy(pred_bb->data_flow_info->ending_check_v);
-        } else {
-          ssa_regs_to_check->Union(pred_bb->data_flow_info->ending_check_v);
-        }
+      if (!copied_first) {
+        copied_first = true;
+        vregs_to_check->Copy(temp_.nce.ending_vregs_to_check_matrix[pred_id]);
+      } else {
+        vregs_to_check->Union(temp_.nce.ending_vregs_to_check_matrix[pred_id]);
       }
-      DCHECK(copied_first);  // At least one predecessor must have been processed before this bb.
+      if (null_check_insn != nullptr) {
+        vregs_to_check->ClearBit(null_check_insn->dalvikInsn.vA);
+      }
     }
-    // At this point, ssa_regs_to_check shows which sregs have an object definition with
-    // no intervening uses.
+    DCHECK(copied_first);  // At least one predecessor must have been processed before this bb.
   }
+  // 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);
 
-    // Propagate type info.
-    infer_changed = InferTypeAndSize(bb, mir, infer_changed);
-    if (!do_nce) {
+    if ((df_attributes & DF_NULL_TRANSFER_N) != 0u) {
+      // The algorithm was written in a phi agnostic way.
       continue;
     }
 
-    uint64_t df_attributes = GetDataFlowAttributes(mir);
-
     // 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.
-        mir->optimization_flags &= ~MIR_IGNORE_NULL_CHECK;
-        // 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);
       }
     }
 
@@ -952,123 +1021,117 @@
      * 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);
       }
     }
   }
 
   // Did anything change?
   bool nce_changed = false;
-  if (do_nce) {
-    if (bb->data_flow_info->ending_check_v == nullptr) {
-      DCHECK(temp_scoped_alloc_.get() != nullptr);
-      bb->data_flow_info->ending_check_v = new (temp_scoped_alloc_.get()) ArenaBitVector(
-          temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapNullCheck);
-      nce_changed = ssa_regs_to_check->GetHighestBitSet() != -1;
-      bb->data_flow_info->ending_check_v->Copy(ssa_regs_to_check);
-    } else if (!ssa_regs_to_check->SameBitsSet(bb->data_flow_info->ending_check_v)) {
-      nce_changed = true;
-      bb->data_flow_info->ending_check_v->Copy(ssa_regs_to_check);
-    }
+  ArenaBitVector* old_ending_ssa_regs_to_check = temp_.nce.ending_vregs_to_check_matrix[bb->id];
+  if (old_ending_ssa_regs_to_check == nullptr) {
+    DCHECK(temp_scoped_alloc_.get() != nullptr);
+    nce_changed = vregs_to_check->GetHighestBitSet() != -1;
+    temp_.nce.ending_vregs_to_check_matrix[bb->id] = vregs_to_check;
+    // Create a new vregs_to_check for next BB.
+    temp_.nce.work_vregs_to_check = new (temp_scoped_alloc_.get()) ArenaBitVector(
+        temp_scoped_alloc_.get(), temp_.nce.num_vregs, false, kBitMapNullCheck);
+  } else if (!vregs_to_check->SameBitsSet(old_ending_ssa_regs_to_check)) {
+    nce_changed = true;
+    temp_.nce.ending_vregs_to_check_matrix[bb->id] = vregs_to_check;
+    temp_.nce.work_vregs_to_check = old_ending_ssa_regs_to_check;  // Reuse for next BB.
   }
-  return infer_changed | nce_changed;
+  return nce_changed;
 }
 
-void MIRGraph::EliminateNullChecksAndInferTypesEnd() {
-  if ((cu_->disable_opt & (1 << kNullCheckElimination)) == 0) {
-    // Clean up temporaries.
-    temp_bit_vector_size_ = 0u;
-    temp_bit_vector_ = nullptr;
-    AllNodesIterator iter(this);
-    for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
-      if (bb->data_flow_info != nullptr) {
-        bb->data_flow_info->ending_check_v = nullptr;
-      }
+void MIRGraph::EliminateNullChecksEnd() {
+  // Clean up temporaries.
+  temp_.nce.num_vregs = 0u;
+  temp_.nce.work_vregs_to_check = nullptr;
+  temp_.nce.ending_vregs_to_check_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;
+      static_assert(kMarkToIgnoreNullCheckShift > 0, "Not a valid right-shift");
+      uint16_t mirMarkAdjustedToIgnoreNullCheck =
+          (mir->optimization_flags & MIR_MARK) >> kMarkToIgnoreNullCheckShift;
+      mir->optimization_flags |= mirMarkAdjustedToIgnoreNullCheck;
     }
-    DCHECK(temp_scoped_alloc_.get() != nullptr);
-    temp_scoped_alloc_.reset();
   }
 }
 
+/*
+ * Perform type and size inference for a basic block.
+ */
+bool MIRGraph::InferTypes(BasicBlock* bb) {
+  if (bb->data_flow_info == nullptr) return false;
+
+  bool infer_changed = false;
+  for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+    if (mir->ssa_rep == NULL) {
+        continue;
+    }
+
+    // Propagate type info.
+    infer_changed = InferTypeAndSize(bb, mir, infer_changed);
+  }
+
+  return infer_changed;
+}
+
 bool MIRGraph::EliminateClassInitChecksGate() {
   if ((cu_->disable_opt & (1 << kClassInitCheckElimination)) != 0 ||
-      !cu_->mir_graph->HasStaticFieldAccess()) {
+      (merged_df_flags_ & DF_CLINIT) == 0) {
     return false;
   }
 
-  if (kIsDebugBuild) {
-    AllNodesIterator iter(this);
-    for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
-      CHECK(bb->data_flow_info == nullptr || bb->data_flow_info->ending_check_v == nullptr);
-    }
-  }
-
   DCHECK(temp_scoped_alloc_.get() == nullptr);
   temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
 
   // Each insn we use here has at least 2 code units, offset/2 will be a unique index.
   const size_t end = (GetNumDalvikInsns() + 1u) / 2u;
-  temp_insn_data_ = static_cast<uint16_t*>(
-      temp_scoped_alloc_->Alloc(end * sizeof(*temp_insn_data_), kArenaAllocGrowableArray));
+  temp_.cice.indexes = static_cast<uint16_t*>(
+      temp_scoped_alloc_->Alloc(end * sizeof(*temp_.cice.indexes), kArenaAllocGrowableArray));
+  std::fill_n(temp_.cice.indexes, end, 0xffffu);
 
   uint32_t unique_class_count = 0u;
   {
@@ -1099,26 +1162,38 @@
     // 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 (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) {
+            const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(mir);
+            if (!field_info.IsReferrersClass()) {
+              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())
+              };
+              uint16_t index = class_to_index_map.insert(entry).first->index;
+              // Using offset/2 for index into temp_.cice.indexes.
+              temp_.cice.indexes[mir->offset / 2u] = index;
+            }
+          } else if (IsInstructionInvokeStatic(mir->dalvikInsn.opcode)) {
+            const MirMethodLoweringInfo& method_info = GetMethodLoweringInfo(mir);
+            DCHECK(method_info.IsStatic());
+            if (method_info.FastPath() && !method_info.IsReferrersClass()) {
+              MapEntry entry = {
+                  method_info.DeclaringDexFile(),
+                  method_info.DeclaringClassIndex(),
+                  static_cast<uint16_t>(class_to_index_map.size())
+              };
+              uint16_t index = class_to_index_map.insert(entry).first->index;
+              // Using offset/2 for index into temp_.cice.indexes.
+              temp_.cice.indexes[mir->offset / 2u] = index;
+            }
           }
-          // Using offset/2 for index into temp_insn_data_.
-          temp_insn_data_[mir->offset / 2u] = index;
         }
       }
     }
@@ -1127,15 +1202,19 @@
 
   if (unique_class_count == 0u) {
     // All SGET/SPUTs refer to initialized classes. Nothing to do.
-    temp_insn_data_ = nullptr;
+    temp_.cice.indexes = nullptr;
     temp_scoped_alloc_.reset();
     return false;
   }
 
-  temp_bit_vector_size_ = unique_class_count;
-  temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
-      temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapClInitCheck);
-  DCHECK_GT(temp_bit_vector_size_, 0u);
+  // 2 bits for each class: is class initialized, is class in dex cache.
+  temp_.cice.num_class_bits = 2u * unique_class_count;
+  temp_.cice.work_classes_to_check = new (temp_scoped_alloc_.get()) ArenaBitVector(
+      temp_scoped_alloc_.get(), temp_.cice.num_class_bits, false, kBitMapClInitCheck);
+  temp_.cice.ending_classes_to_check_matrix = static_cast<ArenaBitVector**>(
+      temp_scoped_alloc_->Alloc(sizeof(ArenaBitVector*) * GetNumBlocks(), kArenaAllocMisc));
+  std::fill_n(temp_.cice.ending_classes_to_check_matrix, GetNumBlocks(), nullptr);
+  DCHECK_GT(temp_.cice.num_class_bits, 0u);
   return true;
 }
 
@@ -1144,39 +1223,31 @@
  */
 bool MIRGraph::EliminateClassInitChecks(BasicBlock* bb) {
   DCHECK_EQ((cu_->disable_opt & (1 << kClassInitCheckElimination)), 0u);
-  if (bb->data_flow_info == NULL) {
+  if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
+    // Ignore the kExitBlock as well.
+    DCHECK(bb->first_mir_insn == nullptr);
     return false;
   }
 
   /*
    * Set initial state.  Catch blocks don't need any special treatment.
    */
-  ArenaBitVector* classes_to_check = temp_bit_vector_;
+  ArenaBitVector* classes_to_check = temp_.cice.work_classes_to_check;
   DCHECK(classes_to_check != nullptr);
   if (bb->block_type == kEntryBlock) {
-    classes_to_check->SetInitialBits(temp_bit_vector_size_);
-  } else if (bb->predecessors.size() == 1) {
-    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(pred_bb->data_flow_info->ending_check_v != nullptr);
-    classes_to_check->Copy(pred_bb->data_flow_info->ending_check_v);
+    classes_to_check->SetInitialBits(temp_.cice.num_class_bits);
   } 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 (pred_bb->data_flow_info->ending_check_v == nullptr) {
+      if (temp_.cice.ending_classes_to_check_matrix[pred_id] == nullptr) {
         continue;
       }
       if (!copied_first) {
         copied_first = true;
-        classes_to_check->Copy(pred_bb->data_flow_info->ending_check_v);
+        classes_to_check->Copy(temp_.cice.ending_classes_to_check_matrix[pred_id]);
       } else {
-        classes_to_check->Union(pred_bb->data_flow_info->ending_check_v);
+        classes_to_check->Union(temp_.cice.ending_classes_to_check_matrix[pred_id]);
       }
     }
     DCHECK(copied_first);  // At least one predecessor must have been processed before this bb.
@@ -1185,114 +1256,143 @@
 
   // Walk through the instruction in the block, updating as necessary
   for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
-    if (mir->dalvikInsn.opcode >= Instruction::SGET &&
-        mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) {
-      uint16_t index = temp_insn_data_[mir->offset / 2u];
-      if (index != 0xffffu) {
-        if (mir->dalvikInsn.opcode >= Instruction::SGET &&
-            mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) {
-          if (!classes_to_check->IsBitSet(index)) {
-            // Eliminate the class init check.
-            mir->optimization_flags |= MIR_IGNORE_CLINIT_CHECK;
-          } else {
-            // Do the class init check.
-            mir->optimization_flags &= ~MIR_IGNORE_CLINIT_CHECK;
-          }
+    uint16_t index = temp_.cice.indexes[mir->offset / 2u];
+    if (index != 0xffffu) {
+      bool check_initialization = false;
+      bool check_dex_cache = false;
+
+      // NOTE: index != 0xffff does not guarantee that this is an SGET/SPUT/INVOKE_STATIC.
+      // Dex instructions with width 1 can have the same offset/2.
+
+      if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) {
+        check_initialization = true;
+        check_dex_cache = true;
+      } else if (IsInstructionInvokeStatic(mir->dalvikInsn.opcode)) {
+        check_initialization = true;
+        // NOTE: INVOKE_STATIC doesn't guarantee that the type will be in the dex cache.
+      }
+
+      if (check_dex_cache) {
+        uint32_t check_dex_cache_index = 2u * index + 1u;
+        if (!classes_to_check->IsBitSet(check_dex_cache_index)) {
+          // Eliminate the class init check.
+          mir->optimization_flags |= MIR_CLASS_IS_IN_DEX_CACHE;
+        } else {
+          // Do the class init check.
+          mir->optimization_flags &= ~MIR_CLASS_IS_IN_DEX_CACHE;
+        }
+        classes_to_check->ClearBit(check_dex_cache_index);
+      }
+      if (check_initialization) {
+        uint32_t check_clinit_index = 2u * index;
+        if (!classes_to_check->IsBitSet(check_clinit_index)) {
+          // Eliminate the class init check.
+          mir->optimization_flags |= MIR_CLASS_IS_INITIALIZED;
+        } else {
+          // Do the class init check.
+          mir->optimization_flags &= ~MIR_CLASS_IS_INITIALIZED;
         }
         // Mark the class as initialized.
-        classes_to_check->ClearBit(index);
+        classes_to_check->ClearBit(check_clinit_index);
       }
     }
   }
 
   // Did anything change?
   bool changed = false;
-  if (bb->data_flow_info->ending_check_v == nullptr) {
+  ArenaBitVector* old_ending_classes_to_check = temp_.cice.ending_classes_to_check_matrix[bb->id];
+  if (old_ending_classes_to_check == nullptr) {
     DCHECK(temp_scoped_alloc_.get() != nullptr);
-    DCHECK(bb->data_flow_info != nullptr);
-    bb->data_flow_info->ending_check_v = new (temp_scoped_alloc_.get()) ArenaBitVector(
-        temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapClInitCheck);
     changed = classes_to_check->GetHighestBitSet() != -1;
-    bb->data_flow_info->ending_check_v->Copy(classes_to_check);
-  } else if (!classes_to_check->Equal(bb->data_flow_info->ending_check_v)) {
+    temp_.cice.ending_classes_to_check_matrix[bb->id] = classes_to_check;
+    // Create a new classes_to_check for next BB.
+    temp_.cice.work_classes_to_check = new (temp_scoped_alloc_.get()) ArenaBitVector(
+        temp_scoped_alloc_.get(), temp_.cice.num_class_bits, false, kBitMapClInitCheck);
+  } else if (!classes_to_check->Equal(old_ending_classes_to_check)) {
     changed = true;
-    bb->data_flow_info->ending_check_v->Copy(classes_to_check);
+    temp_.cice.ending_classes_to_check_matrix[bb->id] = classes_to_check;
+    temp_.cice.work_classes_to_check = old_ending_classes_to_check;  // Reuse for next BB.
   }
   return changed;
 }
 
 void MIRGraph::EliminateClassInitChecksEnd() {
   // Clean up temporaries.
-  temp_bit_vector_size_ = 0u;
-  temp_bit_vector_ = nullptr;
-  AllNodesIterator iter(this);
-  for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
-    if (bb->data_flow_info != nullptr) {
-      bb->data_flow_info->ending_check_v = nullptr;
-    }
-  }
-
-  DCHECK(temp_insn_data_ != nullptr);
-  temp_insn_data_ = nullptr;
+  temp_.cice.num_class_bits = 0u;
+  temp_.cice.work_classes_to_check = nullptr;
+  temp_.cice.ending_classes_to_check_matrix = nullptr;
+  DCHECK(temp_.cice.indexes != nullptr);
+  temp_.cice.indexes = nullptr;
   DCHECK(temp_scoped_alloc_.get() != nullptr);
   temp_scoped_alloc_.reset();
 }
 
 bool MIRGraph::ApplyGlobalValueNumberingGate() {
-  if ((cu_->disable_opt & (1u << kGlobalValueNumbering)) != 0u) {
+  if (GlobalValueNumbering::Skip(cu_)) {
     return false;
   }
 
   DCHECK(temp_scoped_alloc_ == nullptr);
   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()));
+  temp_.gvn.ifield_ids_ =
+      GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), ifield_lowering_infos_);
+  temp_.gvn.sfield_ids_ =
+      GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), sfield_lowering_infos_);
+  DCHECK(temp_.gvn.gvn == nullptr);
+  temp_.gvn.gvn = new (temp_scoped_alloc_.get()) GlobalValueNumbering(
+      cu_, temp_scoped_alloc_.get(), GlobalValueNumbering::kModeGvn);
   return true;
 }
 
 bool MIRGraph::ApplyGlobalValueNumbering(BasicBlock* bb) {
-  DCHECK(temp_gvn_ != nullptr);
-  LocalValueNumbering* lvn = temp_gvn_->PrepareBasicBlock(bb);
+  DCHECK(temp_.gvn.gvn != nullptr);
+  LocalValueNumbering* lvn = temp_.gvn.gvn->PrepareBasicBlock(bb);
   if (lvn != nullptr) {
     for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
       lvn->GetValueNumber(mir);
     }
   }
-  bool change = (lvn != nullptr) && temp_gvn_->FinishBasicBlock(bb);
+  bool change = (lvn != nullptr) && temp_.gvn.gvn->FinishBasicBlock(bb);
   return change;
 }
 
 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);
+  DCHECK(temp_.gvn.gvn != nullptr);
+  if (temp_.gvn.gvn->Good()) {
+    if (max_nested_loops_ != 0u) {
+      temp_.gvn.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.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.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);
   }
 
-  DCHECK(temp_gvn_ != nullptr);
-  temp_gvn_.reset();
+  delete temp_.gvn.gvn;
+  temp_.gvn.gvn = nullptr;
+  temp_.gvn.ifield_ids_ = nullptr;
+  temp_.gvn.sfield_ids_ = nullptr;
   DCHECK(temp_scoped_alloc_ != nullptr);
   temp_scoped_alloc_.reset();
 }
 
 void MIRGraph::ComputeInlineIFieldLoweringInfo(uint16_t field_idx, MIR* invoke, MIR* iget_or_iput) {
   uint32_t method_index = invoke->meta.method_lowering_info;
-  if (temp_bit_vector_->IsBitSet(method_index)) {
-    iget_or_iput->meta.ifield_lowering_info = temp_insn_data_[method_index];
+  if (temp_.smi.processed_indexes->IsBitSet(method_index)) {
+    iget_or_iput->meta.ifield_lowering_info = temp_.smi.lowering_infos[method_index];
     DCHECK_EQ(field_idx, GetIFieldLoweringInfo(iget_or_iput).FieldIndex());
     return;
   }
@@ -1303,14 +1403,15 @@
       cu_, cu_->class_loader, cu_->class_linker, *target.dex_file,
       nullptr /* code_item not used */, 0u /* class_def_idx not used */, target.dex_method_index,
       0u /* access_flags not used */, nullptr /* verified_method not used */);
-  MirIFieldLoweringInfo inlined_field_info(field_idx);
+  DexMemAccessType type = IGetOrIPutMemAccessType(iget_or_iput->dalvikInsn.opcode);
+  MirIFieldLoweringInfo inlined_field_info(field_idx, type);
   MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, &inlined_unit, &inlined_field_info, 1u);
   DCHECK(inlined_field_info.IsResolved());
 
   uint32_t field_info_index = ifield_lowering_infos_.size();
   ifield_lowering_infos_.push_back(inlined_field_info);
-  temp_bit_vector_->SetBit(method_index);
-  temp_insn_data_[method_index] = field_info_index;
+  temp_.smi.processed_indexes->SetBit(method_index);
+  temp_.smi.lowering_infos[method_index] = field_info_index;
   iget_or_iput->meta.ifield_lowering_info = field_info_index;
 }
 
@@ -1332,12 +1433,12 @@
 
   DCHECK(temp_scoped_alloc_.get() == nullptr);
   temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
-  temp_bit_vector_size_ = method_lowering_infos_.size();
-  temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
-      temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapMisc);
-  temp_bit_vector_->ClearAllBits();
-  temp_insn_data_ = static_cast<uint16_t*>(temp_scoped_alloc_->Alloc(
-      temp_bit_vector_size_ * sizeof(*temp_insn_data_), kArenaAllocGrowableArray));
+  temp_.smi.num_indexes = method_lowering_infos_.size();
+  temp_.smi.processed_indexes = new (temp_scoped_alloc_.get()) ArenaBitVector(
+      temp_scoped_alloc_.get(), temp_.smi.num_indexes, false, kBitMapMisc);
+  temp_.smi.processed_indexes->ClearAllBits();
+  temp_.smi.lowering_infos = static_cast<uint16_t*>(temp_scoped_alloc_->Alloc(
+      temp_.smi.num_indexes * sizeof(*temp_.smi.lowering_infos), kArenaAllocGrowableArray));
 }
 
 void MIRGraph::InlineSpecialMethods(BasicBlock* bb) {
@@ -1362,8 +1463,8 @@
     }
 
     if (sharp_type == kStatic) {
-      bool needs_clinit = method_info.NeedsClassInitialization() &&
-          ((mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0);
+      bool needs_clinit = !method_info.IsClassInitialized() &&
+          ((mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0);
       if (needs_clinit) {
         continue;
       }
@@ -1384,10 +1485,12 @@
 }
 
 void MIRGraph::InlineSpecialMethodsEnd() {
-  DCHECK(temp_insn_data_ != nullptr);
-  temp_insn_data_ = nullptr;
-  DCHECK(temp_bit_vector_ != nullptr);
-  temp_bit_vector_ = nullptr;
+  // Clean up temporaries.
+  DCHECK(temp_.smi.lowering_infos != nullptr);
+  temp_.smi.lowering_infos = nullptr;
+  temp_.smi.num_indexes = 0u;
+  DCHECK(temp_.smi.processed_indexes != nullptr);
+  temp_.smi.processed_indexes = nullptr;
   DCHECK(temp_scoped_alloc_.get() != nullptr);
   temp_scoped_alloc_.reset();
 }
@@ -1416,7 +1519,7 @@
   }
 }
 
-bool MIRGraph::BuildExtendedBBList(struct BasicBlock* bb) {
+bool MIRGraph::BuildExtendedBBList(class BasicBlock* bb) {
   if (bb->visited) return false;
   if (!((bb->block_type == kEntryBlock) || (bb->block_type == kDalvikByteCode)
       || (bb->block_type == kExitBlock))) {
@@ -1448,6 +1551,16 @@
   return false;  // Not iterative - return value will be ignored
 }
 
+void MIRGraph::BasicBlockOptimizationStart() {
+  if ((cu_->disable_opt & (1 << kLocalValueNumbering)) == 0) {
+    temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
+    temp_.gvn.ifield_ids_ =
+        GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), ifield_lowering_infos_);
+    temp_.gvn.sfield_ids_ =
+        GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), sfield_lowering_infos_);
+  }
+}
+
 void MIRGraph::BasicBlockOptimization() {
   if ((cu_->disable_opt & (1 << kSuppressExceptionEdges)) != 0) {
     ClearAllVisitedFlags();
@@ -1467,4 +1580,316 @@
   }
 }
 
+void MIRGraph::BasicBlockOptimizationEnd() {
+  // Clean up after LVN.
+  temp_.gvn.ifield_ids_ = nullptr;
+  temp_.gvn.sfield_ids_ = nullptr;
+  temp_scoped_alloc_.reset();
+}
+
+bool MIRGraph::EliminateSuspendChecksGate() {
+  if ((cu_->disable_opt & (1 << kSuspendCheckElimination)) != 0 ||  // Disabled.
+      GetMaxNestedLoops() == 0u ||   // Nothing to do.
+      GetMaxNestedLoops() >= 32u ||  // Only 32 bits in suspend_checks_in_loops_[.].
+                                     // Exclude 32 as well to keep bit shifts well-defined.
+      !HasInvokes()) {               // No invokes to actually eliminate any suspend checks.
+    return false;
+  }
+  if (cu_->compiler_driver != nullptr && cu_->compiler_driver->GetMethodInlinerMap() != nullptr) {
+    temp_.sce.inliner =
+        cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file);
+  }
+  suspend_checks_in_loops_ = static_cast<uint32_t*>(
+      arena_->Alloc(GetNumBlocks() * sizeof(*suspend_checks_in_loops_), kArenaAllocMisc));
+  return true;
+}
+
+bool MIRGraph::EliminateSuspendChecks(BasicBlock* bb) {
+  if (bb->block_type != kDalvikByteCode) {
+    return false;
+  }
+  DCHECK_EQ(GetTopologicalSortOrderLoopHeadStack()->size(), bb->nesting_depth);
+  if (bb->nesting_depth == 0u) {
+    // Out of loops.
+    DCHECK_EQ(suspend_checks_in_loops_[bb->id], 0u);  // The array was zero-initialized.
+    return false;
+  }
+  uint32_t suspend_checks_in_loops = (1u << bb->nesting_depth) - 1u;  // Start with all loop heads.
+  bool found_invoke = false;
+  for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+    if (IsInstructionInvoke(mir->dalvikInsn.opcode) &&
+        (temp_.sce.inliner == nullptr ||
+         !temp_.sce.inliner->IsIntrinsic(mir->dalvikInsn.vB, nullptr))) {
+      // Non-intrinsic invoke, rely on a suspend point in the invoked method.
+      found_invoke = true;
+      break;
+    }
+  }
+  if (!found_invoke) {
+    // Intersect suspend checks from predecessors.
+    uint16_t bb_topo_idx = topological_order_indexes_[bb->id];
+    uint32_t pred_mask_union = 0u;
+    for (BasicBlockId pred_id : bb->predecessors) {
+      uint16_t pred_topo_idx = topological_order_indexes_[pred_id];
+      if (pred_topo_idx < bb_topo_idx) {
+        // Determine the loop depth of the predecessors relative to this block.
+        size_t pred_loop_depth = topological_order_loop_head_stack_.size();
+        while (pred_loop_depth != 0u &&
+            pred_topo_idx < topological_order_loop_head_stack_[pred_loop_depth - 1].first) {
+          --pred_loop_depth;
+        }
+        DCHECK_LE(pred_loop_depth, GetBasicBlock(pred_id)->nesting_depth);
+        uint32_t pred_mask = (1u << pred_loop_depth) - 1u;
+        // Intersect pred_mask bits in suspend_checks_in_loops with
+        // suspend_checks_in_loops_[pred_id].
+        uint32_t pred_loops_without_checks = pred_mask & ~suspend_checks_in_loops_[pred_id];
+        suspend_checks_in_loops = suspend_checks_in_loops & ~pred_loops_without_checks;
+        pred_mask_union |= pred_mask;
+      }
+    }
+    DCHECK_EQ(((1u << (IsLoopHead(bb->id) ? bb->nesting_depth - 1u: bb->nesting_depth)) - 1u),
+              pred_mask_union);
+    suspend_checks_in_loops &= pred_mask_union;
+  }
+  suspend_checks_in_loops_[bb->id] = suspend_checks_in_loops;
+  if (suspend_checks_in_loops == 0u) {
+    return false;
+  }
+  // Apply MIR_IGNORE_SUSPEND_CHECK if appropriate.
+  if (bb->taken != NullBasicBlockId) {
+    DCHECK(bb->last_mir_insn != nullptr);
+    DCHECK(IsInstructionIfCc(bb->last_mir_insn->dalvikInsn.opcode) ||
+           IsInstructionIfCcZ(bb->last_mir_insn->dalvikInsn.opcode) ||
+           IsInstructionGoto(bb->last_mir_insn->dalvikInsn.opcode) ||
+           (static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) >= kMirOpFusedCmplFloat &&
+            static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) <= kMirOpFusedCmpLong));
+    if (!IsSuspendCheckEdge(bb, bb->taken) &&
+        (bb->fall_through == NullBasicBlockId || !IsSuspendCheckEdge(bb, bb->fall_through))) {
+      bb->last_mir_insn->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK;
+    }
+  } else if (bb->fall_through != NullBasicBlockId && IsSuspendCheckEdge(bb, bb->fall_through)) {
+    // We've got a fall-through suspend edge. Add an artificial GOTO to force suspend check.
+    MIR* mir = NewMIR();
+    mir->dalvikInsn.opcode = Instruction::GOTO;
+    mir->dalvikInsn.vA = 0;  // Branch offset.
+    mir->offset = GetBasicBlock(bb->fall_through)->start_offset;
+    mir->m_unit_index = current_method_;
+    mir->ssa_rep = reinterpret_cast<SSARepresentation*>(
+        arena_->Alloc(sizeof(SSARepresentation), kArenaAllocDFInfo));  // Zero-initialized.
+    bb->AppendMIR(mir);
+    std::swap(bb->fall_through, bb->taken);  // The fall-through has become taken.
+  }
+  return true;
+}
+
+void MIRGraph::EliminateSuspendChecksEnd() {
+  temp_.sce.inliner = nullptr;
+}
+
+bool MIRGraph::CanThrow(MIR* mir) {
+  if ((mir->dalvikInsn.FlagsOf() & Instruction::kThrow) == 0) {
+    return false;
+  }
+  const int opt_flags = mir->optimization_flags;
+  uint64_t df_attributes = GetDataFlowAttributes(mir);
+
+  // First, check if the insn can still throw NPE.
+  if (((df_attributes & DF_HAS_NULL_CHKS) != 0) && ((opt_flags & MIR_IGNORE_NULL_CHECK) == 0)) {
+    return true;
+  }
+
+  // Now process specific instructions.
+  if ((df_attributes & DF_IFIELD) != 0) {
+    // The IGET/IPUT family. We have processed the IGET/IPUT null check above.
+    DCHECK_NE(opt_flags & MIR_IGNORE_NULL_CHECK, 0);
+    // If not fast, weird things can happen and the insn can throw.
+    const MirIFieldLoweringInfo& field_info = GetIFieldLoweringInfo(mir);
+    bool fast = (df_attributes & DF_DA) != 0 ? field_info.FastGet() : field_info.FastPut();
+    return !fast;
+  } else if ((df_attributes & DF_SFIELD) != 0) {
+    // The SGET/SPUT family. Check for potentially throwing class initialization.
+    // Also, if not fast, weird things can happen and the insn can throw.
+    const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(mir);
+    bool fast = (df_attributes & DF_DA) != 0 ? field_info.FastGet() : field_info.FastPut();
+    bool is_class_initialized = field_info.IsClassInitialized() ||
+        ((mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0);
+    return !(fast && is_class_initialized);
+  } 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(opt_flags & MIR_IGNORE_NULL_CHECK, 0);
+    // Non-throwing only if range check has been eliminated.
+    return ((opt_flags & MIR_IGNORE_RANGE_CHECK) == 0);
+  } else if (mir->dalvikInsn.opcode == Instruction::ARRAY_LENGTH ||
+      mir->dalvikInsn.opcode == Instruction::FILL_ARRAY_DATA ||
+      static_cast<int>(mir->dalvikInsn.opcode) == kMirOpNullCheck) {
+    // No more checks for these (null check was processed above).
+    return false;
+  }
+  return true;
+}
+
+bool MIRGraph::HasAntiDependency(MIR* first, MIR* second) {
+  DCHECK(first->ssa_rep != nullptr);
+  DCHECK(second->ssa_rep != nullptr);
+  if ((second->ssa_rep->num_defs > 0) && (first->ssa_rep->num_uses > 0)) {
+    int vreg0 = SRegToVReg(second->ssa_rep->defs[0]);
+    int vreg1 = (second->ssa_rep->num_defs == 2) ?
+        SRegToVReg(second->ssa_rep->defs[1]) : INVALID_VREG;
+    for (int i = 0; i < first->ssa_rep->num_uses; i++) {
+      int32_t use = SRegToVReg(first->ssa_rep->uses[i]);
+      if (use == vreg0 || use == vreg1) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void MIRGraph::CombineMultiplyAdd(MIR* mul_mir, MIR* add_mir, bool mul_is_first_addend,
+                                  bool is_wide, bool is_sub) {
+  if (is_wide) {
+    if (is_sub) {
+      add_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpMsubLong);
+    } else {
+      add_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpMaddLong);
+    }
+  } else {
+    if (is_sub) {
+      add_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpMsubInt);
+    } else {
+      add_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpMaddInt);
+    }
+  }
+  add_mir->ssa_rep->num_uses = is_wide ? 6 : 3;
+  int32_t addend0 = INVALID_SREG;
+  int32_t addend1 = INVALID_SREG;
+  if (is_wide) {
+    addend0 = mul_is_first_addend ? add_mir->ssa_rep->uses[2] : add_mir->ssa_rep->uses[0];
+    addend1 = mul_is_first_addend ? add_mir->ssa_rep->uses[3] : add_mir->ssa_rep->uses[1];
+  } else {
+    addend0 = mul_is_first_addend ? add_mir->ssa_rep->uses[1] : add_mir->ssa_rep->uses[0];
+  }
+
+  AllocateSSAUseData(add_mir, add_mir->ssa_rep->num_uses);
+  add_mir->ssa_rep->uses[0] = mul_mir->ssa_rep->uses[0];
+  add_mir->ssa_rep->uses[1] = mul_mir->ssa_rep->uses[1];
+  // Clear the original multiply product ssa use count, as it is not used anymore.
+  raw_use_counts_[mul_mir->ssa_rep->defs[0]] = 0;
+  use_counts_[mul_mir->ssa_rep->defs[0]] = 0;
+  if (is_wide) {
+    DCHECK_EQ(add_mir->ssa_rep->num_uses, 6);
+    add_mir->ssa_rep->uses[2] = mul_mir->ssa_rep->uses[2];
+    add_mir->ssa_rep->uses[3] = mul_mir->ssa_rep->uses[3];
+    add_mir->ssa_rep->uses[4] = addend0;
+    add_mir->ssa_rep->uses[5] = addend1;
+    raw_use_counts_[mul_mir->ssa_rep->defs[1]] = 0;
+    use_counts_[mul_mir->ssa_rep->defs[1]] = 0;
+  } else {
+    DCHECK_EQ(add_mir->ssa_rep->num_uses, 3);
+    add_mir->ssa_rep->uses[2] = addend0;
+  }
+  // Copy in the decoded instruction information.
+  add_mir->dalvikInsn.vB = SRegToVReg(add_mir->ssa_rep->uses[0]);
+  if (is_wide) {
+    add_mir->dalvikInsn.vC = SRegToVReg(add_mir->ssa_rep->uses[2]);
+    add_mir->dalvikInsn.arg[0] = SRegToVReg(add_mir->ssa_rep->uses[4]);
+  } else {
+    add_mir->dalvikInsn.vC = SRegToVReg(add_mir->ssa_rep->uses[1]);
+    add_mir->dalvikInsn.arg[0] = SRegToVReg(add_mir->ssa_rep->uses[2]);
+  }
+  // Original multiply MIR is set to Nop.
+  mul_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+}
+
+void MIRGraph::MultiplyAddOpt(BasicBlock* bb) {
+  if (bb->block_type == kDead) {
+    return;
+  }
+  ScopedArenaAllocator allocator(&cu_->arena_stack);
+  ScopedArenaSafeMap<uint32_t, MIR*> ssa_mul_map(std::less<uint32_t>(), allocator.Adapter());
+  ScopedArenaSafeMap<uint32_t, MIR*>::iterator map_it;
+  for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+    Instruction::Code opcode = mir->dalvikInsn.opcode;
+    bool is_sub = true;
+    bool is_candidate_multiply = false;
+    switch (opcode) {
+      case Instruction::MUL_INT:
+      case Instruction::MUL_INT_2ADDR:
+        is_candidate_multiply = true;
+        break;
+      case Instruction::MUL_LONG:
+      case Instruction::MUL_LONG_2ADDR:
+        if (cu_->target64) {
+          is_candidate_multiply = true;
+        }
+        break;
+      case Instruction::ADD_INT:
+      case Instruction::ADD_INT_2ADDR:
+        is_sub = false;
+        FALLTHROUGH_INTENDED;
+      case Instruction::SUB_INT:
+      case Instruction::SUB_INT_2ADDR:
+        if (((map_it = ssa_mul_map.find(mir->ssa_rep->uses[0])) != ssa_mul_map.end()) && !is_sub) {
+          // a*b+c
+          CombineMultiplyAdd(map_it->second, mir, true /* product is the first addend */,
+                             false /* is_wide */, false /* is_sub */);
+          ssa_mul_map.erase(mir->ssa_rep->uses[0]);
+        } else if ((map_it = ssa_mul_map.find(mir->ssa_rep->uses[1])) != ssa_mul_map.end()) {
+          // c+a*b or c-a*b
+          CombineMultiplyAdd(map_it->second, mir, false /* product is the second addend */,
+                             false /* is_wide */, is_sub);
+          ssa_mul_map.erase(map_it);
+        }
+        break;
+      case Instruction::ADD_LONG:
+      case Instruction::ADD_LONG_2ADDR:
+        is_sub = false;
+        FALLTHROUGH_INTENDED;
+      case Instruction::SUB_LONG:
+      case Instruction::SUB_LONG_2ADDR:
+        if (!cu_->target64) {
+          break;
+        }
+        if ((map_it = ssa_mul_map.find(mir->ssa_rep->uses[0])) != ssa_mul_map.end() && !is_sub) {
+          // a*b+c
+          CombineMultiplyAdd(map_it->second, mir, true /* product is the first addend */,
+                             true /* is_wide */, false /* is_sub */);
+          ssa_mul_map.erase(map_it);
+        } else if ((map_it = ssa_mul_map.find(mir->ssa_rep->uses[2])) != ssa_mul_map.end()) {
+          // c+a*b or c-a*b
+          CombineMultiplyAdd(map_it->second, mir, false /* product is the second addend */,
+                             true /* is_wide */, is_sub);
+          ssa_mul_map.erase(map_it);
+        }
+        break;
+      default:
+        if (!ssa_mul_map.empty() && CanThrow(mir)) {
+          // Should not combine multiply and add MIRs across potential exception.
+          ssa_mul_map.clear();
+        }
+        break;
+    }
+
+    // Exclude the case when an MIR writes a vreg which is previous candidate multiply MIR's uses.
+    // It is because that current RA may allocate the same physical register to them. For this
+    // kind of cases, the multiplier has been updated, we should not use updated value to the
+    // multiply-add insn.
+    if (ssa_mul_map.size() > 0) {
+      for (auto it = ssa_mul_map.begin(); it != ssa_mul_map.end();) {
+        MIR* mul = it->second;
+        if (HasAntiDependency(mul, mir)) {
+          it = ssa_mul_map.erase(it);
+        } else {
+          ++it;
+        }
+      }
+    }
+
+    if (is_candidate_multiply &&
+        (GetRawUseCount(mir->ssa_rep->defs[0]) == 1) && (mir->next != nullptr)) {
+      ssa_mul_map.Put(mir->ssa_rep->defs[0], mir);
+    }
+  }
+}
+
 }  // namespace art
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index 55e547e..362c7fd 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -19,19 +19,13 @@
 #include "compiler_internals.h"
 #include "dataflow_iterator.h"
 #include "dataflow_iterator-inl.h"
+#include "dex/mir_field_info.h"
 #include "gtest/gtest.h"
 
 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;
@@ -43,10 +37,24 @@
     BasicBlockId predecessors[kMaxPredecessors];
   };
 
+  struct MethodDef {
+    uint16_t method_idx;
+    uintptr_t declaring_dex_file;
+    uint16_t declaring_class_idx;
+    uint16_t declaring_method_idx;
+    InvokeType invoke_type;
+    InvokeType sharp_type;
+    bool is_referrers_class;
+    bool is_initialized;
+  };
+
   struct MIRDef {
-    Instruction::Code opcode;
     BasicBlockId bbid;
+    Instruction::Code opcode;
     uint32_t field_or_method_info;
+    uint32_t vA;
+    uint32_t vB;
+    uint32_t vC;
   };
 
 #define DEF_SUCC0() \
@@ -72,31 +80,20 @@
 #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);
-  }
+#define DEF_SGET_SPUT(bb, opcode, vA, field_info) \
+    { bb, opcode, field_info, vA, 0u, 0u }
+#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, method_info) \
+    { bb, opcode, method_info, 0u, 0u, vC }
+#define DEF_OTHER0(bb, opcode) \
+    { bb, opcode, 0u, 0u, 0u, 0u }
+#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 }
 
   void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
     cu_.mir_graph->block_id_map_.clear();
@@ -132,7 +129,6 @@
             cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
       }
     }
-    cu_.mir_graph->num_blocks_ = count;
     ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
     cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
     ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
@@ -145,6 +141,142 @@
     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 PrepareNestedLoopsWhile_While() {
+    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(8)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 8), DEF_PRED2(3, 7)),  // Outer while loop head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)),  // Inner while loop head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)),        // "taken" loops to inner head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(5)),        // "taken" loops to outer head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+    };
+    PrepareBasicBlocks(bbs);
+  }
+
+  void PrepareNestedLoopsWhile_WhileWhile() {
+    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(10)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 10), DEF_PRED2(3, 9)),   // Outer while loop head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)),    // Inner while loop head 1.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)),          // Loops to inner head 1.
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 9), DEF_PRED2(5, 8)),    // Inner while loop head 2.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED1(7)),          // loops to inner head 2.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(7)),          // loops to outer head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+    };
+    PrepareBasicBlocks(bbs);
+  }
+
+  void PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge() {
+    // Extra edge from the first inner loop body to second inner loop body (6u->8u).
+    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(10)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 10), DEF_PRED2(3, 9)),   // Outer while loop head.
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 7), DEF_PRED2(4, 6)),    // Inner while loop head 1.
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 8), DEF_PRED1(5)),       // Loops to inner head 1.
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 9), DEF_PRED2(5, 8)),    // Inner while loop head 2.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED2(7, 6)),       // loops to inner head 2.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(7)),          // loops to outer head.
+        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 DoPrepareMethods(const MethodDef* defs, size_t count) {
+    cu_.mir_graph->method_lowering_infos_.clear();
+    cu_.mir_graph->method_lowering_infos_.reserve(count);
+    for (size_t i = 0u; i != count; ++i) {
+      const MethodDef* def = &defs[i];
+      MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type);
+      if (def->declaring_dex_file != 0u) {
+        method_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
+        method_info.declaring_class_idx_ = def->declaring_class_idx;
+        method_info.declaring_method_idx_ = def->declaring_method_idx;
+      }
+      ASSERT_EQ(def->invoke_type != kStatic, def->sharp_type != kStatic);
+      method_info.flags_ =
+          ((def->invoke_type == kStatic) ? MirMethodLoweringInfo::kFlagIsStatic : 0u) |
+          MirMethodLoweringInfo::kFlagFastPath |
+          (static_cast<uint16_t>(def->invoke_type) << MirMethodLoweringInfo::kBitInvokeTypeBegin) |
+          (static_cast<uint16_t>(def->sharp_type) << MirMethodLoweringInfo::kBitSharpTypeBegin) |
+          ((def->is_referrers_class) ? MirMethodLoweringInfo::kFlagIsReferrersClass : 0u) |
+          ((def->is_initialized == kStatic) ? MirMethodLoweringInfo::kFlagClassIsInitialized : 0u);
+      ASSERT_EQ(def->declaring_dex_file != 0u, method_info.IsResolved());
+      cu_.mir_graph->method_lowering_infos_.push_back(method_info);
+    }
+  }
+
+  template <size_t count>
+  void PrepareMethods(const MethodDef (&defs)[count]) {
+    DoPrepareMethods(defs, count);
+  }
+
   void DoPrepareMIRs(const MIRDef* defs, size_t count) {
     mir_count_ = count;
     mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
@@ -156,10 +288,23 @@
       ASSERT_LT(def->bbid, cu_.mir_graph->block_list_.size());
       BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid];
       bb->AppendMIR(mir);
-      if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
+      if (IsInstructionIGetOrIPut(def->opcode)) {
+        ASSERT_LT(def->field_or_method_info, cu_.mir_graph->ifield_lowering_infos_.size());
+        mir->meta.ifield_lowering_info = def->field_or_method_info;
+        ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_or_method_info].MemAccessType(),
+                  IGetOrIPutMemAccessType(def->opcode));
+      } else if (IsInstructionSGetOrSPut(def->opcode)) {
         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_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_or_method_info].MemAccessType(),
+                  SGetOrSPutMemAccessType(def->opcode));
+      } else if (IsInstructionInvoke(def->opcode)) {
+        ASSERT_LT(def->field_or_method_info, cu_.mir_graph->method_lowering_infos_.size());
+        mir->meta.method_lowering_info = def->field_or_method_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 +324,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,100 +341,272 @@
   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;
+    DexMemAccessType type;
+  };
+
+  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, def->type);
+      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;
+        // We don't care about the volatile flag in these tests.
+      }
+      ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
+      ASSERT_FALSE(field_info.IsClassInitialized());
+      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;
+    DexMemAccessType type;
+  };
+
+  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, def->type);
+      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;
+        // We don't care about the volatile flag in these tests.
+      }
+      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() {
+    static const MethodDef methods[] = {
+        { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false },  // Dummy.
+    };
+    PrepareMethods(methods);
+  }
+};
+
+class SuspendCheckEliminationTest : public MirOptimizationTest {
+ protected:
+  bool IsBackEdge(BasicBlockId branch_bb, BasicBlockId target_bb) {
+    BasicBlock* branch = cu_.mir_graph->GetBasicBlock(branch_bb);
+    return target_bb != NullBasicBlockId && cu_.mir_graph->IsBackEdge(branch, target_bb);
+  }
+
+  bool IsSuspendCheckEdge(BasicBlockId branch_bb, BasicBlockId target_bb) {
+    BasicBlock* branch = cu_.mir_graph->GetBasicBlock(branch_bb);
+    return cu_.mir_graph->IsSuspendCheckEdge(branch, target_bb);
+  }
+
+  void PerformSuspendCheckElimination() {
+    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->EliminateSuspendChecksGate();
+    ASSERT_TRUE(gate_result);
+    TopologicalSortIterator iterator(cu_.mir_graph.get());
+    bool change = false;
+    for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
+      change = cu_.mir_graph->EliminateSuspendChecks(bb);
+    }
+    cu_.mir_graph->EliminateSuspendChecksEnd();
+  }
+
+  SuspendCheckEliminationTest()
+      : MirOptimizationTest() {
+    static const MethodDef methods[] = {
+        { 0u, 1u, 0u, 0u, kDirect, kDirect, false, false },  // Dummy.
+    };
+    PrepareMethods(methods);
+  }
+};
+
 TEST_F(ClassInitCheckEliminationTest, SingleBlock) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, 0u },
-      { 1u, 1u, 1u, 1u },
-      { 2u, 1u, 2u, 2u },
-      { 3u, 1u, 3u, 3u },  // Same declaring class as sfield[4].
-      { 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)),
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 2u, 2u, kDexMemAccessWord },
+      { 3u, 1u, 3u, 3u, kDexMemAccessWord },  // Same declaring class as sfield[4].
+      { 4u, 1u, 3u, 4u, kDexMemAccessWord },  // Same declaring class as sfield[3].
+      { 5u, 0u, 0u, 0u, kDexMemAccessWord },  // Unresolved.
   };
   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(3u, Instruction::SPUT, 0u, 5u),  // Unresolved.
+      DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u),  // Unresolved.
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 5u),  // Unresolved.
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 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_);
   for (size_t i = 0u; i != arraysize(mirs); ++i) {
     EXPECT_EQ(expected_ignore_clinit_check[i],
-              (mirs_[i].optimization_flags & MIR_IGNORE_CLINIT_CHECK) != 0) << i;
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_ignore_clinit_check[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
+  }
+}
+
+TEST_F(ClassInitCheckEliminationTest, SingleBlockWithInvokes) {
+  static const SFieldDef sfields[] = {
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 2u, 2u, kDexMemAccessWord },
+  };
+  static const MethodDef methods[] = {
+      { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
+      { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
+      { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
+  };
+  static const MIRDef mirs[] = {
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u),
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
+  };
+  static const bool expected_class_initialized[] = {
+      false, true, false, true, false, true
+  };
+  static const bool expected_class_in_dex_cache[] = {
+      false, false, false, false, false, false
+  };
+
+  PrepareSFields(sfields);
+  PrepareMethods(methods);
+  PrepareSingleBlock();
+  PrepareMIRs(mirs);
+  PerformClassInitCheckElimination();
+  ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
+  ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_class_initialized[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_class_in_dex_cache[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
   }
 }
 
 TEST_F(ClassInitCheckEliminationTest, Diamond) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, 0u },
-      { 1u, 1u, 1u, 1u },
-      { 2u, 1u, 2u, 2u },
-      { 3u, 1u, 3u, 3u },
-      { 4u, 1u, 4u, 4u },
-      { 5u, 1u, 5u, 5u },
-      { 6u, 1u, 6u, 6u },
-      { 7u, 1u, 7u, 7u },
-      { 8u, 1u, 8u, 8u },  // Same declaring class as sfield[9].
-      { 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)),
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 2u, 2u, kDexMemAccessWord },
+      { 3u, 1u, 3u, 3u, kDexMemAccessWord },
+      { 4u, 1u, 4u, 4u, kDexMemAccessWord },
+      { 5u, 1u, 5u, 5u, kDexMemAccessWord },
+      { 6u, 1u, 6u, 6u, kDexMemAccessWord },
+      { 7u, 1u, 7u, 7u, kDexMemAccessWord },
+      { 8u, 1u, 8u, 8u, kDexMemAccessWord },   // Same declaring class as sfield[9].
+      { 9u, 1u, 8u, 9u, kDexMemAccessWord },   // Same declaring class as sfield[8].
+      { 10u, 0u, 0u, 0u, kDexMemAccessWord },  // Unresolved.
   };
   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(3u, Instruction::SGET, 0u, 10u),  // Unresolved.
+      DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 10u),  // Unresolved.
+      DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u),  // Eliminated (BB #3 dominates #6).
+      DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 1u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u),  // Not eliminated (BB #4 doesn't dominate #6).
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 2u),
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),  // Eliminated (BB #3 dominates #4).
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 3u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 3u),  // Eliminated (BB #3 dominates #5).
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 4u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 4u),  // Eliminated (BB #3 dominates #6).
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 5u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 5u),  // Not eliminated (BB #4 doesn't dominate #6).
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 6u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 6u),  // Not eliminated (BB #5 doesn't dominate #6).
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 7u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 7u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 7u),  // Eliminated (initialized in both #3 and #4).
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 8u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 9u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 8u),  // Eliminated (with sfield[9] in BB #5).
+      DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 9u),  // Eliminated (with sfield[8] in BB #4).
   };
   static const bool expected_ignore_clinit_check[] = {
-      false, true,          // Unresolved: sfield[10], method[2]
+      false, true,          // Unresolved: sfield[10]
       false, true,          // sfield[0]
       false, false,         // sfield[1]
       false, true,          // sfield[2]
@@ -317,100 +619,559 @@
   };
 
   PrepareSFields(sfields);
-  PrepareBasicBlocks(bbs);
+  PrepareDiamond();
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
   for (size_t i = 0u; i != arraysize(mirs); ++i) {
     EXPECT_EQ(expected_ignore_clinit_check[i],
-              (mirs_[i].optimization_flags & MIR_IGNORE_CLINIT_CHECK) != 0) << i;
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_ignore_clinit_check[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
+  }
+}
+
+TEST_F(ClassInitCheckEliminationTest, DiamondWithInvokes) {
+  static const SFieldDef sfields[] = {
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 2u, 2u, kDexMemAccessWord },
+      { 3u, 1u, 3u, 3u, kDexMemAccessWord },
+      { 4u, 1u, 4u, 4u, kDexMemAccessWord },
+  };
+  static const MethodDef methods[] = {
+      { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
+      { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
+      { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
+      { 3u, 1u, 3u, 3u, kStatic, kStatic, false, false },
+      { 4u, 1u, 4u, 4u, kStatic, kStatic, false, false },
+  };
+  static const MIRDef mirs[] = {
+      // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
+      DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 0u),
+      DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
+      DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 1u),
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
+      DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
+      DEF_SGET_SPUT(6u, Instruction::SPUT, 0u, 2u),
+      DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 3u),
+      DEF_SGET_SPUT(5u, Instruction::SPUT, 0u, 3u),
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 3u),
+      DEF_SGET_SPUT(4u, Instruction::SPUT, 0u, 4u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 4u),
+      DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u /* dummy */, 4u),
+  };
+  static const bool expected_class_initialized[] = {
+      false, true,    // BB #3 SPUT, BB#6 INVOKE_STATIC
+      false, true,    // BB #3 INVOKE_STATIC, BB#6 SPUT
+      false, false, true,   // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
+      false, false, true,   // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
+      false, false, true,   // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
+  };
+  static const bool expected_class_in_dex_cache[] = {
+      false, false,   // BB #3 SPUT, BB#6 INVOKE_STATIC
+      false, false,   // BB #3 INVOKE_STATIC, BB#6 SPUT
+      false, false, false,  // BB #4 SGET, BB #5 INVOKE_STATIC, BB #6 SPUT
+      false, false, false,  // BB #4 INVOKE_STATIC, BB #5 SPUT, BB #6 SGET
+      false, false, false,  // BB #4 SPUT, BB #5 SGET, BB #6 INVOKE_STATIC
+  };
+
+  PrepareSFields(sfields);
+  PrepareMethods(methods);
+  PrepareDiamond();
+  PrepareMIRs(mirs);
+  PerformClassInitCheckElimination();
+  ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
+  ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_class_initialized[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_class_in_dex_cache[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
   }
 }
 
 TEST_F(ClassInitCheckEliminationTest, Loop) {
   static const SFieldDef sfields[] = {
-      { 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)),
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 2u, 2u, kDexMemAccessWord },
   };
   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(3u, Instruction::SGET, 0u, 0u),
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 0u),  // Eliminated.
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 1u),  // Eliminated.
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u),  // Eliminated.
   };
   static const bool expected_ignore_clinit_check[] = {
-      false, false, true, true
+      false, true, false, true, false, true,
   };
 
   PrepareSFields(sfields);
-  PrepareBasicBlocks(bbs);
+  PrepareLoop();
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
   for (size_t i = 0u; i != arraysize(mirs); ++i) {
     EXPECT_EQ(expected_ignore_clinit_check[i],
-              (mirs_[i].optimization_flags & MIR_IGNORE_CLINIT_CHECK) != 0) << i;
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_ignore_clinit_check[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
+  }
+}
+
+TEST_F(ClassInitCheckEliminationTest, LoopWithInvokes) {
+  static const SFieldDef sfields[] = {
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+  };
+  static const MethodDef methods[] = {
+      { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false },
+      { 1u, 1u, 1u, 1u, kStatic, kStatic, false, false },
+      { 2u, 1u, 2u, 2u, kStatic, kStatic, false, false },
+  };
+  static const MIRDef mirs[] = {
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
+      DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 0u),
+      DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
+      DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 1u),
+      DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
+      DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u /* dummy */, 2u),
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u),
+  };
+  static const bool expected_class_initialized[] = {
+      false, true, false, true, false, true, true,
+  };
+  static const bool expected_class_in_dex_cache[] = {
+      false, false, false, false, false, false, false,
+  };
+
+  PrepareSFields(sfields);
+  PrepareMethods(methods);
+  PrepareLoop();
+  PrepareMIRs(mirs);
+  PerformClassInitCheckElimination();
+  ASSERT_EQ(arraysize(expected_class_initialized), mir_count_);
+  ASSERT_EQ(arraysize(expected_class_in_dex_cache), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_class_initialized[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_class_in_dex_cache[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
   }
 }
 
 TEST_F(ClassInitCheckEliminationTest, Catch) {
   static const SFieldDef sfields[] = {
-      { 0u, 1u, 0u, 0u },
-      { 1u, 1u, 1u, 1u },
-      { 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.
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 2u, 2u, kDexMemAccessWord },
+      { 3u, 1u, 3u, 3u, kDexMemAccessWord },
   };
   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(3u, Instruction::SGET, 0u, 0u),  // Before the exception edge.
+      DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 1u),  // Before the exception edge.
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 2u),  // After the exception edge.
+      DEF_SGET_SPUT(4u, Instruction::SGET, 0u, 3u),  // After the exception edge.
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 0u),  // In catch handler; eliminated.
+      DEF_SGET_SPUT(5u, Instruction::SGET, 0u, 2u),  // In catch handler; not eliminated.
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 0u),  // Class init check eliminated.
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 1u),  // Class init check eliminated.
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 2u),  // Class init check eliminated.
+      DEF_SGET_SPUT(6u, Instruction::SGET, 0u, 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_);
   for (size_t i = 0u; i != arraysize(mirs); ++i) {
     EXPECT_EQ(expected_ignore_clinit_check[i],
-              (mirs_[i].optimization_flags & MIR_IGNORE_CLINIT_CHECK) != 0) << i;
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_INITIALIZED) != 0) << i;
+    EXPECT_EQ(expected_ignore_clinit_check[i],
+              (mirs_[i].optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) != 0) << i;
   }
 }
 
+TEST_F(NullCheckEliminationTest, SingleBlock) {
+  static const IFieldDef ifields[] = {
+      { 0u, 1u, 0u, 0u, kDexMemAccessWord },
+      { 1u, 1u, 0u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 0u, 2u, kDexMemAccessObject },
+  };
+  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, 0u /* dummy */),
+      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, 0u /* dummy */),
+      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, kDexMemAccessWord },
+      { 1u, 1u, 0u, 1u, kDexMemAccessWord },
+      { 2u, 1u, 0u, 2u, kDexMemAccessObject },  // 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, 0u /* dummy */),
+      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, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+  };
+  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, kDexMemAccessWord },
+      { 1u, 1u, 1u, 1u, kDexMemAccessWord },
+  };
+  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;
+  }
+}
+
+TEST_F(SuspendCheckEliminationTest, LoopNoElimination) {
+  static const MIRDef mirs[] = {
+    DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u, 0u),  // Force the pass to run.
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge back.
+  };
+
+  PrepareLoop();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(4u, 4u));
+  EXPECT_TRUE(IsSuspendCheckEdge(4u, 4u));  // Suspend point on loop to self.
+}
+
+TEST_F(SuspendCheckEliminationTest, LoopElimination) {
+  static const MIRDef mirs[] = {
+    DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in the loop.
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge back.
+  };
+
+  PrepareLoop();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(4u, 4u));
+  EXPECT_FALSE(IsSuspendCheckEdge(4u, 4u));  // No suspend point on loop to self.
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_NoElimination) {
+  static const MIRDef mirs[] = {
+    DEF_INVOKE(3u, Instruction::INVOKE_STATIC, 0u, 0u),  // Force the pass to run.
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER0(7u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_While();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(7u, 4u));
+  EXPECT_TRUE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInOuterLoopHead) {
+  static const MIRDef mirs[] = {
+    DEF_INVOKE(4u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in outer loop head.
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER0(7u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_While();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(7u, 4u));
+  EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInOuterLoopBody) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_INVOKE(7u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in outer loop body.
+    DEF_OTHER0(7u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_While();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(7u, 4u));
+  EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInInnerLoopHead) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in inner loop head.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER0(7u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_While();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(7u, 4u));
+  EXPECT_FALSE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_While_InvokeInInnerLoopBody) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop.
+    DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in inner loop body.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER0(7u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_While();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(7u, 4u));
+  EXPECT_TRUE(IsSuspendCheckEdge(7u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_InvokeInFirstInnerLoopHead) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_INVOKE(5u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in first inner loop head.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 1.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER1(7u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 2.
+    DEF_OTHER0(8u, Instruction::GOTO),                   // Edge back to inner loop 2 head.
+    DEF_OTHER0(9u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_WhileWhile();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(8u, 7u));
+  EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));
+  ASSERT_TRUE(IsBackEdge(9u, 4u));
+  EXPECT_FALSE(IsSuspendCheckEdge(9u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_InvokeInFirstInnerLoopBody) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 1.
+    DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in first inner loop body.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER1(7u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 2.
+    DEF_OTHER0(8u, Instruction::GOTO),                   // Edge back to inner loop 2 head.
+    DEF_OTHER0(9u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_WhileWhile();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(8u, 7u));
+  EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));
+  ASSERT_TRUE(IsBackEdge(9u, 4u));
+  EXPECT_TRUE(IsSuspendCheckEdge(9u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_WithExtraEdge_InvokeInFirstInnerLoopBody) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 1.
+    DEF_INVOKE(6u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in first inner loop body.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_OTHER1(7u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 2.
+    DEF_OTHER0(8u, Instruction::GOTO),                   // Edge back to inner loop 2 head.
+    DEF_OTHER0(9u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_FALSE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(8u, 7u));
+  EXPECT_TRUE(IsSuspendCheckEdge(8u, 7u));  // Unaffected by the extra edge.
+  ASSERT_TRUE(IsBackEdge(9u, 4u));
+  EXPECT_TRUE(IsSuspendCheckEdge(9u, 4u));
+}
+
+TEST_F(SuspendCheckEliminationTest, While_WhileWhile_WithExtraEdge_InvokeInSecondInnerLoopHead) {
+  static const MIRDef mirs[] = {
+    DEF_OTHER1(4u, Instruction::IF_NEZ, 1u),             // Edge out of outer loop.
+    DEF_OTHER1(5u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 1.
+    DEF_OTHER0(6u, Instruction::GOTO),                   // Edge back to inner loop head.
+    DEF_INVOKE(7u, Instruction::INVOKE_STATIC, 0u, 0u),  // Invoke in second inner loop head.
+    DEF_OTHER1(7u, Instruction::IF_NEZ, 2u),             // Edge out of inner loop 2.
+    DEF_OTHER0(8u, Instruction::GOTO),                   // Edge back to inner loop 2 head.
+    DEF_OTHER0(9u, Instruction::GOTO),                   // Edge back to outer loop head.
+  };
+
+  PrepareNestedLoopsWhile_WhileWhile_WithExtraEdge();
+  PrepareMIRs(mirs);
+  PerformSuspendCheckElimination();
+  ASSERT_TRUE(IsBackEdge(6u, 5u));
+  EXPECT_TRUE(IsSuspendCheckEdge(6u, 5u));
+  ASSERT_TRUE(IsBackEdge(8u, 7u));
+  EXPECT_FALSE(IsSuspendCheckEdge(8u, 7u));  // Unaffected by the extra edge.
+  ASSERT_TRUE(IsBackEdge(9u, 4u));
+  EXPECT_FALSE(IsSuspendCheckEdge(9u, 4u));
+}
+
 }  // namespace art
diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h
index c377426..d3e54a0 100644
--- a/compiler/dex/pass.h
+++ b/compiler/dex/pass.h
@@ -19,11 +19,13 @@
 
 #include <string>
 
-#include "base/macros.h"
+#include "compiler_ir.h"
+#include "base/logging.h"
+
 namespace art {
 
 // Forward declarations.
-struct BasicBlock;
+class BasicBlock;
 struct CompilationUnit;
 class Pass;
 
@@ -81,12 +83,10 @@
    * @param data the object containing data necessary for the pass.
    * @return whether or not there is a change when walking the BasicBlock
    */
-  virtual bool Worker(PassDataHolder* data) const {
-    // Unused parameter.
-    UNUSED(data);
-
-    // BasicBlock did not change.
-    return false;
+  virtual bool Worker(PassDataHolder* data ATTRIBUTE_UNUSED) const {
+    // Passes that do all their work in Start() or End() should not allow useless node iteration.
+    LOG(FATAL) << "Unsupported default Worker() used for " << GetName();
+    UNREACHABLE();
   }
 
   static void BasePrintMessage(CompilationUnit* c_unit, const char* pass_name, const char* message, ...) {
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 6281062..6bb94c3 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,18 @@
 const Pass* const PassDriver<PassDriverMEOpts>::g_passes[] = {
   GetPassInstance<CacheFieldLoweringInfo>(),
   GetPassInstance<CacheMethodLoweringInfo>(),
-  GetPassInstance<SpecialMethodInliner>(),
-  GetPassInstance<CodeLayout>(),
-  GetPassInstance<NullCheckEliminationAndTypeInference>(),
+  GetPassInstance<CalculatePredecessors>(),
+  GetPassInstance<DFSOrders>(),
   GetPassInstance<ClassInitCheckElimination>(),
-  GetPassInstance<GlobalValueNumberingPass>(),
+  GetPassInstance<SpecialMethodInliner>(),
+  GetPassInstance<NullCheckElimination>(),
   GetPassInstance<BBCombine>(),
+  GetPassInstance<CodeLayout>(),
+  GetPassInstance<GlobalValueNumberingPass>(),
+  GetPassInstance<ConstantPropagation>(),
+  GetPassInstance<MethodUseCount>(),
   GetPassInstance<BBOptimizations>(),
+  GetPassInstance<SuspendCheckElimination>(),
 };
 
 // The number of the passes in the initial list of Passes (g_passes).
diff --git a/compiler/dex/pass_driver_me_post_opt.cc b/compiler/dex/pass_driver_me_post_opt.cc
index 4acab6c..5e2140d 100644
--- a/compiler/dex/pass_driver_me_post_opt.cc
+++ b/compiler/dex/pass_driver_me_post_opt.cc
@@ -31,21 +31,18 @@
 // The initial list of passes to be used by the PassDriveMEPostOpt.
 template<>
 const Pass* const PassDriver<PassDriverMEPostOpt>::g_passes[] = {
-  GetPassInstance<InitializeData>(),
-  GetPassInstance<ClearPhiInstructions>(),
-  GetPassInstance<CalculatePredecessors>(),
-  GetPassInstance<DFSOrders>(),
-  GetPassInstance<BuildDomination>(),
-  GetPassInstance<TopologicalSortOrders>(),
-  GetPassInstance<DefBlockMatrix>(),
-  GetPassInstance<CreatePhiNodes>(),
-  GetPassInstance<ClearVisitedFlag>(),
-  GetPassInstance<SSAConversion>(),
-  GetPassInstance<PhiNodeOperands>(),
-  GetPassInstance<ConstantPropagation>(),
-  GetPassInstance<PerformInitRegLocations>(),
-  GetPassInstance<MethodUseCount>(),
-  GetPassInstance<FreeData>(),
+    GetPassInstance<DFSOrders>(),
+    GetPassInstance<BuildDomination>(),
+    GetPassInstance<TopologicalSortOrders>(),
+    GetPassInstance<InitializeSSATransformation>(),
+    GetPassInstance<ClearPhiInstructions>(),
+    GetPassInstance<DefBlockMatrix>(),
+    GetPassInstance<CreatePhiNodes>(),
+    GetPassInstance<SSAConversion>(),
+    GetPassInstance<PhiNodeOperands>(),
+    GetPassInstance<PerformInitRegLocations>(),
+    GetPassInstance<TypeInference>(),
+    GetPassInstance<FinishSSATransformation>(),
 };
 
 // The number of the passes in the initial list of Passes (g_passes).
diff --git a/compiler/dex/pass_me.h b/compiler/dex/pass_me.h
index 8242cb8..d0b450a 100644
--- a/compiler/dex/pass_me.h
+++ b/compiler/dex/pass_me.h
@@ -23,7 +23,7 @@
 namespace art {
 
 // Forward declarations.
-struct BasicBlock;
+class BasicBlock;
 struct CompilationUnit;
 class Pass;
 
@@ -32,10 +32,11 @@
  * @details Each enum should be a power of 2 to be correctly used.
  */
 enum OptimizationFlag {
-  kOptimizationBasicBlockChange = 1,  /**< @brief Has there been a change to a BasicBlock? */
-  kOptimizationDefUsesChange = 2,     /**< @brief Has there been a change to a def-use? */
-  kLoopStructureChange = 4,           /**< @brief Has there been a loop structural change? */
+  kOptimizationBasicBlockChange = 1,  /// @brief Has there been a change to a BasicBlock?
+  kOptimizationDefUsesChange = 2,     /// @brief Has there been a change to a def-use?
+  kLoopStructureChange = 4,           /// @brief Has there been a loop structural change?
 };
+std::ostream& operator<<(std::ostream& os, const OptimizationFlag& rhs);
 
 // Data holder class.
 class PassMEDataHolder: public PassDataHolder {
@@ -47,25 +48,25 @@
 };
 
 enum DataFlowAnalysisMode {
-  kAllNodes = 0,                           /**< @brief All nodes. */
-  kPreOrderDFSTraversal,                   /**< @brief Depth-First-Search / Pre-Order. */
-  kRepeatingPreOrderDFSTraversal,          /**< @brief Depth-First-Search / Repeating Pre-Order. */
-  kReversePostOrderDFSTraversal,           /**< @brief Depth-First-Search / Reverse Post-Order. */
-  kRepeatingPostOrderDFSTraversal,         /**< @brief Depth-First-Search / Repeating Post-Order. */
-  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. */
+  kAllNodes = 0,                           /// @brief All nodes.
+  kPreOrderDFSTraversal,                   /// @brief Depth-First-Search / Pre-Order.
+  kRepeatingPreOrderDFSTraversal,          /// @brief Depth-First-Search / Repeating Pre-Order.
+  kReversePostOrderDFSTraversal,           /// @brief Depth-First-Search / Reverse Post-Order.
+  kRepeatingPostOrderDFSTraversal,         /// @brief Depth-First-Search / Repeating Post-Order.
+  kRepeatingReversePostOrderDFSTraversal,  /// @brief Depth-First-Search / Repeating Reverse Post-Order.
+  kPostOrderDOMTraversal,                  /// @brief Dominator tree / Post-Order.
+  kTopologicalSortTraversal,               /// @brief Topological Order traversal.
+  kLoopRepeatingTopologicalSortTraversal,  /// @brief Loop-repeating Topological Order traversal.
+  kNoNodes,                                /// @brief Skip BasicBlock traversal.
 };
+std::ostream& operator<<(std::ostream& os, const DataFlowAnalysisMode& rhs);
 
 /**
  * @class Pass
  * @brief Pass is the Pass structure for the optimizations.
  * @details The following structure has the different optimization passes that we are going to do.
  */
-class PassME: public Pass {
+class PassME : public Pass {
  public:
   explicit PassME(const char* name, DataFlowAnalysisMode type = kAllNodes,
           unsigned int flags = 0u, const char* dump = "")
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
deleted file mode 100644
index ba255e0..0000000
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ /dev/null
@@ -1,2003 +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 "object_utils.h"
-
-#include <llvm/ADT/DepthFirstIterator.h>
-#include <llvm/Analysis/Verifier.h>
-#include <llvm/Bitcode/ReaderWriter.h>
-#include <llvm/IR/Instruction.h>
-#include <llvm/IR/Instructions.h>
-#include <llvm/IR/Metadata.h>
-#include <llvm/IR/Type.h>
-#include <llvm/Support/Casting.h>
-#include <llvm/Support/InstIterator.h>
-#include <llvm/Support/ToolOutputFile.h>
-
-#include "dex/compiler_internals.h"
-#include "dex/dataflow_iterator-inl.h"
-#include "dex/frontend.h"
-#include "llvm/ir_builder.h"
-#include "llvm/llvm_compilation_unit.h"
-#include "llvm/utils_llvm.h"
-#include "mir_to_gbc.h"
-#include "thread-inl.h"
-
-const char* kLabelFormat = "%c0x%x_%d";
-const char kInvalidBlock = 0xff;
-const char kNormalBlock = 'L';
-const char kCatchBlock = 'C';
-
-namespace art {
-namespace llvm {
-::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
-}
-
-LLVMInfo::LLVMInfo() {
-  // Create context, module, intrinsic helper & ir builder
-  llvm_context_.reset(new ::llvm::LLVMContext());
-  llvm_module_ = new ::llvm::Module("art", *llvm_context_);
-  ::llvm::StructType::create(*llvm_context_, "JavaObject");
-  art::llvm::makeLLVMModuleContents(llvm_module_);
-  intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_));
-  ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
-}
-
-LLVMInfo::~LLVMInfo() {
-}
-
-::llvm::BasicBlock* MirConverter::GetLLVMBlock(int id) {
-  return id_to_block_map_.Get(id);
-}
-
-::llvm::Value* MirConverter::GetLLVMValue(int s_reg) {
-  return llvm_values_[s_reg];
-}
-
-void MirConverter::SetVregOnValue(::llvm::Value* val, int s_reg) {
-  // Set vreg for debugging
-  art::llvm::IntrinsicHelper::IntrinsicId id = art::llvm::IntrinsicHelper::SetVReg;
-  ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(id);
-  int v_reg = mir_graph_->SRegToVReg(s_reg);
-  ::llvm::Value* table_slot = irb_->getInt32(v_reg);
-  ::llvm::Value* args[] = { table_slot, val };
-  irb_->CreateCall(func, args);
-}
-
-// Replace the placeholder value with the real definition
-void MirConverter::DefineValueOnly(::llvm::Value* val, int s_reg) {
-  ::llvm::Value* placeholder = GetLLVMValue(s_reg);
-  if (placeholder == NULL) {
-    // This can happen on instruction rewrite on verification failure
-    LOG(WARNING) << "Null placeholder";
-    return;
-  }
-  placeholder->replaceAllUsesWith(val);
-  val->takeName(placeholder);
-  llvm_values_[s_reg] = val;
-  ::llvm::Instruction* inst = ::llvm::dyn_cast< ::llvm::Instruction>(placeholder);
-  DCHECK(inst != NULL);
-  inst->eraseFromParent();
-}
-
-void MirConverter::DefineValue(::llvm::Value* val, int s_reg) {
-  DefineValueOnly(val, s_reg);
-  SetVregOnValue(val, s_reg);
-}
-
-::llvm::Type* MirConverter::LlvmTypeFromLocRec(RegLocation loc) {
-  ::llvm::Type* res = NULL;
-  if (loc.wide) {
-    if (loc.fp)
-        res = irb_->getDoubleTy();
-    else
-        res = irb_->getInt64Ty();
-  } else {
-    if (loc.fp) {
-      res = irb_->getFloatTy();
-    } else {
-      if (loc.ref)
-        res = irb_->getJObjectTy();
-      else
-        res = irb_->getInt32Ty();
-    }
-  }
-  return res;
-}
-
-void MirConverter::InitIR() {
-  if (llvm_info_ == NULL) {
-    CompilerTls* tls = cu_->compiler_driver->GetTls();
-    CHECK(tls != NULL);
-    llvm_info_ = static_cast<LLVMInfo*>(tls->GetLLVMInfo());
-    if (llvm_info_ == NULL) {
-      llvm_info_ = new LLVMInfo();
-      tls->SetLLVMInfo(llvm_info_);
-    }
-  }
-  context_ = llvm_info_->GetLLVMContext();
-  module_ = llvm_info_->GetLLVMModule();
-  intrinsic_helper_ = llvm_info_->GetIntrinsicHelper();
-  irb_ = llvm_info_->GetIRBuilder();
-}
-
-::llvm::BasicBlock* MirConverter::FindCaseTarget(uint32_t vaddr) {
-  BasicBlock* bb = mir_graph_->FindBlock(vaddr);
-  DCHECK(bb != NULL);
-  return GetLLVMBlock(bb->id);
-}
-
-void MirConverter::ConvertPackedSwitch(BasicBlock* bb, MIR* mir,
-                                int32_t table_offset, RegLocation rl_src) {
-  const Instruction::PackedSwitchPayload* payload =
-      reinterpret_cast<const Instruction::PackedSwitchPayload*>(
-      mir_graph_->GetTable(mir, table_offset));
-
-  ::llvm::Value* value = GetLLVMValue(rl_src.orig_sreg);
-
-  ::llvm::SwitchInst* sw =
-    irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through),
-                             payload->case_count);
-
-  for (uint16_t i = 0; i < payload->case_count; ++i) {
-    ::llvm::BasicBlock* llvm_bb =
-        FindCaseTarget(current_dalvik_offset_ + payload->targets[i]);
-    sw->addCase(irb_->getInt32(payload->first_key + i), llvm_bb);
-  }
-  ::llvm::MDNode* switch_node =
-      ::llvm::MDNode::get(*context_, irb_->getInt32(table_offset));
-  sw->setMetadata("SwitchTable", switch_node);
-  bb->taken = NullBasicBlockId;
-  bb->fall_through = NullBasicBlockId;
-}
-
-void MirConverter::ConvertSparseSwitch(BasicBlock* bb, MIR* mir,
-                                int32_t table_offset, RegLocation rl_src) {
-  const Instruction::SparseSwitchPayload* payload =
-      reinterpret_cast<const Instruction::SparseSwitchPayload*>(
-      mir_graph_->GetTable(mir, table_offset));
-
-  const int32_t* keys = payload->GetKeys();
-  const int32_t* targets = payload->GetTargets();
-
-  ::llvm::Value* value = GetLLVMValue(rl_src.orig_sreg);
-
-  ::llvm::SwitchInst* sw =
-    irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through),
-                             payload->case_count);
-
-  for (size_t i = 0; i < payload->case_count; ++i) {
-    ::llvm::BasicBlock* llvm_bb =
-        FindCaseTarget(current_dalvik_offset_ + targets[i]);
-    sw->addCase(irb_->getInt32(keys[i]), llvm_bb);
-  }
-  ::llvm::MDNode* switch_node =
-      ::llvm::MDNode::get(*context_, irb_->getInt32(table_offset));
-  sw->setMetadata("SwitchTable", switch_node);
-  bb->taken = NullBasicBlockId;
-  bb->fall_through = NullBasicBlockId;
-}
-
-void MirConverter::ConvertSget(int32_t field_index,
-                        art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest) {
-  ::llvm::Constant* field_idx = irb_->getInt32(field_index);
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* res = irb_->CreateCall(intr, field_idx);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertSput(int32_t field_index,
-                        art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_src) {
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(field_index));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  irb_->CreateCall(intr, args);
-}
-
-void MirConverter::ConvertFillArrayData(int32_t offset, RegLocation rl_array) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  id = art::llvm::IntrinsicHelper::HLFillArrayData;
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(offset));
-  args.push_back(GetLLVMValue(rl_array.orig_sreg));
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  irb_->CreateCall(intr, args);
-}
-
-::llvm::Value* MirConverter::EmitConst(::llvm::ArrayRef< ::llvm::Value*> src,
-                              RegLocation loc) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  if (loc.wide) {
-    if (loc.fp) {
-      id = art::llvm::IntrinsicHelper::ConstDouble;
-    } else {
-      id = art::llvm::IntrinsicHelper::ConstLong;
-    }
-  } else {
-    if (loc.fp) {
-      id = art::llvm::IntrinsicHelper::ConstFloat;
-    } else if (loc.ref) {
-      id = art::llvm::IntrinsicHelper::ConstObj;
-    } else {
-      id = art::llvm::IntrinsicHelper::ConstInt;
-    }
-  }
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  return irb_->CreateCall(intr, src);
-}
-
-void MirConverter::EmitPopShadowFrame() {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(
-      art::llvm::IntrinsicHelper::PopShadowFrame);
-  irb_->CreateCall(intr);
-}
-
-::llvm::Value* MirConverter::EmitCopy(::llvm::ArrayRef< ::llvm::Value*> src,
-                             RegLocation loc) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  if (loc.wide) {
-    if (loc.fp) {
-      id = art::llvm::IntrinsicHelper::CopyDouble;
-    } else {
-      id = art::llvm::IntrinsicHelper::CopyLong;
-    }
-  } else {
-    if (loc.fp) {
-      id = art::llvm::IntrinsicHelper::CopyFloat;
-    } else if (loc.ref) {
-      id = art::llvm::IntrinsicHelper::CopyObj;
-    } else {
-      id = art::llvm::IntrinsicHelper::CopyInt;
-    }
-  }
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  return irb_->CreateCall(intr, src);
-}
-
-void MirConverter::ConvertMoveException(RegLocation rl_dest) {
-  ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(
-      art::llvm::IntrinsicHelper::GetException);
-  ::llvm::Value* res = irb_->CreateCall(func);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertThrow(RegLocation rl_src) {
-  ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
-  ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(
-      art::llvm::IntrinsicHelper::HLThrowException);
-  irb_->CreateCall(func, src);
-}
-
-void MirConverter::ConvertMonitorEnterExit(int opt_flags,
-                                    art::llvm::IntrinsicHelper::IntrinsicId id,
-                                    RegLocation rl_src) {
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(opt_flags));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(id);
-  irb_->CreateCall(func, args);
-}
-
-void MirConverter::ConvertArrayLength(int opt_flags,
-                               RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(opt_flags));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(
-      art::llvm::IntrinsicHelper::OptArrayLength);
-  ::llvm::Value* res = irb_->CreateCall(func, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::EmitSuspendCheck() {
-  art::llvm::IntrinsicHelper::IntrinsicId id =
-      art::llvm::IntrinsicHelper::CheckSuspend;
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  irb_->CreateCall(intr);
-}
-
-::llvm::Value* MirConverter::ConvertCompare(ConditionCode cc,
-                                   ::llvm::Value* src1, ::llvm::Value* src2) {
-  ::llvm::Value* res = NULL;
-  DCHECK_EQ(src1->getType(), src2->getType());
-  switch (cc) {
-    case kCondEq: res = irb_->CreateICmpEQ(src1, src2); break;
-    case kCondNe: res = irb_->CreateICmpNE(src1, src2); break;
-    case kCondLt: res = irb_->CreateICmpSLT(src1, src2); break;
-    case kCondGe: res = irb_->CreateICmpSGE(src1, src2); break;
-    case kCondGt: res = irb_->CreateICmpSGT(src1, src2); break;
-    case kCondLe: res = irb_->CreateICmpSLE(src1, src2); break;
-    default: LOG(FATAL) << "Unexpected cc value " << cc;
-  }
-  return res;
-}
-
-void MirConverter::ConvertCompareAndBranch(BasicBlock* bb, MIR* mir,
-                                    ConditionCode cc, RegLocation rl_src1, RegLocation rl_src2) {
-  if (mir_graph_->GetBasicBlock(bb->taken)->start_offset <= mir->offset) {
-    EmitSuspendCheck();
-  }
-  ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
-  ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg);
-  ::llvm::Value* cond_value = ConvertCompare(cc, src1, src2);
-  cond_value->setName(StringPrintf("t%d", temp_name_++));
-  irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken),
-                           GetLLVMBlock(bb->fall_through));
-  // Don't redo the fallthrough branch in the BB driver
-  bb->fall_through = NullBasicBlockId;
-}
-
-void MirConverter::ConvertCompareZeroAndBranch(BasicBlock* bb,
-                                        MIR* mir, ConditionCode cc, RegLocation rl_src1) {
-  if (mir_graph_->GetBasicBlock(bb->taken)->start_offset <= mir->offset) {
-    EmitSuspendCheck();
-  }
-  ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
-  ::llvm::Value* src2;
-  if (rl_src1.ref) {
-    src2 = irb_->getJNull();
-  } else {
-    src2 = irb_->getInt32(0);
-  }
-  ::llvm::Value* cond_value = ConvertCompare(cc, src1, src2);
-  irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken),
-                           GetLLVMBlock(bb->fall_through));
-  // Don't redo the fallthrough branch in the BB driver
-  bb->fall_through = NullBasicBlockId;
-}
-
-::llvm::Value* MirConverter::GenDivModOp(bool is_div, bool is_long,
-                                ::llvm::Value* src1, ::llvm::Value* src2) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  if (is_long) {
-    if (is_div) {
-      id = art::llvm::IntrinsicHelper::DivLong;
-    } else {
-      id = art::llvm::IntrinsicHelper::RemLong;
-    }
-  } else {
-    if (is_div) {
-      id = art::llvm::IntrinsicHelper::DivInt;
-    } else {
-      id = art::llvm::IntrinsicHelper::RemInt;
-    }
-  }
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2>args;
-  args.push_back(src1);
-  args.push_back(src2);
-  return irb_->CreateCall(intr, args);
-}
-
-::llvm::Value* MirConverter::GenArithOp(OpKind op, bool is_long,
-                               ::llvm::Value* src1, ::llvm::Value* src2) {
-  ::llvm::Value* res = NULL;
-  switch (op) {
-    case kOpAdd: res = irb_->CreateAdd(src1, src2); break;
-    case kOpSub: res = irb_->CreateSub(src1, src2); break;
-    case kOpRsub: res = irb_->CreateSub(src2, src1); break;
-    case kOpMul: res = irb_->CreateMul(src1, src2); break;
-    case kOpOr: res = irb_->CreateOr(src1, src2); break;
-    case kOpAnd: res = irb_->CreateAnd(src1, src2); break;
-    case kOpXor: res = irb_->CreateXor(src1, src2); break;
-    case kOpDiv: res = GenDivModOp(true, is_long, src1, src2); break;
-    case kOpRem: res = GenDivModOp(false, is_long, src1, src2); break;
-    case kOpLsl: res = irb_->CreateShl(src1, src2); break;
-    case kOpLsr: res = irb_->CreateLShr(src1, src2); break;
-    case kOpAsr: res = irb_->CreateAShr(src1, src2); break;
-    default:
-      LOG(FATAL) << "Invalid op " << op;
-  }
-  return res;
-}
-
-void MirConverter::ConvertFPArithOp(OpKind op, RegLocation rl_dest,
-                             RegLocation rl_src1, RegLocation rl_src2) {
-  ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
-  ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg);
-  ::llvm::Value* res = NULL;
-  switch (op) {
-    case kOpAdd: res = irb_->CreateFAdd(src1, src2); break;
-    case kOpSub: res = irb_->CreateFSub(src1, src2); break;
-    case kOpMul: res = irb_->CreateFMul(src1, src2); break;
-    case kOpDiv: res = irb_->CreateFDiv(src1, src2); break;
-    case kOpRem: res = irb_->CreateFRem(src1, src2); break;
-    default:
-      LOG(FATAL) << "Invalid op " << op;
-  }
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertShift(art::llvm::IntrinsicHelper::IntrinsicId id,
-                         RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2>args;
-  args.push_back(GetLLVMValue(rl_src1.orig_sreg));
-  args.push_back(GetLLVMValue(rl_src2.orig_sreg));
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertShiftLit(art::llvm::IntrinsicHelper::IntrinsicId id,
-                            RegLocation rl_dest, RegLocation rl_src, int shift_amount) {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2>args;
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  args.push_back(irb_->getInt32(shift_amount));
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertArithOp(OpKind op, RegLocation rl_dest,
-                           RegLocation rl_src1, RegLocation rl_src2) {
-  ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
-  ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg);
-  DCHECK_EQ(src1->getType(), src2->getType());
-  ::llvm::Value* res = GenArithOp(op, rl_dest.wide, src1, src2);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertArithOpLit(OpKind op, RegLocation rl_dest,
-                              RegLocation rl_src1, int32_t imm) {
-  ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
-  ::llvm::Value* src2 = irb_->getInt32(imm);
-  ::llvm::Value* res = GenArithOp(op, rl_dest.wide, src1, src2);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-/*
- * Process arguments for invoke.  Note: this code is also used to
- * collect and process arguments for NEW_FILLED_ARRAY and NEW_FILLED_ARRAY_RANGE.
- * The requirements are similar.
- */
-void MirConverter::ConvertInvoke(BasicBlock* bb, MIR* mir,
-                          InvokeType invoke_type, bool is_range, bool is_filled_new_array) {
-  CallInfo* info = mir_graph_->NewMemCallInfo(bb, mir, invoke_type, is_range);
-  ::llvm::SmallVector< ::llvm::Value*, 10> args;
-  // Insert the invoke_type
-  args.push_back(irb_->getInt32(static_cast<int>(invoke_type)));
-  // Insert the method_idx
-  args.push_back(irb_->getInt32(info->index));
-  // Insert the optimization flags
-  args.push_back(irb_->getInt32(info->opt_flags));
-  // Now, insert the actual arguments
-  for (int i = 0; i < info->num_arg_words;) {
-    ::llvm::Value* val = GetLLVMValue(info->args[i].orig_sreg);
-    args.push_back(val);
-    i += info->args[i].wide ? 2 : 1;
-  }
-  /*
-   * Choose the invoke return type based on actual usage.  Note: may
-   * be different than shorty.  For example, if a function return value
-   * is not used, we'll treat this as a void invoke.
-   */
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  if (is_filled_new_array) {
-    id = art::llvm::IntrinsicHelper::HLFilledNewArray;
-  } else if (info->result.location == kLocInvalid) {
-    id = art::llvm::IntrinsicHelper::HLInvokeVoid;
-  } else {
-    if (info->result.wide) {
-      if (info->result.fp) {
-        id = art::llvm::IntrinsicHelper::HLInvokeDouble;
-      } else {
-        id = art::llvm::IntrinsicHelper::HLInvokeLong;
-      }
-    } else if (info->result.ref) {
-        id = art::llvm::IntrinsicHelper::HLInvokeObj;
-    } else if (info->result.fp) {
-        id = art::llvm::IntrinsicHelper::HLInvokeFloat;
-    } else {
-        id = art::llvm::IntrinsicHelper::HLInvokeInt;
-    }
-  }
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  if (info->result.location != kLocInvalid) {
-    DefineValue(res, info->result.orig_sreg);
-  }
-}
-
-void MirConverter::ConvertConstObject(uint32_t idx,
-                               art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest) {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* index = irb_->getInt32(idx);
-  ::llvm::Value* res = irb_->CreateCall(intr, index);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertCheckCast(uint32_t type_idx, RegLocation rl_src) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  id = art::llvm::IntrinsicHelper::HLCheckCast;
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(type_idx));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  irb_->CreateCall(intr, args);
-}
-
-void MirConverter::ConvertNewInstance(uint32_t type_idx, RegLocation rl_dest) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  id = art::llvm::IntrinsicHelper::NewInstance;
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* index = irb_->getInt32(type_idx);
-  ::llvm::Value* res = irb_->CreateCall(intr, index);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertNewArray(uint32_t type_idx,
-                            RegLocation rl_dest, RegLocation rl_src) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  id = art::llvm::IntrinsicHelper::NewArray;
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(type_idx));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertAget(int opt_flags,
-                        art::llvm::IntrinsicHelper::IntrinsicId id,
-                        RegLocation rl_dest, RegLocation rl_array, RegLocation rl_index) {
-  ::llvm::SmallVector< ::llvm::Value*, 3> args;
-  args.push_back(irb_->getInt32(opt_flags));
-  args.push_back(GetLLVMValue(rl_array.orig_sreg));
-  args.push_back(GetLLVMValue(rl_index.orig_sreg));
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertAput(int opt_flags,
-                        art::llvm::IntrinsicHelper::IntrinsicId id,
-                        RegLocation rl_src, RegLocation rl_array, RegLocation rl_index) {
-  ::llvm::SmallVector< ::llvm::Value*, 4> args;
-  args.push_back(irb_->getInt32(opt_flags));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  args.push_back(GetLLVMValue(rl_array.orig_sreg));
-  args.push_back(GetLLVMValue(rl_index.orig_sreg));
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  irb_->CreateCall(intr, args);
-}
-
-void MirConverter::ConvertIget(int opt_flags,
-                        art::llvm::IntrinsicHelper::IntrinsicId id,
-                        RegLocation rl_dest, RegLocation rl_obj, int field_index) {
-  ::llvm::SmallVector< ::llvm::Value*, 3> args;
-  args.push_back(irb_->getInt32(opt_flags));
-  args.push_back(GetLLVMValue(rl_obj.orig_sreg));
-  args.push_back(irb_->getInt32(field_index));
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertIput(int opt_flags,
-                        art::llvm::IntrinsicHelper::IntrinsicId id,
-                        RegLocation rl_src, RegLocation rl_obj, int field_index) {
-  ::llvm::SmallVector< ::llvm::Value*, 4> args;
-  args.push_back(irb_->getInt32(opt_flags));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  args.push_back(GetLLVMValue(rl_obj.orig_sreg));
-  args.push_back(irb_->getInt32(field_index));
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  irb_->CreateCall(intr, args);
-}
-
-void MirConverter::ConvertInstanceOf(uint32_t type_idx,
-                              RegLocation rl_dest, RegLocation rl_src) {
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  id = art::llvm::IntrinsicHelper::InstanceOf;
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(irb_->getInt32(type_idx));
-  args.push_back(GetLLVMValue(rl_src.orig_sreg));
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertIntToLong(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* res = irb_->CreateSExt(GetLLVMValue(rl_src.orig_sreg),
-                                            irb_->getInt64Ty());
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertLongToInt(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
-  ::llvm::Value* res = irb_->CreateTrunc(src, irb_->getInt32Ty());
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertFloatToDouble(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
-  ::llvm::Value* res = irb_->CreateFPExt(src, irb_->getDoubleTy());
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertDoubleToFloat(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
-  ::llvm::Value* res = irb_->CreateFPTrunc(src, irb_->getFloatTy());
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertWideComparison(art::llvm::IntrinsicHelper::IntrinsicId id,
-                                         RegLocation rl_dest, RegLocation rl_src1,
-                                         RegLocation rl_src2) {
-  DCHECK_EQ(rl_src1.fp, rl_src2.fp);
-  DCHECK_EQ(rl_src1.wide, rl_src2.wide);
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::SmallVector< ::llvm::Value*, 2> args;
-  args.push_back(GetLLVMValue(rl_src1.orig_sreg));
-  args.push_back(GetLLVMValue(rl_src2.orig_sreg));
-  ::llvm::Value* res = irb_->CreateCall(intr, args);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertIntNarrowing(RegLocation rl_dest, RegLocation rl_src,
-                                art::llvm::IntrinsicHelper::IntrinsicId id) {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* res =
-      irb_->CreateCall(intr, GetLLVMValue(rl_src.orig_sreg));
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertNeg(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* res = irb_->CreateNeg(GetLLVMValue(rl_src.orig_sreg));
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertIntToFP(::llvm::Type* ty, RegLocation rl_dest,
-                           RegLocation rl_src) {
-  ::llvm::Value* res =
-      irb_->CreateSIToFP(GetLLVMValue(rl_src.orig_sreg), ty);
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertFPToInt(art::llvm::IntrinsicHelper::IntrinsicId id,
-                           RegLocation rl_dest,
-                    RegLocation rl_src) {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Value* res = irb_->CreateCall(intr, GetLLVMValue(rl_src.orig_sreg));
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-
-void MirConverter::ConvertNegFP(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* res =
-      irb_->CreateFNeg(GetLLVMValue(rl_src.orig_sreg));
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::ConvertNot(RegLocation rl_dest, RegLocation rl_src) {
-  ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
-  ::llvm::Value* res = irb_->CreateXor(src, static_cast<uint64_t>(-1));
-  DefineValue(res, rl_dest.orig_sreg);
-}
-
-void MirConverter::EmitConstructorBarrier() {
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(
-      art::llvm::IntrinsicHelper::ConstructorBarrier);
-  irb_->CreateCall(intr);
-}
-
-/*
- * Target-independent code generation.  Use only high-level
- * load/store utilities here, or target-dependent genXX() handlers
- * when necessary.
- */
-bool MirConverter::ConvertMIRNode(MIR* mir, BasicBlock* bb,
-                           ::llvm::BasicBlock* llvm_bb) {
-  bool res = false;   // Assume success
-  RegLocation rl_src[3];
-  RegLocation rl_dest = mir_graph_->GetBadLoc();
-  Instruction::Code opcode = mir->dalvikInsn.opcode;
-  int op_val = opcode;
-  uint32_t vB = mir->dalvikInsn.vB;
-  uint32_t vC = mir->dalvikInsn.vC;
-  int opt_flags = mir->optimization_flags;
-
-  if (cu_->verbose) {
-    if (!IsPseudoMirOp(op_val)) {
-      LOG(INFO) << ".. " << Instruction::Name(opcode) << " 0x" << std::hex << op_val;
-    } else {
-      LOG(INFO) << mir_graph_->extended_mir_op_names_[op_val - kMirOpFirst] << " 0x" << std::hex << op_val;
-    }
-  }
-
-  /* Prep Src and Dest locations */
-  int next_sreg = 0;
-  int next_loc = 0;
-  uint64_t attrs = MirGraph::GetDataFlowAttributes(opcode);
-  rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
-  if (attrs & DF_UA) {
-    if (attrs & DF_A_WIDE) {
-      rl_src[next_loc++] = mir_graph_->GetSrcWide(mir, next_sreg);
-      next_sreg+= 2;
-    } else {
-      rl_src[next_loc++] = mir_graph_->GetSrc(mir, next_sreg);
-      next_sreg++;
-    }
-  }
-  if (attrs & DF_UB) {
-    if (attrs & DF_B_WIDE) {
-      rl_src[next_loc++] = mir_graph_->GetSrcWide(mir, next_sreg);
-      next_sreg+= 2;
-    } else {
-      rl_src[next_loc++] = mir_graph_->GetSrc(mir, next_sreg);
-      next_sreg++;
-    }
-  }
-  if (attrs & DF_UC) {
-    if (attrs & DF_C_WIDE) {
-      rl_src[next_loc++] = mir_graph_->GetSrcWide(mir, next_sreg);
-    } else {
-      rl_src[next_loc++] = mir_graph_->GetSrc(mir, next_sreg);
-    }
-  }
-  if (attrs & DF_DA) {
-    if (attrs & DF_A_WIDE) {
-      rl_dest = mir_graph_->GetDestWide(mir);
-    } else {
-      rl_dest = mir_graph_->GetDest(mir);
-    }
-  }
-
-  switch (opcode) {
-    case Instruction::NOP:
-      break;
-
-    case Instruction::MOVE:
-    case Instruction::MOVE_OBJECT:
-    case Instruction::MOVE_16:
-    case Instruction::MOVE_OBJECT_16:
-    case Instruction::MOVE_OBJECT_FROM16:
-    case Instruction::MOVE_FROM16:
-    case Instruction::MOVE_WIDE:
-    case Instruction::MOVE_WIDE_16:
-    case Instruction::MOVE_WIDE_FROM16: {
-        /*
-         * Moves/copies are meaningless in pure SSA register form,
-         * but we need to preserve them for the conversion back into
-         * MIR (at least until we stop using the Dalvik register maps).
-         * Insert a dummy intrinsic copy call, which will be recognized
-         * by the quick path and removed by the portable path.
-         */
-        ::llvm::Value* src = GetLLVMValue(rl_src[0].orig_sreg);
-        ::llvm::Value* res = EmitCopy(src, rl_dest);
-        DefineValue(res, rl_dest.orig_sreg);
-      }
-      break;
-
-    case Instruction::CONST:
-    case Instruction::CONST_4:
-    case Instruction::CONST_16: {
-        ::llvm::Constant* imm_value = irb_->getJInt(vB);
-        ::llvm::Value* res = EmitConst(imm_value, rl_dest);
-        DefineValue(res, rl_dest.orig_sreg);
-      }
-      break;
-
-    case Instruction::CONST_WIDE_16:
-    case Instruction::CONST_WIDE_32: {
-        // Sign extend to 64 bits
-        int64_t imm = static_cast<int32_t>(vB);
-        ::llvm::Constant* imm_value = irb_->getJLong(imm);
-        ::llvm::Value* res = EmitConst(imm_value, rl_dest);
-        DefineValue(res, rl_dest.orig_sreg);
-      }
-      break;
-
-    case Instruction::CONST_HIGH16: {
-        ::llvm::Constant* imm_value = irb_->getJInt(vB << 16);
-        ::llvm::Value* res = EmitConst(imm_value, rl_dest);
-        DefineValue(res, rl_dest.orig_sreg);
-      }
-      break;
-
-    case Instruction::CONST_WIDE: {
-        ::llvm::Constant* imm_value =
-            irb_->getJLong(mir->dalvikInsn.vB_wide);
-        ::llvm::Value* res = EmitConst(imm_value, rl_dest);
-        DefineValue(res, rl_dest.orig_sreg);
-      }
-      break;
-    case Instruction::CONST_WIDE_HIGH16: {
-        int64_t imm = static_cast<int64_t>(vB) << 48;
-        ::llvm::Constant* imm_value = irb_->getJLong(imm);
-        ::llvm::Value* res = EmitConst(imm_value, rl_dest);
-        DefineValue(res, rl_dest.orig_sreg);
-      }
-      break;
-
-    case Instruction::SPUT_OBJECT:
-      ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputObject,
-                  rl_src[0]);
-      break;
-    case Instruction::SPUT:
-      if (rl_src[0].fp) {
-        ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputFloat,
-                    rl_src[0]);
-      } else {
-        ConvertSput(vB, art::llvm::IntrinsicHelper::HLSput, rl_src[0]);
-      }
-      break;
-    case Instruction::SPUT_BOOLEAN:
-      ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputBoolean,
-                  rl_src[0]);
-      break;
-    case Instruction::SPUT_BYTE:
-      ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputByte, rl_src[0]);
-      break;
-    case Instruction::SPUT_CHAR:
-      ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputChar, rl_src[0]);
-      break;
-    case Instruction::SPUT_SHORT:
-      ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputShort, rl_src[0]);
-      break;
-    case Instruction::SPUT_WIDE:
-      if (rl_src[0].fp) {
-        ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputDouble,
-                    rl_src[0]);
-      } else {
-        ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputWide,
-                    rl_src[0]);
-      }
-      break;
-
-    case Instruction::SGET_OBJECT:
-      ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetObject, rl_dest);
-      break;
-    case Instruction::SGET:
-      if (rl_dest.fp) {
-        ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetFloat, rl_dest);
-      } else {
-        ConvertSget(vB, art::llvm::IntrinsicHelper::HLSget, rl_dest);
-      }
-      break;
-    case Instruction::SGET_BOOLEAN:
-      ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetBoolean, rl_dest);
-      break;
-    case Instruction::SGET_BYTE:
-      ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetByte, rl_dest);
-      break;
-    case Instruction::SGET_CHAR:
-      ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetChar, rl_dest);
-      break;
-    case Instruction::SGET_SHORT:
-      ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetShort, rl_dest);
-      break;
-    case Instruction::SGET_WIDE:
-      if (rl_dest.fp) {
-        ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetDouble,
-                    rl_dest);
-      } else {
-        ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetWide, rl_dest);
-      }
-      break;
-
-    case Instruction::RETURN_WIDE:
-    case Instruction::RETURN:
-    case Instruction::RETURN_OBJECT: {
-        if (!mir_graph_->MethodIsLeaf()) {
-          EmitSuspendCheck();
-        }
-        EmitPopShadowFrame();
-        irb_->CreateRet(GetLLVMValue(rl_src[0].orig_sreg));
-        DCHECK(bb->terminated_by_return);
-      }
-      break;
-
-    case Instruction::RETURN_VOID: {
-        if (((cu_->access_flags & kAccConstructor) != 0) &&
-            cu_->compiler_driver->RequiresConstructorBarrier(Thread::Current(),
-                                                            cu_->dex_file,
-                                                            cu_->class_def_idx)) {
-          EmitConstructorBarrier();
-        }
-        if (!mir_graph_->MethodIsLeaf()) {
-          EmitSuspendCheck();
-        }
-        EmitPopShadowFrame();
-        irb_->CreateRetVoid();
-        DCHECK(bb->terminated_by_return);
-      }
-      break;
-
-    case Instruction::IF_EQ:
-      ConvertCompareAndBranch(bb, mir, kCondEq, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::IF_NE:
-      ConvertCompareAndBranch(bb, mir, kCondNe, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::IF_LT:
-      ConvertCompareAndBranch(bb, mir, kCondLt, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::IF_GE:
-      ConvertCompareAndBranch(bb, mir, kCondGe, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::IF_GT:
-      ConvertCompareAndBranch(bb, mir, kCondGt, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::IF_LE:
-      ConvertCompareAndBranch(bb, mir, kCondLe, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::IF_EQZ:
-      ConvertCompareZeroAndBranch(bb, mir, kCondEq, rl_src[0]);
-      break;
-    case Instruction::IF_NEZ:
-      ConvertCompareZeroAndBranch(bb, mir, kCondNe, rl_src[0]);
-      break;
-    case Instruction::IF_LTZ:
-      ConvertCompareZeroAndBranch(bb, mir, kCondLt, rl_src[0]);
-      break;
-    case Instruction::IF_GEZ:
-      ConvertCompareZeroAndBranch(bb, mir, kCondGe, rl_src[0]);
-      break;
-    case Instruction::IF_GTZ:
-      ConvertCompareZeroAndBranch(bb, mir, kCondGt, rl_src[0]);
-      break;
-    case Instruction::IF_LEZ:
-      ConvertCompareZeroAndBranch(bb, mir, kCondLe, rl_src[0]);
-      break;
-
-    case Instruction::GOTO:
-    case Instruction::GOTO_16:
-    case Instruction::GOTO_32: {
-        if (mir_graph_->GetBasicBlock(bb->taken)->start_offset <= bb->start_offset) {
-          EmitSuspendCheck();
-        }
-        irb_->CreateBr(GetLLVMBlock(bb->taken));
-      }
-      break;
-
-    case Instruction::ADD_LONG:
-    case Instruction::ADD_LONG_2ADDR:
-    case Instruction::ADD_INT:
-    case Instruction::ADD_INT_2ADDR:
-      ConvertArithOp(kOpAdd, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::SUB_LONG:
-    case Instruction::SUB_LONG_2ADDR:
-    case Instruction::SUB_INT:
-    case Instruction::SUB_INT_2ADDR:
-      ConvertArithOp(kOpSub, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::MUL_LONG:
-    case Instruction::MUL_LONG_2ADDR:
-    case Instruction::MUL_INT:
-    case Instruction::MUL_INT_2ADDR:
-      ConvertArithOp(kOpMul, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::DIV_LONG:
-    case Instruction::DIV_LONG_2ADDR:
-    case Instruction::DIV_INT:
-    case Instruction::DIV_INT_2ADDR:
-      ConvertArithOp(kOpDiv, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::REM_LONG:
-    case Instruction::REM_LONG_2ADDR:
-    case Instruction::REM_INT:
-    case Instruction::REM_INT_2ADDR:
-      ConvertArithOp(kOpRem, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::AND_LONG:
-    case Instruction::AND_LONG_2ADDR:
-    case Instruction::AND_INT:
-    case Instruction::AND_INT_2ADDR:
-      ConvertArithOp(kOpAnd, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::OR_LONG:
-    case Instruction::OR_LONG_2ADDR:
-    case Instruction::OR_INT:
-    case Instruction::OR_INT_2ADDR:
-      ConvertArithOp(kOpOr, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::XOR_LONG:
-    case Instruction::XOR_LONG_2ADDR:
-    case Instruction::XOR_INT:
-    case Instruction::XOR_INT_2ADDR:
-      ConvertArithOp(kOpXor, rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::SHL_LONG:
-    case Instruction::SHL_LONG_2ADDR:
-      ConvertShift(art::llvm::IntrinsicHelper::SHLLong,
-                    rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::SHL_INT:
-    case Instruction::SHL_INT_2ADDR:
-      ConvertShift(art::llvm::IntrinsicHelper::SHLInt,
-                   rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::SHR_LONG:
-    case Instruction::SHR_LONG_2ADDR:
-      ConvertShift(art::llvm::IntrinsicHelper::SHRLong,
-                   rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::SHR_INT:
-    case Instruction::SHR_INT_2ADDR:
-      ConvertShift(art::llvm::IntrinsicHelper::SHRInt,
-                   rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::USHR_LONG:
-    case Instruction::USHR_LONG_2ADDR:
-      ConvertShift(art::llvm::IntrinsicHelper::USHRLong,
-                   rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::USHR_INT:
-    case Instruction::USHR_INT_2ADDR:
-      ConvertShift(art::llvm::IntrinsicHelper::USHRInt,
-                   rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::ADD_INT_LIT16:
-    case Instruction::ADD_INT_LIT8:
-      ConvertArithOpLit(kOpAdd, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::RSUB_INT:
-    case Instruction::RSUB_INT_LIT8:
-      ConvertArithOpLit(kOpRsub, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::MUL_INT_LIT16:
-    case Instruction::MUL_INT_LIT8:
-      ConvertArithOpLit(kOpMul, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::DIV_INT_LIT16:
-    case Instruction::DIV_INT_LIT8:
-      ConvertArithOpLit(kOpDiv, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::REM_INT_LIT16:
-    case Instruction::REM_INT_LIT8:
-      ConvertArithOpLit(kOpRem, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::AND_INT_LIT16:
-    case Instruction::AND_INT_LIT8:
-      ConvertArithOpLit(kOpAnd, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::OR_INT_LIT16:
-    case Instruction::OR_INT_LIT8:
-      ConvertArithOpLit(kOpOr, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::XOR_INT_LIT16:
-    case Instruction::XOR_INT_LIT8:
-      ConvertArithOpLit(kOpXor, rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::SHL_INT_LIT8:
-      ConvertShiftLit(art::llvm::IntrinsicHelper::SHLInt,
-                      rl_dest, rl_src[0], vC & 0x1f);
-      break;
-    case Instruction::SHR_INT_LIT8:
-      ConvertShiftLit(art::llvm::IntrinsicHelper::SHRInt,
-                      rl_dest, rl_src[0], vC & 0x1f);
-      break;
-    case Instruction::USHR_INT_LIT8:
-      ConvertShiftLit(art::llvm::IntrinsicHelper::USHRInt,
-                      rl_dest, rl_src[0], vC & 0x1f);
-      break;
-
-    case Instruction::ADD_FLOAT:
-    case Instruction::ADD_FLOAT_2ADDR:
-    case Instruction::ADD_DOUBLE:
-    case Instruction::ADD_DOUBLE_2ADDR:
-      ConvertFPArithOp(kOpAdd, rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::SUB_FLOAT:
-    case Instruction::SUB_FLOAT_2ADDR:
-    case Instruction::SUB_DOUBLE:
-    case Instruction::SUB_DOUBLE_2ADDR:
-      ConvertFPArithOp(kOpSub, rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::MUL_FLOAT:
-    case Instruction::MUL_FLOAT_2ADDR:
-    case Instruction::MUL_DOUBLE:
-    case Instruction::MUL_DOUBLE_2ADDR:
-      ConvertFPArithOp(kOpMul, rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::DIV_FLOAT:
-    case Instruction::DIV_FLOAT_2ADDR:
-    case Instruction::DIV_DOUBLE:
-    case Instruction::DIV_DOUBLE_2ADDR:
-      ConvertFPArithOp(kOpDiv, rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::REM_FLOAT:
-    case Instruction::REM_FLOAT_2ADDR:
-    case Instruction::REM_DOUBLE:
-    case Instruction::REM_DOUBLE_2ADDR:
-      ConvertFPArithOp(kOpRem, rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::INVOKE_STATIC:
-      ConvertInvoke(bb, mir, kStatic, false /*range*/,
-                    false /* NewFilledArray */);
-      break;
-    case Instruction::INVOKE_STATIC_RANGE:
-      ConvertInvoke(bb, mir, kStatic, true /*range*/,
-                    false /* NewFilledArray */);
-      break;
-
-    case Instruction::INVOKE_DIRECT:
-      ConvertInvoke(bb,  mir, kDirect, false /*range*/,
-                    false /* NewFilledArray */);
-      break;
-    case Instruction::INVOKE_DIRECT_RANGE:
-      ConvertInvoke(bb, mir, kDirect, true /*range*/,
-                    false /* NewFilledArray */);
-      break;
-
-    case Instruction::INVOKE_VIRTUAL:
-      ConvertInvoke(bb, mir, kVirtual, false /*range*/,
-                    false /* NewFilledArray */);
-      break;
-    case Instruction::INVOKE_VIRTUAL_RANGE:
-      ConvertInvoke(bb, mir, kVirtual, true /*range*/,
-                    false /* NewFilledArray */);
-      break;
-
-    case Instruction::INVOKE_SUPER:
-      ConvertInvoke(bb, mir, kSuper, false /*range*/,
-                    false /* NewFilledArray */);
-      break;
-    case Instruction::INVOKE_SUPER_RANGE:
-      ConvertInvoke(bb, mir, kSuper, true /*range*/,
-                    false /* NewFilledArray */);
-      break;
-
-    case Instruction::INVOKE_INTERFACE:
-      ConvertInvoke(bb, mir, kInterface, false /*range*/,
-                    false /* NewFilledArray */);
-      break;
-    case Instruction::INVOKE_INTERFACE_RANGE:
-      ConvertInvoke(bb, mir, kInterface, true /*range*/,
-                    false /* NewFilledArray */);
-      break;
-    case Instruction::FILLED_NEW_ARRAY:
-      ConvertInvoke(bb, mir, kInterface, false /*range*/,
-                    true /* NewFilledArray */);
-      break;
-    case Instruction::FILLED_NEW_ARRAY_RANGE:
-      ConvertInvoke(bb, mir, kInterface, true /*range*/,
-                    true /* NewFilledArray */);
-      break;
-
-    case Instruction::CONST_STRING:
-    case Instruction::CONST_STRING_JUMBO:
-      ConvertConstObject(vB, art::llvm::IntrinsicHelper::ConstString,
-                         rl_dest);
-      break;
-
-    case Instruction::CONST_CLASS:
-      ConvertConstObject(vB, art::llvm::IntrinsicHelper::ConstClass,
-                         rl_dest);
-      break;
-
-    case Instruction::CHECK_CAST:
-      ConvertCheckCast(vB, rl_src[0]);
-      break;
-
-    case Instruction::NEW_INSTANCE:
-      ConvertNewInstance(vB, rl_dest);
-      break;
-
-    case Instruction::MOVE_EXCEPTION:
-      ConvertMoveException(rl_dest);
-      break;
-
-    case Instruction::THROW:
-      ConvertThrow(rl_src[0]);
-      /*
-       * If this throw is standalone, terminate.
-       * If it might rethrow, force termination
-       * of the following block.
-       */
-      if (bb->fall_through == NullBasicBlockId) {
-        irb_->CreateUnreachable();
-      } else {
-        mir_graph_->GetBasicBlock(bb->fall_through)->fall_through = NullBasicBlockId;
-        mir_graph_->GetBasicBlock(bb->fall_through)->taken = NullBasicBlockId;
-      }
-      break;
-
-    case Instruction::MOVE_RESULT_WIDE:
-    case Instruction::MOVE_RESULT:
-    case Instruction::MOVE_RESULT_OBJECT:
-      /*
-       * All move_results should have been folded into the preceeding invoke.
-       */
-      LOG(FATAL) << "Unexpected move_result";
-      break;
-
-    case Instruction::MONITOR_ENTER:
-      ConvertMonitorEnterExit(opt_flags,
-                              art::llvm::IntrinsicHelper::MonitorEnter,
-                              rl_src[0]);
-      break;
-
-    case Instruction::MONITOR_EXIT:
-      ConvertMonitorEnterExit(opt_flags,
-                              art::llvm::IntrinsicHelper::MonitorExit,
-                              rl_src[0]);
-      break;
-
-    case Instruction::ARRAY_LENGTH:
-      ConvertArrayLength(opt_flags, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::NEW_ARRAY:
-      ConvertNewArray(vC, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::INSTANCE_OF:
-      ConvertInstanceOf(vC, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::AGET:
-      if (rl_dest.fp) {
-        ConvertAget(opt_flags,
-                    art::llvm::IntrinsicHelper::HLArrayGetFloat,
-                    rl_dest, rl_src[0], rl_src[1]);
-      } else {
-        ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGet,
-                    rl_dest, rl_src[0], rl_src[1]);
-      }
-      break;
-    case Instruction::AGET_OBJECT:
-      ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetObject,
-                  rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::AGET_BOOLEAN:
-      ConvertAget(opt_flags,
-                  art::llvm::IntrinsicHelper::HLArrayGetBoolean,
-                  rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::AGET_BYTE:
-      ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetByte,
-                  rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::AGET_CHAR:
-      ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetChar,
-                  rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::AGET_SHORT:
-      ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetShort,
-                  rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::AGET_WIDE:
-      if (rl_dest.fp) {
-        ConvertAget(opt_flags,
-                    art::llvm::IntrinsicHelper::HLArrayGetDouble,
-                    rl_dest, rl_src[0], rl_src[1]);
-      } else {
-        ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetWide,
-                    rl_dest, rl_src[0], rl_src[1]);
-      }
-      break;
-
-    case Instruction::APUT:
-      if (rl_src[0].fp) {
-        ConvertAput(opt_flags,
-                    art::llvm::IntrinsicHelper::HLArrayPutFloat,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      } else {
-        ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPut,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      }
-      break;
-    case Instruction::APUT_OBJECT:
-      ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutObject,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      break;
-    case Instruction::APUT_BOOLEAN:
-      ConvertAput(opt_flags,
-                  art::llvm::IntrinsicHelper::HLArrayPutBoolean,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      break;
-    case Instruction::APUT_BYTE:
-      ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutByte,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      break;
-    case Instruction::APUT_CHAR:
-      ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutChar,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      break;
-    case Instruction::APUT_SHORT:
-      ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutShort,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      break;
-    case Instruction::APUT_WIDE:
-      if (rl_src[0].fp) {
-        ConvertAput(opt_flags,
-                    art::llvm::IntrinsicHelper::HLArrayPutDouble,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      } else {
-        ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutWide,
-                    rl_src[0], rl_src[1], rl_src[2]);
-      }
-      break;
-
-    case Instruction::IGET:
-      if (rl_dest.fp) {
-        ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetFloat,
-                    rl_dest, rl_src[0], vC);
-      } else {
-        ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGet,
-                    rl_dest, rl_src[0], vC);
-      }
-      break;
-    case Instruction::IGET_OBJECT:
-      ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetObject,
-                  rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::IGET_BOOLEAN:
-      ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetBoolean,
-                  rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::IGET_BYTE:
-      ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetByte,
-                  rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::IGET_CHAR:
-      ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetChar,
-                  rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::IGET_SHORT:
-      ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetShort,
-                  rl_dest, rl_src[0], vC);
-      break;
-    case Instruction::IGET_WIDE:
-      if (rl_dest.fp) {
-        ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetDouble,
-                    rl_dest, rl_src[0], vC);
-      } else {
-        ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetWide,
-                    rl_dest, rl_src[0], vC);
-      }
-      break;
-    case Instruction::IPUT:
-      if (rl_src[0].fp) {
-        ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutFloat,
-                    rl_src[0], rl_src[1], vC);
-      } else {
-        ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPut,
-                    rl_src[0], rl_src[1], vC);
-      }
-      break;
-    case Instruction::IPUT_OBJECT:
-      ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutObject,
-                  rl_src[0], rl_src[1], vC);
-      break;
-    case Instruction::IPUT_BOOLEAN:
-      ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutBoolean,
-                  rl_src[0], rl_src[1], vC);
-      break;
-    case Instruction::IPUT_BYTE:
-      ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutByte,
-                  rl_src[0], rl_src[1], vC);
-      break;
-    case Instruction::IPUT_CHAR:
-      ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutChar,
-                  rl_src[0], rl_src[1], vC);
-      break;
-    case Instruction::IPUT_SHORT:
-      ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutShort,
-                  rl_src[0], rl_src[1], vC);
-      break;
-    case Instruction::IPUT_WIDE:
-      if (rl_src[0].fp) {
-        ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutDouble,
-                    rl_src[0], rl_src[1], vC);
-      } else {
-        ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutWide,
-                    rl_src[0], rl_src[1], vC);
-      }
-      break;
-
-    case Instruction::FILL_ARRAY_DATA:
-      ConvertFillArrayData(vB, rl_src[0]);
-      break;
-
-    case Instruction::LONG_TO_INT:
-      ConvertLongToInt(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::INT_TO_LONG:
-      ConvertIntToLong(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::INT_TO_CHAR:
-      ConvertIntNarrowing(rl_dest, rl_src[0],
-                          art::llvm::IntrinsicHelper::IntToChar);
-      break;
-    case Instruction::INT_TO_BYTE:
-      ConvertIntNarrowing(rl_dest, rl_src[0],
-                          art::llvm::IntrinsicHelper::IntToByte);
-      break;
-    case Instruction::INT_TO_SHORT:
-      ConvertIntNarrowing(rl_dest, rl_src[0],
-                          art::llvm::IntrinsicHelper::IntToShort);
-      break;
-
-    case Instruction::INT_TO_FLOAT:
-    case Instruction::LONG_TO_FLOAT:
-      ConvertIntToFP(irb_->getFloatTy(), rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::INT_TO_DOUBLE:
-    case Instruction::LONG_TO_DOUBLE:
-      ConvertIntToFP(irb_->getDoubleTy(), rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::FLOAT_TO_DOUBLE:
-      ConvertFloatToDouble(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::DOUBLE_TO_FLOAT:
-      ConvertDoubleToFloat(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::NEG_LONG:
-    case Instruction::NEG_INT:
-      ConvertNeg(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::NEG_FLOAT:
-    case Instruction::NEG_DOUBLE:
-      ConvertNegFP(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::NOT_LONG:
-    case Instruction::NOT_INT:
-      ConvertNot(rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::FLOAT_TO_INT:
-      ConvertFPToInt(art::llvm::IntrinsicHelper::F2I, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::DOUBLE_TO_INT:
-      ConvertFPToInt(art::llvm::IntrinsicHelper::D2I, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::FLOAT_TO_LONG:
-      ConvertFPToInt(art::llvm::IntrinsicHelper::F2L, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::DOUBLE_TO_LONG:
-      ConvertFPToInt(art::llvm::IntrinsicHelper::D2L, rl_dest, rl_src[0]);
-      break;
-
-    case Instruction::CMPL_FLOAT:
-      ConvertWideComparison(art::llvm::IntrinsicHelper::CmplFloat,
-                            rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::CMPG_FLOAT:
-      ConvertWideComparison(art::llvm::IntrinsicHelper::CmpgFloat,
-                            rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::CMPL_DOUBLE:
-      ConvertWideComparison(art::llvm::IntrinsicHelper::CmplDouble,
-                            rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::CMPG_DOUBLE:
-      ConvertWideComparison(art::llvm::IntrinsicHelper::CmpgDouble,
-                            rl_dest, rl_src[0], rl_src[1]);
-      break;
-    case Instruction::CMP_LONG:
-      ConvertWideComparison(art::llvm::IntrinsicHelper::CmpLong,
-                            rl_dest, rl_src[0], rl_src[1]);
-      break;
-
-    case Instruction::PACKED_SWITCH:
-      ConvertPackedSwitch(bb, vB, rl_src[0]);
-      break;
-
-    case Instruction::SPARSE_SWITCH:
-      ConvertSparseSwitch(bb, vB, rl_src[0]);
-      break;
-
-    default:
-      UNIMPLEMENTED(FATAL) << "Unsupported Dex opcode 0x" << std::hex << opcode;
-      res = true;
-  }
-  return res;
-}  // NOLINT(readability/fn_size)
-
-void MirConverter::SetDexOffset(int32_t offset) {
-  current_dalvik_offset_ = offset;
-  ::llvm::SmallVector< ::llvm::Value*, 1> array_ref;
-  array_ref.push_back(irb_->getInt32(offset));
-  ::llvm::MDNode* node = ::llvm::MDNode::get(*context_, array_ref);
-  irb_->SetDexOffset(node);
-}
-
-// Attach method info as metadata to special intrinsic
-void MirConverter::SetMethodInfo() {
-  // We don't want dex offset on this
-  irb_->SetDexOffset(NULL);
-  art::llvm::IntrinsicHelper::IntrinsicId id;
-  id = art::llvm::IntrinsicHelper::MethodInfo;
-  ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
-  ::llvm::Instruction* inst = irb_->CreateCall(intr);
-  ::llvm::SmallVector< ::llvm::Value*, 2> reg_info;
-  reg_info.push_back(irb_->getInt32(mir_graph_->GetNumOfInVRs()));
-  reg_info.push_back(irb_->getInt32(mir_graph_->GetNumOfLocalCodeVRs()));
-  reg_info.push_back(irb_->getInt32(mir_graph_->GetNumOfOutVRs()));
-  reg_info.push_back(irb_->getInt32(mir_graph_->GetNumUsedCompilerTemps()));
-  reg_info.push_back(irb_->getInt32(mir_graph_->GetNumSSARegs()));
-  ::llvm::MDNode* reg_info_node = ::llvm::MDNode::get(*context_, reg_info);
-  inst->setMetadata("RegInfo", reg_info_node);
-  SetDexOffset(current_dalvik_offset_);
-}
-
-void MirConverter::HandlePhiNodes(BasicBlock* bb, ::llvm::BasicBlock* llvm_bb) {
-  SetDexOffset(bb->start_offset);
-  for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
-    int opcode = mir->dalvikInsn.opcode;
-    if (!IsPseudoMirOp(opcode)) {
-      // Stop after first non-pseudo MIR op.
-      continue;
-    }
-    if (opcode != kMirOpPhi) {
-      // Skip other mir Pseudos.
-      continue;
-    }
-    RegLocation rl_dest = mir_graph_->reg_location_[mir->ssa_rep->defs[0]];
-    /*
-     * The Art compiler's Phi nodes only handle 32-bit operands,
-     * representing wide values using a matched set of Phi nodes
-     * for the lower and upper halves.  In the llvm world, we only
-     * want a single Phi for wides.  Here we will simply discard
-     * the Phi node representing the high word.
-     */
-    if (rl_dest.high_word) {
-      continue;  // No Phi node - handled via low word
-    }
-    BasicBlockId* incoming = mir->meta.phi_incoming;
-    ::llvm::Type* phi_type =
-        LlvmTypeFromLocRec(rl_dest);
-    ::llvm::PHINode* phi = irb_->CreatePHI(phi_type, mir->ssa_rep->num_uses);
-    for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
-      RegLocation loc;
-      // Don't check width here.
-      loc = mir_graph_->GetRawSrc(mir, i);
-      DCHECK_EQ(rl_dest.wide, loc.wide);
-      DCHECK_EQ(rl_dest.wide & rl_dest.high_word, loc.wide & loc.high_word);
-      DCHECK_EQ(rl_dest.fp, loc.fp);
-      DCHECK_EQ(rl_dest.core, loc.core);
-      DCHECK_EQ(rl_dest.ref, loc.ref);
-      SafeMap<unsigned int, unsigned int>::iterator it;
-      it = mir_graph_->block_id_map_.find(incoming[i]);
-      DCHECK(it != mir_graph_->block_id_map_.end());
-      DCHECK(GetLLVMValue(loc.orig_sreg) != NULL);
-      DCHECK(GetLLVMBlock(it->second) != NULL);
-      phi->addIncoming(GetLLVMValue(loc.orig_sreg),
-                       GetLLVMBlock(it->second));
-    }
-    DefineValueOnly(phi, rl_dest.orig_sreg);
-  }
-}
-
-/* Extended MIR instructions like PHI */
-void MirConverter::ConvertExtendedMIR(BasicBlock* bb, MIR* mir,
-                                      ::llvm::BasicBlock* llvm_bb) {
-  switch (static_cast<ExtendedMIROpcode>(mir->dalvikInsn.opcode)) {
-    case kMirOpPhi: {
-      // The llvm Phi node already emitted - just DefineValue() here.
-      RegLocation rl_dest = mir_graph_->reg_location_[mir->ssa_rep->defs[0]];
-      if (!rl_dest.high_word) {
-        // Only consider low word of pairs.
-        DCHECK(GetLLVMValue(rl_dest.orig_sreg) != NULL);
-        ::llvm::Value* phi = GetLLVMValue(rl_dest.orig_sreg);
-        if (1) SetVregOnValue(phi, rl_dest.orig_sreg);
-      }
-      break;
-    }
-    case kMirOpCopy: {
-      UNIMPLEMENTED(WARNING) << "unimp kMirOpPhi";
-      break;
-    }
-    case kMirOpNop:
-      if ((mir == bb->last_mir_insn) && (bb->taken == NullBasicBlockId) &&
-          (bb->fall_through == NullBasicBlockId)) {
-        irb_->CreateUnreachable();
-      }
-      break;
-
-    // TODO: need GBC intrinsic to take advantage of fused operations
-    case kMirOpFusedCmplFloat:
-      UNIMPLEMENTED(FATAL) << "kMirOpFusedCmpFloat unsupported";
-      break;
-    case kMirOpFusedCmpgFloat:
-      UNIMPLEMENTED(FATAL) << "kMirOpFusedCmgFloat unsupported";
-      break;
-    case kMirOpFusedCmplDouble:
-      UNIMPLEMENTED(FATAL) << "kMirOpFusedCmplDouble unsupported";
-      break;
-    case kMirOpFusedCmpgDouble:
-      UNIMPLEMENTED(FATAL) << "kMirOpFusedCmpgDouble unsupported";
-      break;
-    case kMirOpFusedCmpLong:
-      UNIMPLEMENTED(FATAL) << "kMirOpLongCmpBranch unsupported";
-      break;
-    default:
-      break;
-  }
-}
-
-/* Handle the content in each basic block */
-bool MirConverter::BlockBitcodeConversion(BasicBlock* bb) {
-  if (bb->block_type == kDead) return false;
-  ::llvm::BasicBlock* llvm_bb = GetLLVMBlock(bb->id);
-  if (llvm_bb == NULL) {
-    CHECK(bb->block_type == kExitBlock);
-  } else {
-    irb_->SetInsertPoint(llvm_bb);
-    SetDexOffset(bb->start_offset);
-  }
-
-  if (cu_->verbose) {
-    LOG(INFO) << "................................";
-    LOG(INFO) << "Block id " << bb->id;
-    if (llvm_bb != NULL) {
-      LOG(INFO) << "label " << llvm_bb->getName().str().c_str();
-    } else {
-      LOG(INFO) << "llvm_bb is NULL";
-    }
-  }
-
-  if (bb->block_type == kEntryBlock) {
-    SetMethodInfo();
-
-    {  // Allocate shadowframe.
-      art::llvm::IntrinsicHelper::IntrinsicId id =
-              art::llvm::IntrinsicHelper::AllocaShadowFrame;
-      ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(id);
-      ::llvm::Value* entries = irb_->getInt32(mir_graph_->GetNumOfCodeVRs());
-      irb_->CreateCall(func, entries);
-    }
-
-    {  // Store arguments to vregs.
-      uint16_t arg_reg = mir_graph_->GetFirstInVR();
-
-      ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
-
-      const char* shorty = cu_->shorty;
-      uint32_t shorty_size = strlen(shorty);
-      CHECK_GE(shorty_size, 1u);
-
-      ++arg_iter;  // skip method object
-
-      if ((cu_->access_flags & kAccStatic) == 0) {
-        SetVregOnValue(arg_iter, arg_reg);
-        ++arg_iter;
-        ++arg_reg;
-      }
-
-      for (uint32_t i = 1; i < shorty_size; ++i, ++arg_iter) {
-        SetVregOnValue(arg_iter, arg_reg);
-
-        ++arg_reg;
-        if (shorty[i] == 'J' || shorty[i] == 'D') {
-          // Wide types, such as long and double, are using a pair of registers
-          // to store the value, so we have to increase arg_reg again.
-          ++arg_reg;
-        }
-      }
-    }
-  } else if (bb->block_type == kExitBlock) {
-    /*
-     * Because of the differences between how MIR/LIR and llvm handle exit
-     * blocks, we won't explicitly covert them.  On the llvm-to-lir
-     * path, it will need to be regenereated.
-     */
-    return false;
-  } else if (bb->block_type == kExceptionHandling) {
-    /*
-     * Because we're deferring null checking, delete the associated empty
-     * exception block.
-     */
-    llvm_bb->eraseFromParent();
-    return false;
-  }
-
-  HandlePhiNodes(bb, llvm_bb);
-
-  for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
-    SetDexOffset(mir->offset);
-
-    int opcode = mir->dalvikInsn.opcode;
-    Instruction::Format dalvik_format =
-        Instruction::FormatOf(mir->dalvikInsn.opcode);
-
-    if (opcode == kMirOpCheck) {
-      // Combine check and work halves of throwing instruction.
-      MIR* work_half = mir->meta.throw_insn;
-      mir->dalvikInsn.opcode = work_half->dalvikInsn.opcode;
-      opcode = mir->dalvikInsn.opcode;
-      SSARepresentation* ssa_rep = work_half->ssa_rep;
-      work_half->ssa_rep = mir->ssa_rep;
-      mir->ssa_rep = ssa_rep;
-      work_half->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
-      if (bb->successor_block_list_type == kCatch) {
-        ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(
-            art::llvm::IntrinsicHelper::CatchTargets);
-        ::llvm::Value* switch_key =
-            irb_->CreateCall(intr, irb_->getInt32(mir->offset));
-        // New basic block to use for work half
-        ::llvm::BasicBlock* work_bb =
-            ::llvm::BasicBlock::Create(*context_, "", func_);
-        ::llvm::SwitchInst* sw =
-            irb_->CreateSwitch(switch_key, work_bb, bb->successor_blocks.size());
-        for (SuccessorBlockInfo *successor_block_info : bb->successor_blocks) {
-          ::llvm::BasicBlock *target =
-              GetLLVMBlock(successor_block_info->block);
-          int type_index = successor_block_info->key;
-          sw->addCase(irb_->getInt32(type_index), target);
-        }
-        llvm_bb = work_bb;
-        irb_->SetInsertPoint(llvm_bb);
-      }
-    }
-
-    if (IsPseudoMirOp(opcode)) {
-      ConvertExtendedMIR(bb, mir, llvm_bb);
-      continue;
-    }
-
-    bool not_handled = ConvertMIRNode(mir, bb, llvm_bb);
-    if (not_handled) {
-      Instruction::Code dalvik_opcode = static_cast<Instruction::Code>(opcode);
-      LOG(WARNING) << StringPrintf("%#06x: Op %#x (%s) / Fmt %d not handled",
-                                   mir->offset, opcode,
-                                   Instruction::Name(dalvik_opcode),
-                                   dalvik_format);
-    }
-  }
-
-  if (bb->block_type == kEntryBlock) {
-    entry_target_bb_ = GetLLVMBlock(bb->fall_through);
-  } else if ((bb->fall_through != NullBasicBlockId) && !bb->terminated_by_return) {
-    irb_->CreateBr(GetLLVMBlock(bb->fall_through));
-  }
-
-  return false;
-}
-
-char RemapShorty(char shorty_type) {
-  /*
-   * TODO: might want to revisit this.  Dalvik registers are 32-bits wide,
-   * and longs/doubles are represented as a pair of registers.  When sub-word
-   * arguments (and method results) are passed, they are extended to Dalvik
-   * virtual register containers.  Because llvm is picky about type consistency,
-   * we must either cast the "real" type to 32-bit container multiple Dalvik
-   * register types, or always use the expanded values.
-   * Here, we're doing the latter.  We map the shorty signature to container
-   * types (which is valid so long as we always do a real expansion of passed
-   * arguments and field loads).
-   */
-  switch (shorty_type) {
-    case 'Z' : shorty_type = 'I'; break;
-    case 'B' : shorty_type = 'I'; break;
-    case 'S' : shorty_type = 'I'; break;
-    case 'C' : shorty_type = 'I'; break;
-    default: break;
-  }
-  return shorty_type;
-}
-
-::llvm::FunctionType* MirConverter::GetFunctionType() {
-  // Get return type
-  ::llvm::Type* ret_type = irb_->getJType(RemapShorty(cu_->shorty[0]));
-
-  // Get argument type
-  std::vector< ::llvm::Type*> args_type;
-
-  // method object
-  args_type.push_back(irb_->getJMethodTy());
-
-  // Do we have  a "this"?
-  if ((cu_->access_flags & kAccStatic) == 0) {
-    args_type.push_back(irb_->getJObjectTy());
-  }
-
-  for (uint32_t i = 1; i < strlen(cu_->shorty); ++i) {
-    args_type.push_back(irb_->getJType(RemapShorty(cu_->shorty[i])));
-  }
-
-  return ::llvm::FunctionType::get(ret_type, args_type, false);
-}
-
-bool MirConverter::CreateFunction() {
-  ::llvm::FunctionType* func_type = GetFunctionType();
-  if (func_type == NULL) {
-    return false;
-  }
-
-  func_ = ::llvm::Function::Create(func_type,
-                                      ::llvm::Function::InternalLinkage,
-                                      symbol_, module_);
-
-  ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
-  ::llvm::Function::arg_iterator arg_end(func_->arg_end());
-
-  arg_iter->setName("method");
-  ++arg_iter;
-
-  int start_sreg = mir_graph_->GetFirstInVR();
-
-  for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
-    arg_iter->setName(StringPrintf("v%i_0", start_sreg));
-    start_sreg += mir_graph_->reg_location_[start_sreg].wide ? 2 : 1;
-  }
-
-  return true;
-}
-
-bool MirConverter::CreateLLVMBasicBlock(BasicBlock* bb) {
-  // Skip the exit block
-  if ((bb->block_type == kDead) ||(bb->block_type == kExitBlock)) {
-    id_to_block_map_.Put(bb->id, NULL);
-  } else {
-    int offset = bb->start_offset;
-    bool entry_block = (bb->block_type == kEntryBlock);
-    ::llvm::BasicBlock* llvm_bb =
-        ::llvm::BasicBlock::Create(*context_, entry_block ? "entry" :
-                                 StringPrintf(kLabelFormat, bb->catch_entry ? kCatchBlock :
-                                              kNormalBlock, offset, bb->id), func_);
-    if (entry_block) {
-        entry_bb_ = llvm_bb;
-        placeholder_bb_ =
-            ::llvm::BasicBlock::Create(*context_, "placeholder",
-                                     func_);
-    }
-    id_to_block_map_.Put(bb->id, llvm_bb);
-  }
-  return false;
-}
-
-
-/*
- * Convert MIR to LLVM_IR
- *  o For each ssa name, create LLVM named value.  Type these
- *    appropriately, and ignore high half of wide and double operands.
- *  o For each MIR basic block, create an LLVM basic block.
- *  o Iterate through the MIR a basic block at a time, setting arguments
- *    to recovered ssa name.
- */
-void MirConverter::MethodMIR2Bitcode() {
-  InitIR();
-
-  // Create the function
-  CreateFunction();
-
-  // Create an LLVM basic block for each MIR block in dfs preorder
-  PreOrderDfsIterator iter(mir_graph_);
-  for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
-    CreateLLVMBasicBlock(bb);
-  }
-
-  /*
-   * Create an llvm named value for each MIR SSA name.  Note: we'll use
-   * placeholders for all non-argument values (because we haven't seen
-   * the definition yet).
-   */
-  irb_->SetInsertPoint(placeholder_bb_);
-  ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
-  arg_iter++;  /* Skip path method */
-  for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) {
-    ::llvm::Value* val;
-    RegLocation rl_temp = mir_graph_->reg_location_[i];
-    if ((mir_graph_->SRegToVReg(i) < 0) || rl_temp.high_word) {
-      llvm_values_.push_back(0);
-    } else if ((i < mir_graph_->GetFirstInVR()) ||
-               (i >= (mir_graph_->GetFirstTempVR()))) {
-      ::llvm::Constant* imm_value = mir_graph_->reg_location_[i].wide ?
-         irb_->getJLong(0) : irb_->getJInt(0);
-      val = EmitConst(imm_value, mir_graph_->reg_location_[i]);
-      val->setName(mir_graph_->GetSSAName(i));
-      llvm_values_.push_back(val);
-    } else {
-      // Recover previously-created argument values
-      ::llvm::Value* arg_val = arg_iter++;
-      llvm_values_.push_back(arg_val);
-    }
-  }
-
-  PreOrderDfsIterator iter2(mir_graph_);
-  for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) {
-    BlockBitcodeConversion(bb);
-  }
-
-  /*
-   * In a few rare cases of verification failure, the verifier will
-   * replace one or more Dalvik opcodes with the special
-   * throw-verification-failure opcode.  This can leave the SSA graph
-   * in an invalid state, as definitions may be lost, while uses retained.
-   * To work around this problem, we insert placeholder definitions for
-   * all Dalvik SSA regs in the "placeholder" block.  Here, after
-   * bitcode conversion is complete, we examine those placeholder definitions
-   * and delete any with no references (which normally is all of them).
-   *
-   * If any definitions remain, we link the placeholder block into the
-   * CFG.  Otherwise, it is deleted.
-   */
-  for (::llvm::BasicBlock::iterator it = placeholder_bb_->begin(),
-       it_end = placeholder_bb_->end(); it != it_end;) {
-    ::llvm::Instruction* inst = ::llvm::dyn_cast< ::llvm::Instruction>(it++);
-    DCHECK(inst != NULL);
-    ::llvm::Value* val = ::llvm::dyn_cast< ::llvm::Value>(inst);
-    DCHECK(val != NULL);
-    if (val->getNumUses() == 0) {
-      inst->eraseFromParent();
-    }
-  }
-  SetDexOffset(0);
-  if (placeholder_bb_->empty()) {
-    placeholder_bb_->eraseFromParent();
-  } else {
-    irb_->SetInsertPoint(placeholder_bb_);
-    irb_->CreateBr(entry_target_bb_);
-    entry_target_bb_ = placeholder_bb_;
-  }
-  irb_->SetInsertPoint(entry_bb_);
-  irb_->CreateBr(entry_target_bb_);
-
-  if (cu_->enable_debug & (1 << kDebugVerifyBitcode)) {
-     if (::llvm::verifyFunction(*func_, ::llvm::PrintMessageAction)) {
-       LOG(INFO) << "Bitcode verification FAILED for "
-                 << PrettyMethod(cu_->method_idx, *cu_->dex_file)
-                 << " of size " << mir_graph_->GetNumDalvikInsns();
-       cu_->enable_debug |= (1 << kDebugDumpBitcodeFile);
-     }
-  }
-
-  if (cu_->enable_debug & (1 << kDebugDumpBitcodeFile)) {
-    // Write bitcode to file
-    std::string errmsg;
-    std::string fname(PrettyMethod(cu_->method_idx, *cu_->dex_file));
-    mir_graph_->ReplaceSpecialChars(fname);
-    // TODO: make configurable change naming mechanism to avoid fname length issues.
-    fname = StringPrintf("/sdcard/Bitcode/%s.bc", fname.c_str());
-
-    if (fname.size() > 240) {
-      LOG(INFO) << "Warning: bitcode filename too long. Truncated.";
-      fname.resize(240);
-    }
-
-    ::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
-        new ::llvm::tool_output_file(fname.c_str(), errmsg,
-                                   ::llvm::sys::fs::F_Binary));
-
-    if (!errmsg.empty()) {
-      LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
-    }
-
-    ::llvm::WriteBitcodeToFile(module_, out_file->os());
-    out_file->keep();
-  }
-}
-
-Backend* PortableCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
-                               ArenaAllocator* const arena,
-                               llvm::LlvmCompilationUnit* const llvm_compilation_unit) {
-  return new MirConverter(cu, mir_graph, arena, llvm_compilation_unit);
-}
-
-}  // namespace art
diff --git a/compiler/dex/portable/mir_to_gbc.h b/compiler/dex/portable/mir_to_gbc.h
deleted file mode 100644
index 94ae3f7..0000000
--- a/compiler/dex/portable/mir_to_gbc.h
+++ /dev/null
@@ -1,241 +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.
- */
-
-#ifndef ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
-#define ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
-
-#include <llvm/ADT/ArrayRef.h>
-#include <llvm/IR/BasicBlock.h>
-#include <llvm/IR/IRBuilder.h>
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/IR/Module.h>
-
-#include "invoke_type.h"
-#include "compiled_method.h"
-#include "dex/compiler_enums.h"
-#include "dex/compiler_ir.h"
-#include "dex/backend.h"
-#include "llvm/intrinsic_helper.h"
-#include "llvm/llvm_compilation_unit.h"
-#include "safe_map.h"
-#include "utils/arena_containers.h"
-
-namespace llvm {
-  class Module;
-  class LLVMContext;
-}
-
-namespace art {
-
-namespace llvm {
-  class IntrinsicHelper;
-  class IRBuilder;
-}
-
-class LLVMInfo {
-  public:
-    LLVMInfo();
-    ~LLVMInfo();
-
-    ::llvm::LLVMContext* GetLLVMContext() {
-      return llvm_context_.get();
-    }
-
-    ::llvm::Module* GetLLVMModule() {
-      return llvm_module_;
-    }
-
-    art::llvm::IntrinsicHelper* GetIntrinsicHelper() {
-      return intrinsic_helper_.get();
-    }
-
-    art::llvm::IRBuilder* GetIRBuilder() {
-      return ir_builder_.get();
-    }
-
-  private:
-    std::unique_ptr< ::llvm::LLVMContext> llvm_context_;
-    ::llvm::Module* llvm_module_;  // Managed by context_.
-    std::unique_ptr<art::llvm::IntrinsicHelper> intrinsic_helper_;
-    std::unique_ptr<art::llvm::IRBuilder> ir_builder_;
-};
-
-struct BasicBlock;
-struct CallInfo;
-struct CompilationUnit;
-struct MIR;
-struct RegLocation;
-struct RegisterInfo;
-class MIRGraph;
-
-// Target-specific initialization.
-Backend* PortableCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
-                               ArenaAllocator* const arena,
-                               llvm::LlvmCompilationUnit* const llvm_compilation_unit);
-
-class MirConverter : public Backend {
-  public:
-    // TODO: flesh out and integrate into new world order.
-    MirConverter(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena,
-                 llvm::LlvmCompilationUnit* llvm_compilation_unit)
-      : Backend(arena),
-        cu_(cu),
-        mir_graph_(mir_graph),
-        llvm_compilation_unit_(llvm_compilation_unit),
-        llvm_info_(llvm_compilation_unit->GetQuickContext()),
-        symbol_(llvm_compilation_unit->GetDexCompilationUnit()->GetSymbol()),
-        context_(NULL),
-        module_(NULL),
-        func_(NULL),
-        intrinsic_helper_(NULL),
-        irb_(NULL),
-        placeholder_bb_(NULL),
-        entry_bb_(NULL),
-        entry_target_bb_(NULL),
-        llvm_values_(arena->Adapter()),
-        temp_name_(0),
-        current_dalvik_offset_(0) {
-      llvm_values_.reserve(mir_graph->GetNumSSARegs());
-      if (kIsDebugBuild) {
-        cu->enable_debug |= (1 << kDebugVerifyBitcode);
-      }
-    }
-
-    void Materialize() {
-      MethodMIR2Bitcode();
-    }
-
-    CompiledMethod* GetCompiledMethod() {
-      return NULL;
-    }
-
-  private:
-    ::llvm::BasicBlock* GetLLVMBlock(int id);
-    ::llvm::Value* GetLLVMValue(int s_reg);
-    void SetVregOnValue(::llvm::Value* val, int s_reg);
-    void DefineValueOnly(::llvm::Value* val, int s_reg);
-    void DefineValue(::llvm::Value* val, int s_reg);
-    ::llvm::Type* LlvmTypeFromLocRec(RegLocation loc);
-    void InitIR();
-    ::llvm::BasicBlock* FindCaseTarget(uint32_t vaddr);
-    void ConvertPackedSwitch(BasicBlock* bb, MIR* mir, int32_t table_offset,
-                             RegLocation rl_src);
-    void ConvertSparseSwitch(BasicBlock* bb, MIR* mir, int32_t table_offset,
-                             RegLocation rl_src);
-    void ConvertSget(int32_t field_index,
-                     art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest);
-    void ConvertSput(int32_t field_index,
-                     art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_src);
-    void ConvertFillArrayData(int32_t offset, RegLocation rl_array);
-    ::llvm::Value* EmitConst(::llvm::ArrayRef< ::llvm::Value*> src,
-                             RegLocation loc);
-    void EmitPopShadowFrame();
-    ::llvm::Value* EmitCopy(::llvm::ArrayRef< ::llvm::Value*> src,
-                            RegLocation loc);
-    void ConvertMoveException(RegLocation rl_dest);
-    void ConvertThrow(RegLocation rl_src);
-    void ConvertMonitorEnterExit(int opt_flags,
-                                 art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_src);
-    void ConvertArrayLength(int opt_flags, RegLocation rl_dest,
-                            RegLocation rl_src);
-    void EmitSuspendCheck();
-    ::llvm::Value* ConvertCompare(ConditionCode cc,
-                                  ::llvm::Value* src1, ::llvm::Value* src2);
-    void ConvertCompareAndBranch(BasicBlock* bb, MIR* mir, ConditionCode cc,
-                                 RegLocation rl_src1, RegLocation rl_src2);
-    void ConvertCompareZeroAndBranch(BasicBlock* bb, MIR* mir, ConditionCode cc,
-                                     RegLocation rl_src1);
-    ::llvm::Value* GenDivModOp(bool is_div, bool is_long, ::llvm::Value* src1,
-                               ::llvm::Value* src2);
-    ::llvm::Value* GenArithOp(OpKind op, bool is_long, ::llvm::Value* src1,
-                              ::llvm::Value* src2);
-    void ConvertFPArithOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
-                          RegLocation rl_src2);
-    void ConvertShift(art::llvm::IntrinsicHelper::IntrinsicId id,
-                      RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    void ConvertShiftLit(art::llvm::IntrinsicHelper::IntrinsicId id,
-                         RegLocation rl_dest, RegLocation rl_src, int shift_amount);
-    void ConvertArithOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
-                        RegLocation rl_src2);
-    void ConvertArithOpLit(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
-                           int32_t imm);
-    void ConvertInvoke(BasicBlock* bb, MIR* mir, InvokeType invoke_type,
-                       bool is_range, bool is_filled_new_array);
-    void ConvertConstObject(uint32_t idx,
-                            art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest);
-    void ConvertCheckCast(uint32_t type_idx, RegLocation rl_src);
-    void ConvertNewInstance(uint32_t type_idx, RegLocation rl_dest);
-    void ConvertNewArray(uint32_t type_idx, RegLocation rl_dest,
-                         RegLocation rl_src);
-    void ConvertAget(int opt_flags, art::llvm::IntrinsicHelper::IntrinsicId id,
-                     RegLocation rl_dest, RegLocation rl_array, RegLocation rl_index);
-    void ConvertAput(int opt_flags, art::llvm::IntrinsicHelper::IntrinsicId id,
-                     RegLocation rl_src, RegLocation rl_array, RegLocation rl_index);
-    void ConvertIget(int opt_flags, art::llvm::IntrinsicHelper::IntrinsicId id,
-                     RegLocation rl_dest, RegLocation rl_obj, int field_index);
-    void ConvertIput(int opt_flags, art::llvm::IntrinsicHelper::IntrinsicId id,
-                     RegLocation rl_src, RegLocation rl_obj, int field_index);
-    void ConvertInstanceOf(uint32_t type_idx, RegLocation rl_dest,
-                           RegLocation rl_src);
-    void ConvertIntToLong(RegLocation rl_dest, RegLocation rl_src);
-    void ConvertLongToInt(RegLocation rl_dest, RegLocation rl_src);
-    void ConvertFloatToDouble(RegLocation rl_dest, RegLocation rl_src);
-    void ConvertDoubleToFloat(RegLocation rl_dest, RegLocation rl_src);
-    void ConvertWideComparison(art::llvm::IntrinsicHelper::IntrinsicId id,
-                               RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    void ConvertIntNarrowing(RegLocation rl_dest, RegLocation rl_src,
-                             art::llvm::IntrinsicHelper::IntrinsicId id);
-    void ConvertNeg(RegLocation rl_dest, RegLocation rl_src);
-    void ConvertIntToFP(::llvm::Type* ty, RegLocation rl_dest, RegLocation rl_src);
-    void ConvertFPToInt(art::llvm::IntrinsicHelper::IntrinsicId id,
-                        RegLocation rl_dest, RegLocation rl_src);
-    void ConvertNegFP(RegLocation rl_dest, RegLocation rl_src);
-    void ConvertNot(RegLocation rl_dest, RegLocation rl_src);
-    void EmitConstructorBarrier();
-    bool ConvertMIRNode(MIR* mir, BasicBlock* bb, ::llvm::BasicBlock* llvm_bb);
-    void SetDexOffset(int32_t offset);
-    void SetMethodInfo();
-    void HandlePhiNodes(BasicBlock* bb, ::llvm::BasicBlock* llvm_bb);
-    void ConvertExtendedMIR(BasicBlock* bb, MIR* mir, ::llvm::BasicBlock* llvm_bb);
-    bool BlockBitcodeConversion(BasicBlock* bb);
-    ::llvm::FunctionType* GetFunctionType();
-    bool CreateFunction();
-    bool CreateLLVMBasicBlock(BasicBlock* bb);
-    void MethodMIR2Bitcode();
-
-    CompilationUnit* cu_;
-    MIRGraph* mir_graph_;
-    llvm::LlvmCompilationUnit* const llvm_compilation_unit_;
-    LLVMInfo* llvm_info_;
-    std::string symbol_;
-    ::llvm::LLVMContext* context_;
-    ::llvm::Module* module_;
-    ::llvm::Function* func_;
-    art::llvm::IntrinsicHelper* intrinsic_helper_;
-    art::llvm::IRBuilder* irb_;
-    ::llvm::BasicBlock* placeholder_bb_;
-    ::llvm::BasicBlock* entry_bb_;
-    ::llvm::BasicBlock* entry_target_bb_;
-    std::string bitcode_filename_;
-    ArenaVector< ::llvm::Value*> llvm_values_;
-    int32_t temp_name_;
-    SafeMap<int32_t, ::llvm::BasicBlock*> id_to_block_map_;  // block id -> llvm bb.
-    int current_dalvik_offset_;
-};  // Class MirConverter
-
-}  // namespace art
-
-#endif  // ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
diff --git a/compiler/dex/post_opt_passes.cc b/compiler/dex/post_opt_passes.cc
index 675dbcf..92078b4 100644
--- a/compiler/dex/post_opt_passes.cc
+++ b/compiler/dex/post_opt_passes.cc
@@ -20,35 +20,6 @@
 
 namespace art {
 
-/*
- * MethodUseCount pass implementation start.
- */
-bool MethodUseCount::Gate(const PassDataHolder* data) const {
-  DCHECK(data != nullptr);
-  CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
-  DCHECK(c_unit != nullptr);
-  // First initialize the data.
-  c_unit->mir_graph->InitializeMethodUses();
-
-  // Now check if the pass is to be ignored.
-  bool res = ((c_unit->disable_opt & (1 << kPromoteRegs)) == 0);
-
-  return res;
-}
-
-bool MethodUseCount::Worker(PassDataHolder* data) const {
-  DCHECK(data != nullptr);
-  PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
-  CompilationUnit* c_unit = pass_me_data_holder->c_unit;
-  DCHECK(c_unit != nullptr);
-  BasicBlock* bb = pass_me_data_holder->bb;
-  DCHECK(bb != nullptr);
-  c_unit->mir_graph->CountUses(bb);
-  // No need of repeating, so just return false.
-  return false;
-}
-
-
 bool ClearPhiInstructions::Worker(PassDataHolder* data) const {
   DCHECK(data != nullptr);
   PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
diff --git a/compiler/dex/post_opt_passes.h b/compiler/dex/post_opt_passes.h
index e7805ba..55ae874 100644
--- a/compiler/dex/post_opt_passes.h
+++ b/compiler/dex/post_opt_passes.h
@@ -24,13 +24,31 @@
 namespace art {
 
 /**
- * @class InitializeData
+ * @class PassMEMirSsaRep
+ * @brief Convenience class for passes that check MIRGraph::MirSsaRepUpToDate().
+ */
+class PassMEMirSsaRep : public PassME {
+ public:
+  PassMEMirSsaRep(const char* name, DataFlowAnalysisMode type = kAllNodes)
+      : PassME(name, type) {
+  }
+
+  bool Gate(const PassDataHolder* data) const OVERRIDE {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    return !c_unit->mir_graph->MirSsaRepUpToDate();
+  }
+};
+
+/**
+ * @class InitializeSSATransformation
  * @brief There is some data that needs to be initialized before performing
  * the post optimization passes.
  */
-class InitializeData : public PassME {
+class InitializeSSATransformation : public PassMEMirSsaRep {
  public:
-  InitializeData() : PassME("InitializeData") {
+  InitializeSSATransformation() : PassMEMirSsaRep("InitializeSSATransformation", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -39,32 +57,18 @@
     DCHECK(data != nullptr);
     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
     DCHECK(c_unit != nullptr);
-    c_unit->mir_graph.get()->InitializeBasicBlockData();
-    c_unit->mir_graph.get()->SSATransformationStart();
+    c_unit->mir_graph->SSATransformationStart();
+    c_unit->mir_graph->CompilerInitializeSSAConversion();
   }
 };
 
 /**
- * @class MethodUseCount
- * @brief Count the register uses of the method
- */
-class MethodUseCount : public PassME {
- public:
-  MethodUseCount() : PassME("UseCount") {
-  }
-
-  bool Worker(PassDataHolder* data) const;
-
-  bool Gate(const PassDataHolder* data) const;
-};
-
-/**
  * @class ClearPhiInformation
  * @brief Clear the PHI nodes from the CFG.
  */
-class ClearPhiInstructions : public PassME {
+class ClearPhiInstructions : public PassMEMirSsaRep {
  public:
-  ClearPhiInstructions() : PassME("ClearPhiInstructions") {
+  ClearPhiInstructions() : PassMEMirSsaRep("ClearPhiInstructions") {
   }
 
   bool Worker(PassDataHolder* data) const;
@@ -76,7 +80,7 @@
  */
 class CalculatePredecessors : public PassME {
  public:
-  CalculatePredecessors() : PassME("CalculatePredecessors") {
+  CalculatePredecessors() : PassME("CalculatePredecessors", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const;
@@ -88,7 +92,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,15 +116,21 @@
  */
 class BuildDomination : public PassME {
  public:
-  BuildDomination() : PassME("BuildDomination") {
+  BuildDomination() : PassME("BuildDomination", 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->DominationUpToDate();
   }
 
   void Start(PassDataHolder* data) const {
     DCHECK(data != nullptr);
     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
     DCHECK(c_unit != nullptr);
-    c_unit->mir_graph.get()->ComputeDominators();
-    c_unit->mir_graph.get()->CompilerInitializeSSAConversion();
+    c_unit->mir_graph->ComputeDominators();
   }
 
   void End(PassDataHolder* data) const {
@@ -133,7 +150,14 @@
  */
 class TopologicalSortOrders : public PassME {
  public:
-  TopologicalSortOrders() : PassME("TopologicalSortOrders") {
+  TopologicalSortOrders() : PassME("TopologicalSortOrders", 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->TopologicalOrderUpToDate();
   }
 
   void Start(PassDataHolder* data) const {
@@ -148,9 +172,9 @@
  * @class DefBlockMatrix
  * @brief Calculate the matrix of definition per basic block
  */
-class DefBlockMatrix : public PassME {
+class DefBlockMatrix : public PassMEMirSsaRep {
  public:
-  DefBlockMatrix() : PassME("DefBlockMatrix") {
+  DefBlockMatrix() : PassMEMirSsaRep("DefBlockMatrix", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -165,9 +189,9 @@
  * @class CreatePhiNodes
  * @brief Pass to create the phi nodes after SSA calculation
  */
-class CreatePhiNodes : public PassME {
+class CreatePhiNodes : public PassMEMirSsaRep {
  public:
-  CreatePhiNodes() : PassME("CreatePhiNodes") {
+  CreatePhiNodes() : PassMEMirSsaRep("CreatePhiNodes", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -179,30 +203,12 @@
 };
 
 /**
- * @class ClearVisitedFlag
- * @brief Pass to clear the visited flag for all basic blocks.
- */
-
-class ClearVisitedFlag : public PassME {
- public:
-  ClearVisitedFlag() : PassME("ClearVisitedFlag") {
-  }
-
-  void Start(PassDataHolder* data) const {
-    DCHECK(data != nullptr);
-    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
-    DCHECK(c_unit != nullptr);
-    c_unit->mir_graph.get()->ClearAllVisitedFlags();
-  }
-};
-
-/**
  * @class SSAConversion
  * @brief Pass for SSA conversion of MIRs
  */
-class SSAConversion : public PassME {
+class SSAConversion : public PassMEMirSsaRep {
  public:
-  SSAConversion() : PassME("SSAConversion") {
+  SSAConversion() : PassMEMirSsaRep("SSAConversion", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -210,6 +216,7 @@
     CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
     DCHECK(c_unit != nullptr);
     MIRGraph *mir_graph = c_unit->mir_graph.get();
+    mir_graph->ClearAllVisitedFlags();
     mir_graph->DoDFSPreOrderSSARename(mir_graph->GetEntryBlock());
   }
 };
@@ -218,9 +225,9 @@
  * @class PhiNodeOperands
  * @brief Pass to insert the Phi node operands to basic blocks
  */
-class PhiNodeOperands : public PassME {
+class PhiNodeOperands : public PassMEMirSsaRep {
  public:
-  PhiNodeOperands() : PassME("PhiNodeOperands", kPreOrderDFSTraversal) {
+  PhiNodeOperands() : PassMEMirSsaRep("PhiNodeOperands", kPreOrderDFSTraversal) {
   }
 
   bool Worker(PassDataHolder* data) const {
@@ -239,9 +246,9 @@
  * @class InitRegLocations
  * @brief Initialize Register Locations.
  */
-class PerformInitRegLocations : public PassME {
+class PerformInitRegLocations : public PassMEMirSsaRep {
  public:
-  PerformInitRegLocations() : PassME("PerformInitRegLocation") {
+  PerformInitRegLocations() : PassMEMirSsaRep("PerformInitRegLocation", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -253,40 +260,32 @@
 };
 
 /**
- * @class ConstantPropagation
- * @brief Perform a constant propagation pass.
+ * @class TypeInference
+ * @brief Type inference pass.
  */
-class ConstantPropagation : public PassME {
+class TypeInference : public PassMEMirSsaRep {
  public:
-  ConstantPropagation() : PassME("ConstantPropagation") {
+  TypeInference() : PassMEMirSsaRep("TypeInference", kRepeatingPreOrderDFSTraversal) {
   }
 
   bool Worker(PassDataHolder* data) const {
     DCHECK(data != nullptr);
-    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
+    PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
+    CompilationUnit* c_unit = pass_me_data_holder->c_unit;
     DCHECK(c_unit != nullptr);
-    BasicBlock* bb = down_cast<PassMEDataHolder*>(data)->bb;
+    BasicBlock* bb = pass_me_data_holder->bb;
     DCHECK(bb != nullptr);
-    c_unit->mir_graph->DoConstantPropagation(bb);
-    // No need of repeating, so just return false.
-    return false;
-  }
-
-  void Start(PassDataHolder* data) const {
-    DCHECK(data != nullptr);
-    CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
-    DCHECK(c_unit != nullptr);
-    c_unit->mir_graph->InitializeConstantPropagation();
+    return c_unit->mir_graph->InferTypes(bb);
   }
 };
 
 /**
- * @class FreeData
+ * @class FinishSSATransformation
  * @brief There is some data that needs to be freed after performing the post optimization passes.
  */
-class FreeData : public PassME {
+class FinishSSATransformation : public PassMEMirSsaRep {
  public:
-  FreeData() : PassME("FreeData") {
+  FinishSSATransformation() : PassMEMirSsaRep("FinishSSATransformation", kNoNodes) {
   }
 
   void End(PassDataHolder* data) const {
diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h
index d935bc3..5d09ae1 100644
--- a/compiler/dex/quick/arm/arm_lir.h
+++ b/compiler/dex/quick/arm/arm_lir.h
@@ -97,7 +97,7 @@
 // First FP callee save.
 #define ARM_FP_CALLEE_SAVE_BASE 16
 // Flag for using R4 to do suspend check
-#define ARM_R4_SUSPEND_FLAG
+// #define ARM_R4_SUSPEND_FLAG
 
 enum ArmResourceEncodingPos {
   kArmGPReg0   = 0,
@@ -109,7 +109,7 @@
   kArmRegEnd   = 48,
 };
 
-enum ArmNativeRegisterPool {
+enum ArmNativeRegisterPool {  // private marker to avoid generate-operator-out.py from processing.
   r0           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  0,
   r1           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  1,
   r2           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  2,
@@ -297,19 +297,20 @@
 constexpr RegStorage rs_dr31(RegStorage::kValid | dr31);
 #endif
 
-// RegisterLocation templates return values (r0, or r0/r1).
-const RegLocation arm_loc_c_return
-    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
-     RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG};
-const RegLocation arm_loc_c_return_wide
+// RegisterLocation templates return values (r0, r0/r1, s0, or d0).
+// Note: The return locations are shared between quick code and quick helper. This follows quick
+// ABI. Quick helper assembly routine needs to handle the ABI differences.
+const RegLocation arm_loc_c_return =
+    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r0, INVALID_SREG, INVALID_SREG};
+const RegLocation arm_loc_c_return_wide =
     {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
-     RegStorage(RegStorage::k64BitPair, r0, r1), INVALID_SREG, INVALID_SREG};
-const RegLocation arm_loc_c_return_float
-    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
-     RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG};
-const RegLocation arm_loc_c_return_double
-    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
-     RegStorage(RegStorage::k64BitPair, r0, r1), INVALID_SREG, INVALID_SREG};
+     RegStorage::MakeRegPair(rs_r0, rs_r1), INVALID_SREG, INVALID_SREG};
+const RegLocation arm_loc_c_return_float = kArm32QuickCodeUseSoftFloat
+    ? arm_loc_c_return
+    : RegLocation({kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, rs_fr0, INVALID_SREG, INVALID_SREG});
+const RegLocation arm_loc_c_return_double = kArm32QuickCodeUseSoftFloat
+    ? arm_loc_c_return_wide
+    : RegLocation({kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1, rs_dr0, INVALID_SREG, INVALID_SREG});
 
 enum ArmShiftEncodings {
   kArmLsl = 0x0,
@@ -480,13 +481,14 @@
   kThumb2LsrRRR,     // lsr [111110100010] rn[19..16] [1111] rd[11..8] [0000] rm[3..0].
   kThumb2AsrRRR,     // asr [111110100100] rn[19..16] [1111] rd[11..8] [0000] rm[3..0].
   kThumb2RorRRR,     // ror [111110100110] rn[19..16] [1111] rd[11..8] [0000] rm[3..0].
-  kThumb2LslRRI5,    // lsl [11101010010011110] imm[14.12] rd[11..8] [00] rm[3..0].
-  kThumb2LsrRRI5,    // lsr [11101010010011110] imm[14.12] rd[11..8] [01] rm[3..0].
-  kThumb2AsrRRI5,    // asr [11101010010011110] imm[14.12] rd[11..8] [10] rm[3..0].
-  kThumb2RorRRI5,    // ror [11101010010011110] imm[14.12] rd[11..8] [11] rm[3..0].
+  kThumb2LslRRI5,    // lsl [11101010010011110] imm3[14..12] rd[11..8] imm2[7..6] [00] rm[3..0].
+  kThumb2LsrRRI5,    // lsr [11101010010011110] imm3[14..12] rd[11..8] imm2[7..6] [01] rm[3..0].
+  kThumb2AsrRRI5,    // asr [11101010010011110] imm3[14..12] rd[11..8] imm2[7..6] [10] rm[3..0].
+  kThumb2RorRRI5,    // ror [11101010010011110] imm3[14..12] rd[11..8] imm2[7..6] [11] rm[3..0].
   kThumb2BicRRI8M,   // bic rd, rn, #<const> [11110] i [000010] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
   kThumb2AndRRI8M,   // and rd, rn, #<const> [11110] i [000000] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
   kThumb2OrrRRI8M,   // orr rd, rn, #<const> [11110] i [000100] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
+  kThumb2OrnRRI8M,   // orn rd, rn, #<const> [11110] i [000110] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
   kThumb2EorRRI8M,   // eor rd, rn, #<const> [11110] i [001000] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
   kThumb2AddRRI8M,   // add rd, rn, #<const> [11110] i [010001] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
   kThumb2AdcRRI8M,   // adc rd, rn, #<const> [11110] i [010101] rn[19..16] [0] imm3[14..12] rd[11..8] imm8[7..0].
@@ -510,7 +512,8 @@
   kThumb2Vnegs,      // vneg.f32 [111011101] D [110000] rd[15-12] [1010110] M [0] vm[3-0].
   kThumb2Vmovs_IMM8,  // vmov.f32 [111011101] D [11] imm4h[19-16] vd[15-12] [10100000] imm4l[3-0].
   kThumb2Vmovd_IMM8,  // vmov.f64 [111011101] D [11] imm4h[19-16] vd[15-12] [10110000] imm4l[3-0].
-  kThumb2Mla,        // mla [111110110000] rn[19-16] ra[15-12] rd[7-4] [0000] rm[3-0].
+  kThumb2Mla,        // mla [111110110000] rn[19-16] ra[15-12] rd[11-8] [0000] rm[3-0].
+  kThumb2Mls,        // mls [111110110000] rn[19-16] ra[15-12] rd[11-8] [0001] rm[3-0].
   kThumb2Umull,      // umull [111110111010] rn[19-16], rdlo[15-12] rdhi[11-8] [0000] rm[3-0].
   kThumb2Ldrex,      // ldrex [111010000101] rn[19-16] rt[15-12] [1111] imm8[7-0].
   kThumb2Ldrexd,     // ldrexd [111010001101] rn[19-16] rt[15-12] rt2[11-8] [11111111].
@@ -545,6 +548,7 @@
   kThumb2StrdI8,     // strd rt, rt2, [rn +-/1024].
   kArmLast,
 };
+std::ostream& operator<<(std::ostream& os, const ArmOpcode& rhs);
 
 enum ArmOpDmbOptions {
   kSY = 0xf,
@@ -576,6 +580,7 @@
   kFmtOff24,       // 24-bit Thumb2 unconditional branch encoding.
   kFmtSkip,        // Unused field, but continue to next.
 };
+std::ostream& operator<<(std::ostream& os, const ArmEncodingKind& rhs);
 
 // Struct used to define the snippet positions for each Thumb opcode.
 struct ArmEncodingMap {
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index cf34948..65fb3cd 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -671,12 +671,12 @@
                  kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0
-                 | IS_LOAD | NEEDS_FIXUP, "pop", "<!0R>", 4, kFixupPushPop),
+                 | IS_LOAD, "pop", "<!0R>", 4, kFixupNone),
     ENCODING_MAP(kThumb2Push,          0xe92d0000,
                  kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0
-                 | IS_STORE | NEEDS_FIXUP, "push", "<!0R>", 4, kFixupPushPop),
+                 | IS_STORE, "push", "<!0R>", 4, kFixupNone),
     ENCODING_MAP(kThumb2CmpRI8M, 0xf1b00f00,
                  kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1,
@@ -788,6 +788,10 @@
                  kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "orr", "!0C, !1C, #!2m", 4, kFixupNone),
+    ENCODING_MAP(kThumb2OrnRRI8M,  0xf0600000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "orn", "!0C, !1C, #!2m", 4, kFixupNone),
     ENCODING_MAP(kThumb2EorRRI8M,  0xf0800000,
                  kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
@@ -892,6 +896,10 @@
                  kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
                  kFmtBitBlt, 15, 12, IS_QUAD_OP | REG_DEF0_USE123,
                  "mla", "!0C, !1C, !2C, !3C", 4, kFixupNone),
+    ENCODING_MAP(kThumb2Mls,  0xfb000010,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 15, 12, IS_QUAD_OP | REG_DEF0_USE123,
+                 "mls", "!0C, !1C, !2C, !3C", 4, kFixupNone),
     ENCODING_MAP(kThumb2Umull,  0xfba00000,
                  kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16,
                  kFmtBitBlt, 3, 0,
@@ -1265,7 +1273,7 @@
           if (lir->operands[1] != rs_r15pc.GetReg()) {
             break;
           }
-          // NOTE: intentional fallthrough.
+          FALLTHROUGH_INTENDED;
         case kFixupLoad: {
           /*
            * PC-relative loads are mostly used to load immediates
@@ -1396,31 +1404,6 @@
           }
           break;
         }
-        case kFixupPushPop: {
-          if (__builtin_popcount(lir->operands[0]) == 1) {
-            /*
-             * The standard push/pop multiple instruction
-             * requires at least two registers in the list.
-             * If we've got just one, switch to the single-reg
-             * encoding.
-             */
-            lir->opcode = (lir->opcode == kThumb2Push) ? kThumb2Push1 :
-                kThumb2Pop1;
-            int reg = 0;
-            while (lir->operands[0]) {
-              if (lir->operands[0] & 0x1) {
-                break;
-              } else {
-                reg++;
-                lir->operands[0] >>= 1;
-              }
-            }
-            lir->operands[0] = reg;
-            // This won't change again, don't bother unlinking, just reset fixup kind
-            lir->flags.fixup = kFixupNone;
-          }
-          break;
-        }
         case kFixupCondBranch: {
           LIR *target_lir = lir->target;
           int32_t delta = 0;
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index b721e02..0713b7a 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -23,6 +23,7 @@
 #include "mirror/art_method.h"
 #include "mirror/object_array-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
+#include "utils.h"
 
 namespace art {
 
@@ -140,41 +141,6 @@
 }
 
 /*
- * Array data table format:
- *  ushort ident = 0x0300   magic value
- *  ushort width            width of each element in the table
- *  uint   size             number of elements in the table
- *  ubyte  data[size*width] table of data values (may contain a single-byte
- *                          padding at the end)
- *
- * Total size is 4+(width * size + 1)/2 16-bit code units.
- */
-void ArmMir2Lir::GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
-  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
-  // Add the table to the list - we'll process it later
-  FillArrayData *tab_rec =
-      static_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData), kArenaAllocData));
-  tab_rec->table = table;
-  tab_rec->vaddr = current_dalvik_offset_;
-  uint16_t width = tab_rec->table[1];
-  uint32_t size = tab_rec->table[2] | ((static_cast<uint32_t>(tab_rec->table[3])) << 16);
-  tab_rec->size = (size * width) + 8;
-
-  fill_array_data_.push_back(tab_rec);
-
-  // Making a call - use explicit registers
-  FlushAllRegs();   /* Everything to home location */
-  LoadValueDirectFixed(rl_src, rs_r0);
-  LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pHandleFillArrayData).Int32Value(),
-               rs_rARM_LR);
-  // Materialize a pointer to the fill data image
-  NewLIR3(kThumb2Adr, rs_r1.GetReg(), 0, WrapPointer(tab_rec));
-  ClobberCallerSave();
-  LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR);
-  MarkSafepointPC(call_inst);
-}
-
-/*
  * Handle unlocked -> thin locked transition inline or else call out to quick entrypoint. For more
  * details see monitor.cc.
  */
@@ -323,18 +289,12 @@
   StoreValue(rl_dest, rl_result);
 }
 
-/*
- * Mark garbage collection card. Skip if the value we're storing is null.
- */
-void ArmMir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void ArmMir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) {
   RegStorage reg_card_base = AllocTemp();
   RegStorage reg_card_no = AllocTemp();
-  LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   LoadWordDisp(rs_rARM_SELF, Thread::CardTableOffset<4>().Int32Value(), reg_card_base);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
-  LIR* target = NewLIR0(kPseudoTargetLabel);
-  branch_over->target = target;
   FreeTemp(reg_card_base);
   FreeTemp(reg_card_no);
 }
@@ -388,7 +348,20 @@
     }
   }
   /* Spill core callee saves */
-  NewLIR1(kThumb2Push, core_spill_mask_);
+  if (core_spill_mask_ == 0u) {
+    // Nothing to spill.
+  } else if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_LR.GetRegNum()))) == 0u) {
+    // Spilling only low regs and/or LR, use 16-bit PUSH.
+    constexpr int lr_bit_shift = rs_rARM_LR.GetRegNum() - 8;
+    NewLIR1(kThumbPush,
+            (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) |
+            ((core_spill_mask_ & (1u << rs_rARM_LR.GetRegNum())) >> lr_bit_shift));
+  } else if (IsPowerOfTwo(core_spill_mask_)) {
+    // kThumb2Push cannot be used to spill a single register.
+    NewLIR1(kThumb2Push1, CTZ(core_spill_mask_));
+  } else {
+    NewLIR1(kThumb2Push, core_spill_mask_);
+  }
   /* Need to spill any FP regs? */
   if (num_fp_spills_) {
     /*
@@ -485,13 +458,26 @@
   if (num_fp_spills_) {
     NewLIR1(kThumb2VPopCS, num_fp_spills_);
   }
-  if (core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) {
+  if ((core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) != 0) {
     /* Unspill rARM_LR to rARM_PC */
     core_spill_mask_ &= ~(1 << rs_rARM_LR.GetRegNum());
     core_spill_mask_ |= (1 << rs_rARM_PC.GetRegNum());
   }
-  NewLIR1(kThumb2Pop, core_spill_mask_);
-  if (!(core_spill_mask_ & (1 << rs_rARM_PC.GetRegNum()))) {
+  if (core_spill_mask_ == 0u) {
+    // Nothing to unspill.
+  } else if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_PC.GetRegNum()))) == 0u) {
+    // Unspilling only low regs and/or PC, use 16-bit POP.
+    constexpr int pc_bit_shift = rs_rARM_PC.GetRegNum() - 8;
+    NewLIR1(kThumbPop,
+            (core_spill_mask_ & ~(1u << rs_rARM_PC.GetRegNum())) |
+            ((core_spill_mask_ & (1u << rs_rARM_PC.GetRegNum())) >> pc_bit_shift));
+  } else if (IsPowerOfTwo(core_spill_mask_)) {
+    // kThumb2Pop cannot be used to unspill a single register.
+    NewLIR1(kThumb2Pop1, CTZ(core_spill_mask_));
+  } else {
+    NewLIR1(kThumb2Pop, core_spill_mask_);
+  }
+  if ((core_spill_mask_ & (1 << rs_rARM_PC.GetRegNum())) == 0) {
     /* We didn't pop to rARM_PC, so must do a bv rARM_LR */
     NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
   }
@@ -510,9 +496,9 @@
  * Bit of a hack here - in the absence of a real scheduling pass,
  * emit the next instruction in static & direct invoke sequences.
  */
-static int ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info,
+static int ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
                              int state, const MethodReference& target_method,
-                             uint32_t unused,
+                             uint32_t unused_idx ATTRIBUTE_UNUSED,
                              uintptr_t direct_code, uintptr_t direct_method,
                              InvokeType type) {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -571,8 +557,8 @@
       if (direct_code == 0) {
         // kInvokeTgt := arg0_ref->entrypoint
         cg->LoadWordDisp(arg0_ref,
-                         mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
-                         cg->TargetPtrReg(kInvokeTgt));
+                         mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+                             kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt));
       }
       break;
     default:
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 932dd87..6ac1849 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -25,6 +25,34 @@
 namespace art {
 
 class ArmMir2Lir FINAL : public Mir2Lir {
+ protected:
+  // Inherited class for ARM backend.
+  class InToRegStorageArmMapper FINAL : public InToRegStorageMapper {
+   public:
+    InToRegStorageArmMapper()
+        : cur_core_reg_(0), cur_fp_reg_(0), cur_fp_double_reg_(0) {
+    }
+
+    RegStorage GetNextReg(ShortyArg arg) OVERRIDE;
+
+    virtual void Reset() OVERRIDE {
+      cur_core_reg_ = 0;
+      cur_fp_reg_ = 0;
+      cur_fp_double_reg_ = 0;
+    }
+
+   private:
+    size_t cur_core_reg_;
+    size_t cur_fp_reg_;
+    size_t cur_fp_double_reg_;
+  };
+
+  InToRegStorageArmMapper in_to_reg_storage_arm_mapper_;
+  InToRegStorageMapper* GetResetedInToRegStorageMapper() OVERRIDE {
+    in_to_reg_storage_arm_mapper_.Reset();
+    return &in_to_reg_storage_arm_mapper_;
+  }
+
   public:
     ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
@@ -32,6 +60,10 @@
     bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                             RegLocation rl_dest, int lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
+    void GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                    int32_t constant) OVERRIDE;
+    void GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                     int64_t constant) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
     RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -44,18 +76,34 @@
                        OpSize size, VolatileKind is_volatile) OVERRIDE;
     LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                           OpSize size) OVERRIDE;
-    void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+
+    /// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
+    void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
 
     // Required for target - register utilities.
-    RegStorage TargetReg(SpecialTargetRegister reg);
-    RegStorage GetArgMappingToPhysicalReg(int arg_num);
-    RegLocation GetReturnAlt();
-    RegLocation GetReturnWideAlt();
-    RegLocation LocCReturn();
-    RegLocation LocCReturnRef();
-    RegLocation LocCReturnDouble();
-    RegLocation LocCReturnFloat();
-    RegLocation LocCReturnWide();
+    RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
+    RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) OVERRIDE {
+      if (wide_kind == kWide) {
+        DCHECK((kArg0 <= reg && reg < kArg3) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
+        RegStorage ret_reg = RegStorage::MakeRegPair(TargetReg(reg),
+            TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
+        if (ret_reg.IsFloat()) {
+          // Regard double as double, be consistent with register allocation.
+          ret_reg = As64BitFloatReg(ret_reg);
+        }
+        return ret_reg;
+      } else {
+        return TargetReg(reg);
+      }
+    }
+
+    RegLocation GetReturnAlt() OVERRIDE;
+    RegLocation GetReturnWideAlt() OVERRIDE;
+    RegLocation LocCReturn() OVERRIDE;
+    RegLocation LocCReturnRef() OVERRIDE;
+    RegLocation LocCReturnDouble() OVERRIDE;
+    RegLocation LocCReturnFloat() OVERRIDE;
+    RegLocation LocCReturnWide() OVERRIDE;
     ResourceMask GetRegMaskCommon(const RegStorage& reg) const OVERRIDE;
     void AdjustSpillMask();
     void ClobberCallerSave();
@@ -87,15 +135,15 @@
 
     // Required for target - Dalvik-level generators.
     void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                        RegLocation rl_src2) OVERRIDE;
+                        RegLocation rl_src2, int flags) OVERRIDE;
     void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                           RegLocation rl_src1, RegLocation rl_src2);
+                           RegLocation rl_src1, RegLocation rl_src2, int flags);
     void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                      RegLocation rl_index, RegLocation rl_dest, int scale);
     void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, RegLocation rl_index,
                      RegLocation rl_src, int scale, bool card_mark);
     void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                           RegLocation rl_src1, RegLocation rl_shift);
+                           RegLocation rl_src1, RegLocation rl_shift, int flags);
     void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                           RegLocation rl_src2);
     void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
@@ -118,13 +166,12 @@
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
     void GenSpecialExitSequence();
-    void GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
     void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
     void GenSelect(BasicBlock* bb, MIR* mir);
     void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                           int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                          int dest_reg_class) OVERRIDE;
+                          RegisterClass dest_reg_class) OVERRIDE;
     bool GenMemBarrier(MemBarrierKind barrier_kind);
     void GenMonitorEnter(int opt_flags, RegLocation rl_src);
     void GenMonitorExit(int opt_flags, RegLocation rl_src);
@@ -135,6 +182,8 @@
     void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
     void GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenLargeSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
+    void GenMaddMsubInt(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                        RegLocation rl_src3, bool is_sub);
 
     // Required for target - single operation generators.
     LIR* OpUnconditionalBranch(LIR* target);
@@ -172,17 +221,18 @@
     int EncodeShift(int code, int amount);
     int ModifiedImmediate(uint32_t value);
     ArmConditionCode ArmConditionEncoding(ConditionCode code);
-    bool InexpensiveConstantInt(int32_t value);
-    bool InexpensiveConstantFloat(int32_t value);
-    bool InexpensiveConstantLong(int64_t value);
-    bool InexpensiveConstantDouble(int64_t value);
+    bool InexpensiveConstantInt(int32_t value) OVERRIDE;
+    bool InexpensiveConstantInt(int32_t value, Instruction::Code opcode) OVERRIDE;
+    bool InexpensiveConstantFloat(int32_t value) OVERRIDE;
+    bool InexpensiveConstantLong(int64_t value) OVERRIDE;
+    bool InexpensiveConstantDouble(int64_t value) OVERRIDE;
     RegStorage AllocPreservedDouble(int s_reg);
     RegStorage AllocPreservedSingle(int s_reg);
 
-    bool WideGPRsAreAliases() OVERRIDE {
+    bool WideGPRsAreAliases() const OVERRIDE {
       return false;  // Wide GPRs are formed by pairing.
     }
-    bool WideFPRsAreAliases() OVERRIDE {
+    bool WideFPRsAreAliases() const OVERRIDE {
       return false;  // Wide FPRs are formed by pairing.
     }
 
@@ -211,6 +261,11 @@
     LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
     size_t GetInstructionOffset(LIR* lir);
 
+    void GenMachineSpecificExtendedMethodMIR(BasicBlock* bb, MIR* mir) OVERRIDE;
+
+    bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
+                          RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
+
   private:
     void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
     void GenMulLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
@@ -225,12 +280,12 @@
     void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
     void AssignDataOffsets();
     RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
-                          bool is_div, bool check_zero);
-    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);
-    typedef struct {
+                          bool is_div, int flags) OVERRIDE;
+    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) OVERRIDE;
+    struct EasyMultiplyOp {
       OpKind op;
       uint32_t shift;
-    } EasyMultiplyOp;
+    };
     bool GetEasyMultiplyOp(int lit, EasyMultiplyOp* op);
     bool GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops);
     void GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops);
@@ -240,6 +295,36 @@
     static constexpr ResourceMask EncodeArmRegFpcsList(int reg_list);
 
     ArenaVector<LIR*> call_method_insns_;
+
+    /**
+     * @brief Given float register pair, returns Solo64 float register.
+     * @param reg #RegStorage containing a float register pair (e.g. @c s2 and @c s3).
+     * @return A Solo64 float mapping to the register pair (e.g. @c d1).
+     */
+    static RegStorage As64BitFloatReg(RegStorage reg) {
+      DCHECK(reg.IsFloat());
+
+      RegStorage low = reg.GetLow();
+      RegStorage high = reg.GetHigh();
+      DCHECK((low.GetRegNum() % 2 == 0) && (low.GetRegNum() + 1 == high.GetRegNum()));
+
+      return RegStorage::FloatSolo64(low.GetRegNum() / 2);
+    }
+
+    /**
+     * @brief Given Solo64 float register, returns float register pair.
+     * @param reg #RegStorage containing a Solo64 float register (e.g. @c d1).
+     * @return A float register pair mapping to the Solo64 float pair (e.g. @c s2 and s3).
+     */
+    static RegStorage As64BitFloatRegPair(RegStorage reg) {
+      DCHECK(reg.IsDouble() && reg.Is64BitSolo());
+
+      int reg_num = reg.GetRegNum();
+      return RegStorage::MakeRegPair(RegStorage::FloatSolo32(reg_num * 2),
+                                     RegStorage::FloatSolo32(reg_num * 2 + 1));
+    }
+
+    int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE;
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index 3eb7c83..2b2592d 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -113,6 +113,32 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+void ArmMir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                            int32_t constant) {
+  RegLocation rl_result;
+  RegStorage r_tmp = AllocTempSingle();
+  LoadConstantNoClobber(r_tmp, constant);
+  rl_src1 = LoadValue(rl_src1, kFPReg);
+  rl_result = EvalLoc(rl_dest, kFPReg, true);
+  NewLIR3(kThumb2Vmuls, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
+  StoreValue(rl_dest, rl_result);
+}
+
+void ArmMir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                             int64_t constant) {
+  RegLocation rl_result;
+  RegStorage r_tmp = AllocTempDouble();
+  DCHECK(r_tmp.IsDouble());
+  LoadConstantWide(r_tmp, constant);
+  rl_src1 = LoadValueWide(rl_src1, kFPReg);
+  DCHECK(rl_src1.wide);
+  rl_result = EvalLocWide(rl_dest, kFPReg, true);
+  DCHECK(rl_dest.wide);
+  DCHECK(rl_result.wide);
+  NewLIR3(kThumb2Vmuld, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
+  StoreValueWide(rl_dest, rl_result);
+}
+
 void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) {
   int op = kThumbBkpt;
   int src_reg;
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 1a4b23e..7970bd8 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -16,12 +16,14 @@
 
 /* This file contains codegen for the Thumb2 ISA. */
 
+#include "arch/instruction_set_features.h"
 #include "arm_lir.h"
 #include "codegen_arm.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "entrypoints/quick/quick_entrypoints.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
+#include "utils.h"
 
 namespace art {
 
@@ -49,12 +51,13 @@
   int cond_bit = code & 1;
   int alt_bit = cond_bit ^ 1;
 
-  // Note: case fallthroughs intentional
   switch (strlen(guide)) {
     case 3:
       mask1 = (guide[2] == 'T') ? cond_bit : alt_bit;
+      FALLTHROUGH_INTENDED;
     case 2:
       mask2 = (guide[1] == 'T') ? cond_bit : alt_bit;
+      FALLTHROUGH_INTENDED;
     case 1:
       mask3 = (guide[0] == 'T') ? cond_bit : alt_bit;
       break;
@@ -62,6 +65,7 @@
       break;
     default:
       LOG(FATAL) << "OAT: bad case in OpIT";
+      UNREACHABLE();
   }
   mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
        (1 << (3 - strlen(guide)));
@@ -77,12 +81,13 @@
   int cond_bit = code & 1;
   int alt_bit = cond_bit ^ 1;
 
-  // Note: case fallthroughs intentional
   switch (strlen(new_guide)) {
     case 3:
       mask1 = (new_guide[2] == 'T') ? cond_bit : alt_bit;
+      FALLTHROUGH_INTENDED;
     case 2:
       mask2 = (new_guide[1] == 'T') ? cond_bit : alt_bit;
+      FALLTHROUGH_INTENDED;
     case 1:
       mask3 = (new_guide[0] == 'T') ? cond_bit : alt_bit;
       break;
@@ -90,6 +95,7 @@
       break;
     default:
       LOG(FATAL) << "OAT: bad case in UpdateIT";
+      UNREACHABLE();
   }
   mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
       (1 << (3 - strlen(new_guide)));
@@ -205,7 +211,8 @@
 
 void ArmMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                                   int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                                  int dest_reg_class) {
+                                  RegisterClass dest_reg_class) {
+  UNUSED(dest_reg_class);
   // TODO: Generalize the IT below to accept more than one-instruction loads.
   DCHECK(InexpensiveConstantInt(true_val));
   DCHECK(InexpensiveConstantInt(false_val));
@@ -228,6 +235,7 @@
 }
 
 void ArmMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb);
   RegLocation rl_result;
   RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
   RegLocation rl_dest = mir_graph_->GetDest(mir);
@@ -438,6 +446,15 @@
     bool src_fp = r_src.IsFloat();
     DCHECK(r_dest.Is64Bit());
     DCHECK(r_src.Is64Bit());
+    // Note: If the register is get by register allocator, it should never be a pair.
+    // But some functions in mir_2_lir assume 64-bit registers are 32-bit register pairs.
+    // TODO: Rework Mir2Lir::LoadArg() and Mir2Lir::LoadArgDirect().
+    if (dest_fp && r_dest.IsPair()) {
+      r_dest = As64BitFloatReg(r_dest);
+    }
+    if (src_fp && r_src.IsPair()) {
+      r_src = As64BitFloatReg(r_src);
+    }
     if (dest_fp) {
       if (src_fp) {
         OpRegCopy(r_dest, r_src);
@@ -491,6 +508,7 @@
 // Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
 bool ArmMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(dalvik_opcode);
   if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
     return false;
   }
@@ -550,21 +568,30 @@
 
 // Try to convert *lit to 1 RegRegRegShift/RegRegShift form.
 bool ArmMir2Lir::GetEasyMultiplyOp(int lit, ArmMir2Lir::EasyMultiplyOp* op) {
+  if (lit == 0) {
+    // Special case for *divide-by-zero*. The ops won't actually be used to generate code, as
+    // GenArithOpIntLit will directly generate exception-throwing code, and multiply-by-zero will
+    // have been optimized away earlier.
+    op->op = kOpInvalid;
+    op->shift = 0;
+    return true;
+  }
+
   if (IsPowerOfTwo(lit)) {
     op->op = kOpLsl;
-    op->shift = LowestSetBit(lit);
+    op->shift = CTZ(lit);
     return true;
   }
 
   if (IsPowerOfTwo(lit - 1)) {
     op->op = kOpAdd;
-    op->shift = LowestSetBit(lit - 1);
+    op->shift = CTZ(lit - 1);
     return true;
   }
 
   if (IsPowerOfTwo(lit + 1)) {
     op->op = kOpRsub;
-    op->shift = LowestSetBit(lit + 1);
+    op->shift = CTZ(lit + 1);
     return true;
   }
 
@@ -575,7 +602,6 @@
 
 // Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms.
 bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) {
-  GetEasyMultiplyOp(lit, &ops[0]);
   if (GetEasyMultiplyOp(lit, &ops[0])) {
     ops[1].op = kOpInvalid;
     ops[1].shift = 0;
@@ -583,7 +609,7 @@
   }
 
   int lit1 = lit;
-  uint32_t shift = LowestSetBit(lit1);
+  uint32_t shift = CTZ(lit1);
   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
     ops[1].op = kOpLsl;
     ops[1].shift = shift;
@@ -591,7 +617,7 @@
   }
 
   lit1 = lit - 1;
-  shift = LowestSetBit(lit1);
+  shift = CTZ(lit1);
   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
     ops[1].op = kOpAdd;
     ops[1].shift = shift;
@@ -599,7 +625,7 @@
   }
 
   lit1 = lit + 1;
-  shift = LowestSetBit(lit1);
+  shift = CTZ(lit1);
   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
     ops[1].op = kOpRsub;
     ops[1].shift = shift;
@@ -674,14 +700,17 @@
 }
 
 RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                      RegLocation rl_src2, bool is_div, bool check_zero) {
+                                  RegLocation rl_src2, bool is_div, int flags) {
+  UNUSED(rl_dest, rl_src1, rl_src2, is_div, flags);
   LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
-  return rl_dest;
+  UNREACHABLE();
 }
 
-RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
+RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit,
+                                     bool is_div) {
+  UNUSED(rl_dest, rl_src1, lit, is_div);
   LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
-  return rl_dest;
+  UNREACHABLE();
 }
 
 RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
@@ -845,14 +874,14 @@
   RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
   RegLocation rl_new_value;
   if (!is_long) {
-    rl_new_value = LoadValue(rl_src_new_value);
+    rl_new_value = LoadValue(rl_src_new_value, LocToRegClass(rl_src_new_value));
   } else if (load_early) {
     rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg);
   }
 
   if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
     // Mark card for object assuming new value is stored.
-    MarkGCCard(rl_new_value.reg, rl_object.reg);
+    MarkGCCard(0, rl_new_value.reg, rl_object.reg);
   }
 
   RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
@@ -868,7 +897,7 @@
 
   RegLocation rl_expected;
   if (!is_long) {
-    rl_expected = LoadValue(rl_src_expected);
+    rl_expected = LoadValue(rl_src_expected, LocToRegClass(rl_src_new_value));
   } else if (load_early) {
     rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
   } else {
@@ -1056,9 +1085,21 @@
   return NewLIR3(kThumb2Vstms, r_base.GetReg(), rs_fr0.GetReg(), count);
 }
 
+void ArmMir2Lir::GenMaddMsubInt(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                RegLocation rl_src3, bool is_sub) {
+  rl_src1 = LoadValue(rl_src1, kCoreReg);
+  rl_src2 = LoadValue(rl_src2, kCoreReg);
+  rl_src3 = LoadValue(rl_src3, kCoreReg);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  NewLIR4(is_sub ? kThumb2Mls : kThumb2Mla, rl_result.reg.GetReg(), rl_src1.reg.GetReg(),
+          rl_src2.reg.GetReg(), rl_src3.reg.GetReg());
+  StoreValue(rl_dest, rl_result);
+}
+
 void ArmMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
                                                RegLocation rl_result, int lit,
                                                int first_bit, int second_bit) {
+  UNUSED(lit);
   OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg,
                    EncodeShift(kArmLsl, second_bit - first_bit));
   if (first_bit != 0) {
@@ -1082,7 +1123,7 @@
 #else
   RegStorage t_reg = AllocTemp();
   LoadBaseDisp(rs_rARM_SELF, Thread::ThreadFlagsOffset<4>().Int32Value(),
-    t_reg, kUnsignedHalf);
+    t_reg, kUnsignedHalf, kNotVolatile);
   LIR* cmp_branch = OpCmpImmBranch((target == NULL) ? kCondNe : kCondEq, t_reg,
     0, target);
   FreeTemp(t_reg);
@@ -1099,7 +1140,9 @@
 }
 
 bool ArmMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
-#if ANDROID_SMP != 0
+  if (!cu_->GetInstructionSetFeatures()->IsSmp()) {
+    return false;
+  }
   // Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
   LIR* barrier = last_lir_insn_;
 
@@ -1129,9 +1172,6 @@
   DCHECK(!barrier->flags.use_def_invalid);
   barrier->u.m.def_mask = &kEncodeAll;
   return ret;
-#else
-  return false;
-#endif
 }
 
 void ArmMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
@@ -1142,6 +1182,7 @@
   // Check for destructive overlap
   if (rl_result.reg.GetLowReg() == rl_src.reg.GetHighReg()) {
     RegStorage t_reg = AllocTemp();
+    OpRegCopy(t_reg, rl_result.reg.GetLow());
     OpRegRegReg(kOpSub, rl_result.reg.GetLow(), z_reg, rl_src.reg.GetLow());
     OpRegRegReg(kOpSbc, rl_result.reg.GetHigh(), z_reg, t_reg);
     FreeTemp(t_reg);
@@ -1155,112 +1196,113 @@
 
 void ArmMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
                             RegLocation rl_src1, RegLocation rl_src2) {
-    /*
-     * tmp1     = src1.hi * src2.lo;  // src1.hi is no longer needed
-     * dest     = src1.lo * src2.lo;
-     * tmp1    += src1.lo * src2.hi;
-     * dest.hi += tmp1;
-     *
-     * To pull off inline multiply, we have a worst-case requirement of 7 temporary
-     * registers.  Normally for Arm, we get 5.  We can get to 6 by including
-     * lr in the temp set.  The only problematic case is all operands and result are
-     * distinct, and none have been promoted.  In that case, we can succeed by aggressively
-     * freeing operand temp registers after they are no longer needed.  All other cases
-     * can proceed normally.  We'll just punt on the case of the result having a misaligned
-     * overlap with either operand and send that case to a runtime handler.
-     */
-    RegLocation rl_result;
-    if (BadOverlap(rl_src1, rl_dest) || (BadOverlap(rl_src2, rl_dest))) {
-      FlushAllRegs();
-      CallRuntimeHelperRegLocationRegLocation(kQuickLmul, rl_src1, rl_src2, false);
-      rl_result = GetReturnWide(kCoreReg);
-      StoreValueWide(rl_dest, rl_result);
-      return;
-    }
-
-    rl_src1 = LoadValueWide(rl_src1, kCoreReg);
-    rl_src2 = LoadValueWide(rl_src2, kCoreReg);
-
-    int reg_status = 0;
-    RegStorage res_lo;
-    RegStorage res_hi;
-    bool dest_promoted = rl_dest.location == kLocPhysReg && rl_dest.reg.Valid() &&
-        !IsTemp(rl_dest.reg.GetLow()) && !IsTemp(rl_dest.reg.GetHigh());
-    bool src1_promoted = !IsTemp(rl_src1.reg.GetLow()) && !IsTemp(rl_src1.reg.GetHigh());
-    bool src2_promoted = !IsTemp(rl_src2.reg.GetLow()) && !IsTemp(rl_src2.reg.GetHigh());
-    // Check if rl_dest is *not* either operand and we have enough temp registers.
-    if ((rl_dest.s_reg_low != rl_src1.s_reg_low && rl_dest.s_reg_low != rl_src2.s_reg_low) &&
-        (dest_promoted || src1_promoted || src2_promoted)) {
-      // In this case, we do not need to manually allocate temp registers for result.
-      rl_result = EvalLoc(rl_dest, kCoreReg, true);
-      res_lo = rl_result.reg.GetLow();
-      res_hi = rl_result.reg.GetHigh();
-    } else {
-      res_lo = AllocTemp();
-      if ((rl_src1.s_reg_low == rl_src2.s_reg_low) || src1_promoted || src2_promoted) {
-        // In this case, we have enough temp registers to be allocated for result.
-        res_hi = AllocTemp();
-        reg_status = 1;
-      } else {
-        // In this case, all temps are now allocated.
-        // res_hi will be allocated after we can free src1_hi.
-        reg_status = 2;
-      }
-    }
-
-    // Temporarily add LR to the temp pool, and assign it to tmp1
-    MarkTemp(rs_rARM_LR);
-    FreeTemp(rs_rARM_LR);
-    RegStorage tmp1 = rs_rARM_LR;
-    LockTemp(rs_rARM_LR);
-
-    if (rl_src1.reg == rl_src2.reg) {
-      DCHECK(res_hi.Valid());
-      DCHECK(res_lo.Valid());
-      NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
-      NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src1.reg.GetLowReg(),
-              rl_src1.reg.GetLowReg());
-      OpRegRegRegShift(kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
-    } else {
-      NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetHighReg());
-      if (reg_status == 2) {
-        DCHECK(!res_hi.Valid());
-        DCHECK_NE(rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
-        DCHECK_NE(rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
-        // Will force free src1_hi, so must clobber.
-        Clobber(rl_src1.reg);
-        FreeTemp(rl_src1.reg.GetHigh());
-        res_hi = AllocTemp();
-      }
-      DCHECK(res_hi.Valid());
-      DCHECK(res_lo.Valid());
-      NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src2.reg.GetLowReg(),
-              rl_src1.reg.GetLowReg());
-      NewLIR4(kThumb2Mla, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg(),
-              tmp1.GetReg());
-      NewLIR4(kThumb2AddRRR, res_hi.GetReg(), tmp1.GetReg(), res_hi.GetReg(), 0);
-      if (reg_status == 2) {
-        FreeTemp(rl_src1.reg.GetLow());
-      }
-    }
-
-    // Now, restore lr to its non-temp status.
-    FreeTemp(tmp1);
-    Clobber(rs_rARM_LR);
-    UnmarkTemp(rs_rARM_LR);
-
-    if (reg_status != 0) {
-      // We had manually allocated registers for rl_result.
-      // Now construct a RegLocation.
-      rl_result = GetReturnWide(kCoreReg);  // Just using as a template.
-      rl_result.reg = RegStorage::MakeRegPair(res_lo, res_hi);
-    }
-
+  UNUSED(opcode);
+  /*
+   * tmp1     = src1.hi * src2.lo;  // src1.hi is no longer needed
+   * dest     = src1.lo * src2.lo;
+   * tmp1    += src1.lo * src2.hi;
+   * dest.hi += tmp1;
+   *
+   * To pull off inline multiply, we have a worst-case requirement of 7 temporary
+   * registers.  Normally for Arm, we get 5.  We can get to 6 by including
+   * lr in the temp set.  The only problematic case is all operands and result are
+   * distinct, and none have been promoted.  In that case, we can succeed by aggressively
+   * freeing operand temp registers after they are no longer needed.  All other cases
+   * can proceed normally.  We'll just punt on the case of the result having a misaligned
+   * overlap with either operand and send that case to a runtime handler.
+   */
+  RegLocation rl_result;
+  if (PartiallyIntersects(rl_src1, rl_dest) || (PartiallyIntersects(rl_src2, rl_dest))) {
+    FlushAllRegs();
+    CallRuntimeHelperRegLocationRegLocation(kQuickLmul, rl_src1, rl_src2, false);
+    rl_result = GetReturnWide(kCoreReg);
     StoreValueWide(rl_dest, rl_result);
+    return;
+  }
+
+  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
+
+  int reg_status = 0;
+  RegStorage res_lo;
+  RegStorage res_hi;
+  bool dest_promoted = rl_dest.location == kLocPhysReg && rl_dest.reg.Valid() &&
+      !IsTemp(rl_dest.reg.GetLow()) && !IsTemp(rl_dest.reg.GetHigh());
+  bool src1_promoted = !IsTemp(rl_src1.reg.GetLow()) && !IsTemp(rl_src1.reg.GetHigh());
+  bool src2_promoted = !IsTemp(rl_src2.reg.GetLow()) && !IsTemp(rl_src2.reg.GetHigh());
+  // Check if rl_dest is *not* either operand and we have enough temp registers.
+  if ((rl_dest.s_reg_low != rl_src1.s_reg_low && rl_dest.s_reg_low != rl_src2.s_reg_low) &&
+      (dest_promoted || src1_promoted || src2_promoted)) {
+    // In this case, we do not need to manually allocate temp registers for result.
+    rl_result = EvalLoc(rl_dest, kCoreReg, true);
+    res_lo = rl_result.reg.GetLow();
+    res_hi = rl_result.reg.GetHigh();
+  } else {
+    res_lo = AllocTemp();
+    if ((rl_src1.s_reg_low == rl_src2.s_reg_low) || src1_promoted || src2_promoted) {
+      // In this case, we have enough temp registers to be allocated for result.
+      res_hi = AllocTemp();
+      reg_status = 1;
+    } else {
+      // In this case, all temps are now allocated.
+      // res_hi will be allocated after we can free src1_hi.
+      reg_status = 2;
+    }
+  }
+
+  // Temporarily add LR to the temp pool, and assign it to tmp1
+  MarkTemp(rs_rARM_LR);
+  FreeTemp(rs_rARM_LR);
+  RegStorage tmp1 = rs_rARM_LR;
+  LockTemp(rs_rARM_LR);
+
+  if (rl_src1.reg == rl_src2.reg) {
+    DCHECK(res_hi.Valid());
+    DCHECK(res_lo.Valid());
+    NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
+    NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src1.reg.GetLowReg(),
+            rl_src1.reg.GetLowReg());
+    OpRegRegRegShift(kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
+  } else {
+    NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetHighReg());
+    if (reg_status == 2) {
+      DCHECK(!res_hi.Valid());
+      DCHECK_NE(rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
+      DCHECK_NE(rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
+      // Will force free src1_hi, so must clobber.
+      Clobber(rl_src1.reg);
+      FreeTemp(rl_src1.reg.GetHigh());
+      res_hi = AllocTemp();
+    }
+    DCHECK(res_hi.Valid());
+    DCHECK(res_lo.Valid());
+    NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src2.reg.GetLowReg(),
+            rl_src1.reg.GetLowReg());
+    NewLIR4(kThumb2Mla, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg(),
+            tmp1.GetReg());
+    NewLIR4(kThumb2AddRRR, res_hi.GetReg(), tmp1.GetReg(), res_hi.GetReg(), 0);
+    if (reg_status == 2) {
+      FreeTemp(rl_src1.reg.GetLow());
+    }
+  }
+
+  // Now, restore lr to its non-temp status.
+  FreeTemp(tmp1);
+  Clobber(rs_rARM_LR);
+  UnmarkTemp(rs_rARM_LR);
+
+  if (reg_status != 0) {
+    // We had manually allocated registers for rl_result.
+    // Now construct a RegLocation.
+    rl_result = GetReturnWide(kCoreReg);  // Just using as a template.
+    rl_result.reg = RegStorage::MakeRegPair(res_lo, res_hi);
+  }
+
+  StoreValueWide(rl_dest, rl_result);
 }
 
 void ArmMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                                RegLocation rl_src2) {
+                                RegLocation rl_src2, int flags) {
   switch (opcode) {
     case Instruction::MUL_LONG:
     case Instruction::MUL_LONG_2ADDR:
@@ -1275,7 +1317,7 @@
   }
 
   // Fallback for all other ops.
-  Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+  Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
 }
 
 /*
@@ -1338,7 +1380,6 @@
       FreeTemp(reg_len);
     }
     LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size, kNotVolatile);
-    MarkPossibleNullPointerException(opt_flags);
     if (!constant_index) {
       FreeTemp(reg_ptr);
     }
@@ -1359,7 +1400,6 @@
       FreeTemp(reg_len);
     }
     LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
-    MarkPossibleNullPointerException(opt_flags);
     FreeTemp(reg_ptr);
     StoreValue(rl_dest, rl_result);
   }
@@ -1438,7 +1478,6 @@
     }
 
     StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size, kNotVolatile);
-    MarkPossibleNullPointerException(opt_flags);
   } else {
     /* reg_ptr -> array data */
     OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
@@ -1448,19 +1487,20 @@
       FreeTemp(reg_len);
     }
     StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
-    MarkPossibleNullPointerException(opt_flags);
   }
   if (allocated_reg_ptr_temp) {
     FreeTemp(reg_ptr);
   }
   if (card_mark) {
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
 
 void ArmMir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
-                                   RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
+                                   RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift,
+                                   int flags) {
+  UNUSED(flags);
   rl_src = LoadValueWide(rl_src, kCoreReg);
   // Per spec, we only care about low 6 bits of shift amount.
   int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
@@ -1468,7 +1508,7 @@
     StoreValueWide(rl_dest, rl_src);
     return;
   }
-  if (BadOverlap(rl_src, rl_dest)) {
+  if (PartiallyIntersects(rl_src, rl_dest)) {
     GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
     return;
   }
@@ -1533,11 +1573,12 @@
 }
 
 void ArmMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
-                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
+                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                   int flags) {
   if ((opcode == Instruction::SUB_LONG_2ADDR) || (opcode == Instruction::SUB_LONG)) {
     if (!rl_src2.is_const) {
       // Don't bother with special handling for subtract from immediate.
-      GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+      GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
       return;
     }
   } else {
@@ -1547,8 +1588,8 @@
       std::swap(rl_src1, rl_src2);
     }
   }
-  if (BadOverlap(rl_src1, rl_dest)) {
-    GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+  if (PartiallyIntersects(rl_src1, rl_dest)) {
+    GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
     return;
   }
   DCHECK(rl_src2.is_const);
@@ -1565,7 +1606,7 @@
     case Instruction::SUB_LONG:
     case Instruction::SUB_LONG_2ADDR:
       if ((mod_imm_lo < 0) || (mod_imm_hi < 0)) {
-        GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+        GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
         return;
       }
       break;
@@ -1615,4 +1656,19 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+bool ArmMir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
+                                  RegLocation rl_src, RegLocation rl_dest, int lit) {
+  if (lit < 2) {
+    return false;
+  }
+
+  // ARM does either not support a division instruction, or it is potentially expensive. Look for
+  // more special cases.
+  if (!IsPowerOfTwo(lit)) {
+    return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
+  }
+
+  return Mir2Lir::HandleEasyDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index dd8f7fe..52a516c 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -89,7 +89,7 @@
 
 // Return a target-dependent special register.
 RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
-  RegStorage res_reg = RegStorage::InvalidReg();
+  RegStorage res_reg;
   switch (reg) {
     case kSelf: res_reg = rs_rARM_SELF; break;
 #ifdef ARM_R4_SUSPEND_FLAG
@@ -104,10 +104,22 @@
     case kArg1: res_reg = rs_r1; break;
     case kArg2: res_reg = rs_r2; break;
     case kArg3: res_reg = rs_r3; break;
-    case kFArg0: res_reg = rs_r0; break;
-    case kFArg1: res_reg = rs_r1; break;
-    case kFArg2: res_reg = rs_r2; break;
-    case kFArg3: res_reg = rs_r3; break;
+    case kFArg0: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r0 : rs_fr0; break;
+    case kFArg1: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r1 : rs_fr1; break;
+    case kFArg2: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r2 : rs_fr2; break;
+    case kFArg3: res_reg = kArm32QuickCodeUseSoftFloat ? rs_r3 : rs_fr3; break;
+    case kFArg4: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr4; break;
+    case kFArg5: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr5; break;
+    case kFArg6: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr6; break;
+    case kFArg7: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr7; break;
+    case kFArg8: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr8; break;
+    case kFArg9: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr9; break;
+    case kFArg10: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr10; break;
+    case kFArg11: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr11; break;
+    case kFArg12: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr12; break;
+    case kFArg13: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr13; break;
+    case kFArg14: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr14; break;
+    case kFArg15: res_reg = kArm32QuickCodeUseSoftFloat ? RegStorage::InvalidReg() : rs_fr15; break;
     case kRet0: res_reg = rs_r0; break;
     case kRet1: res_reg = rs_r1; break;
     case kInvokeTgt: res_reg = rs_rARM_LR; break;
@@ -119,20 +131,6 @@
   return res_reg;
 }
 
-RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
-  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
-  switch (arg_num) {
-    case 0:
-      return rs_r1;
-    case 1:
-      return rs_r2;
-    case 2:
-      return rs_r3;
-    default:
-      return RegStorage::InvalidReg();
-  }
-}
-
 /*
  * Decode the register id.
  */
@@ -561,11 +559,10 @@
   call_method_insns_.reserve(100);
   // Sanity check - make sure encoding map lines up.
   for (int i = 0; i < kArmLast; i++) {
-    if (ArmMir2Lir::EncodingMap[i].opcode != i) {
-      LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
-                 << " is wrong: expecting " << i << ", seeing "
-                 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
-    }
+    DCHECK_EQ(ArmMir2Lir::EncodingMap[i].opcode, i)
+        << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
+        << " is wrong: expecting " << i << ", seeing "
+        << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
   }
 }
 
@@ -718,6 +715,32 @@
   LockTemp(rs_r1);
   LockTemp(rs_r2);
   LockTemp(rs_r3);
+  if (!kArm32QuickCodeUseSoftFloat) {
+    LockTemp(rs_fr0);
+    LockTemp(rs_fr1);
+    LockTemp(rs_fr2);
+    LockTemp(rs_fr3);
+    LockTemp(rs_fr4);
+    LockTemp(rs_fr5);
+    LockTemp(rs_fr6);
+    LockTemp(rs_fr7);
+    LockTemp(rs_fr8);
+    LockTemp(rs_fr9);
+    LockTemp(rs_fr10);
+    LockTemp(rs_fr11);
+    LockTemp(rs_fr12);
+    LockTemp(rs_fr13);
+    LockTemp(rs_fr14);
+    LockTemp(rs_fr15);
+    LockTemp(rs_dr0);
+    LockTemp(rs_dr1);
+    LockTemp(rs_dr2);
+    LockTemp(rs_dr3);
+    LockTemp(rs_dr4);
+    LockTemp(rs_dr5);
+    LockTemp(rs_dr6);
+    LockTemp(rs_dr7);
+  }
 }
 
 /* To be used when explicitly managing register use */
@@ -726,6 +749,33 @@
   FreeTemp(rs_r1);
   FreeTemp(rs_r2);
   FreeTemp(rs_r3);
+  FreeTemp(TargetReg(kHiddenArg));
+  if (!kArm32QuickCodeUseSoftFloat) {
+    FreeTemp(rs_fr0);
+    FreeTemp(rs_fr1);
+    FreeTemp(rs_fr2);
+    FreeTemp(rs_fr3);
+    FreeTemp(rs_fr4);
+    FreeTemp(rs_fr5);
+    FreeTemp(rs_fr6);
+    FreeTemp(rs_fr7);
+    FreeTemp(rs_fr8);
+    FreeTemp(rs_fr9);
+    FreeTemp(rs_fr10);
+    FreeTemp(rs_fr11);
+    FreeTemp(rs_fr12);
+    FreeTemp(rs_fr13);
+    FreeTemp(rs_fr14);
+    FreeTemp(rs_fr15);
+    FreeTemp(rs_dr0);
+    FreeTemp(rs_dr1);
+    FreeTemp(rs_dr2);
+    FreeTemp(rs_dr3);
+    FreeTemp(rs_dr4);
+    FreeTemp(rs_dr5);
+    FreeTemp(rs_dr6);
+    FreeTemp(rs_dr7);
+  }
 }
 
 RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
@@ -847,4 +897,86 @@
   Mir2Lir::InstallLiteralPools();
 }
 
+RegStorage ArmMir2Lir::InToRegStorageArmMapper::GetNextReg(ShortyArg arg) {
+  const RegStorage coreArgMappingToPhysicalReg[] =
+      {rs_r1, rs_r2, rs_r3};
+  const int coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
+  const RegStorage fpArgMappingToPhysicalReg[] =
+      {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
+       rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
+  constexpr uint32_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
+  static_assert(fpArgMappingToPhysicalRegSize % 2 == 0, "Number of FP Arg regs is not even");
+
+  RegStorage result = RegStorage::InvalidReg();
+  // Regard double as long, float as int for kArm32QuickCodeUseSoftFloat.
+  if (arg.IsFP() && !kArm32QuickCodeUseSoftFloat) {
+    if (arg.IsWide()) {
+      cur_fp_double_reg_ = std::max(cur_fp_double_reg_, RoundUp(cur_fp_reg_, 2));
+      if (cur_fp_double_reg_ < fpArgMappingToPhysicalRegSize) {
+        result = RegStorage::MakeRegPair(fpArgMappingToPhysicalReg[cur_fp_double_reg_],
+                                         fpArgMappingToPhysicalReg[cur_fp_double_reg_ + 1]);
+        result = As64BitFloatReg(result);
+        cur_fp_double_reg_ += 2;
+      }
+    } else {
+      if (cur_fp_reg_ % 2 == 0) {
+        cur_fp_reg_ = std::max(cur_fp_double_reg_, cur_fp_reg_);
+      }
+      if (cur_fp_reg_ < fpArgMappingToPhysicalRegSize) {
+        result = fpArgMappingToPhysicalReg[cur_fp_reg_];
+        cur_fp_reg_++;
+      }
+    }
+  } else {
+    if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+      if (!kArm32QuickCodeUseSoftFloat && arg.IsWide() && cur_core_reg_ == 0) {
+        // Skip r1, and use r2-r3 for the register pair.
+        cur_core_reg_++;
+      }
+      result = coreArgMappingToPhysicalReg[cur_core_reg_++];
+      if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+        result = RegStorage::MakeRegPair(result, coreArgMappingToPhysicalReg[cur_core_reg_++]);
+      }
+    }
+  }
+  return result;
+}
+
+int ArmMir2Lir::GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) {
+  if (kArm32QuickCodeUseSoftFloat) {
+    return Mir2Lir::GenDalvikArgsBulkCopy(info, first, count);
+  }
+  /*
+   * TODO: Improve by adding block copy for large number of arguments.  For now, just
+   * copy a Dalvik vreg at a time.
+   */
+  return count;
+}
+
+void ArmMir2Lir::GenMachineSpecificExtendedMethodMIR(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb);
+  DCHECK(MIR::DecodedInstruction::IsPseudoMirOp(mir->dalvikInsn.opcode));
+  RegLocation rl_src[3];
+  RegLocation rl_dest = mir_graph_->GetBadLoc();
+  rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
+  switch (static_cast<ExtendedMIROpcode>(mir->dalvikInsn.opcode)) {
+    case kMirOpMaddInt:
+      rl_dest = mir_graph_->GetDest(mir);
+      rl_src[0] = mir_graph_->GetSrc(mir, 0);
+      rl_src[1] = mir_graph_->GetSrc(mir, 1);
+      rl_src[2]= mir_graph_->GetSrc(mir, 2);
+      GenMaddMsubInt(rl_dest, rl_src[0], rl_src[1], rl_src[2], false);
+      break;
+    case kMirOpMsubInt:
+      rl_dest = mir_graph_->GetDest(mir);
+      rl_src[0] = mir_graph_->GetSrc(mir, 0);
+      rl_src[1] = mir_graph_->GetSrc(mir, 1);
+      rl_src[2]= mir_graph_->GetSrc(mir, 2);
+      GenMaddMsubInt(rl_dest, rl_src[0], rl_src[1], rl_src[2], true);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected opcode: " << mir->dalvikInsn.opcode;
+  }
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index bba1a8c..73b68a5 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#include "arm_lir.h"
 #include "codegen_arm.h"
+
+#include "arch/arm/instruction_set_features_arm.h"
+#include "arm_lir.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 
@@ -95,31 +97,11 @@
   return load_pc_rel;
 }
 
-static int LeadingZeros(uint32_t val) {
-  uint32_t alt;
-  int32_t n;
-  int32_t count;
-
-  count = 16;
-  n = 32;
-  do {
-    alt = val >> count;
-    if (alt != 0) {
-      n = n - count;
-      val = alt;
-    }
-    count >>= 1;
-  } while (count);
-  return n - val;
-}
-
 /*
  * Determine whether value can be encoded as a Thumb2 modified
  * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
  */
 int ArmMir2Lir::ModifiedImmediate(uint32_t value) {
-  int32_t z_leading;
-  int32_t z_trailing;
   uint32_t b0 = value & 0xff;
 
   /* Note: case of value==0 must use 0:000:0:0000000 encoding */
@@ -133,8 +115,8 @@
   if (value == ((b0 << 24) | (b0 << 8)))
     return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
   /* Can we do it with rotation? */
-  z_leading = LeadingZeros(value);
-  z_trailing = 32 - LeadingZeros(~value & (value - 1));
+  int z_leading = CLZ(value);
+  int z_trailing = CTZ(value);
   /* A run of eight or fewer active bits? */
   if ((z_leading + z_trailing) < 24)
     return -1;  /* No - bail */
@@ -150,6 +132,71 @@
   return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0);
 }
 
+bool ArmMir2Lir::InexpensiveConstantInt(int32_t value, Instruction::Code opcode) {
+  switch (opcode) {
+    case Instruction::ADD_INT:
+    case Instruction::ADD_INT_2ADDR:
+    case Instruction::SUB_INT:
+    case Instruction::SUB_INT_2ADDR:
+      if ((value >> 12) == (value >> 31)) {  // Signed 12-bit, RRI12 versions of ADD/SUB.
+        return true;
+      }
+      FALLTHROUGH_INTENDED;
+    case Instruction::IF_EQ:
+    case Instruction::IF_NE:
+    case Instruction::IF_LT:
+    case Instruction::IF_GE:
+    case Instruction::IF_GT:
+    case Instruction::IF_LE:
+      return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(-value) >= 0);
+    case Instruction::SHL_INT:
+    case Instruction::SHL_INT_2ADDR:
+    case Instruction::SHR_INT:
+    case Instruction::SHR_INT_2ADDR:
+    case Instruction::USHR_INT:
+    case Instruction::USHR_INT_2ADDR:
+      return true;
+    case Instruction::CONST:
+    case Instruction::CONST_4:
+    case Instruction::CONST_16:
+      if ((value >> 16) == 0) {
+        return true;  // movw, 16-bit unsigned.
+      }
+      FALLTHROUGH_INTENDED;
+    case Instruction::AND_INT:
+    case Instruction::AND_INT_2ADDR:
+    case Instruction::AND_INT_LIT16:
+    case Instruction::AND_INT_LIT8:
+    case Instruction::OR_INT:
+    case Instruction::OR_INT_2ADDR:
+    case Instruction::OR_INT_LIT16:
+    case Instruction::OR_INT_LIT8:
+      return (ModifiedImmediate(value) >= 0) || (ModifiedImmediate(~value) >= 0);
+    case Instruction::XOR_INT:
+    case Instruction::XOR_INT_2ADDR:
+    case Instruction::XOR_INT_LIT16:
+    case Instruction::XOR_INT_LIT8:
+      return (ModifiedImmediate(value) >= 0);
+    case Instruction::MUL_INT:
+    case Instruction::MUL_INT_2ADDR:
+    case Instruction::MUL_INT_LIT8:
+    case Instruction::MUL_INT_LIT16:
+    case Instruction::DIV_INT:
+    case Instruction::DIV_INT_2ADDR:
+    case Instruction::DIV_INT_LIT8:
+    case Instruction::DIV_INT_LIT16:
+    case Instruction::REM_INT:
+    case Instruction::REM_INT_2ADDR:
+    case Instruction::REM_INT_LIT8:
+    case Instruction::REM_INT_LIT16: {
+      EasyMultiplyOp ops[2];
+      return GetEasyMultiplyTwoOps(value, ops);
+    }
+    default:
+      return false;
+  }
+}
+
 bool ArmMir2Lir::InexpensiveConstantFloat(int32_t value) {
   return EncodeImmSingle(value) >= 0;
 }
@@ -211,10 +258,7 @@
 }
 
 LIR* ArmMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
-  // This is kThumb2BCond instead of kThumbBCond for performance reasons. The assembly
-  // time required for a new pass after kThumbBCond is fixed up to kThumb2BCond is
-  // substantial.
-  LIR* branch = NewLIR2(kThumb2BCond, 0 /* offset to be patched */,
+  LIR* branch = NewLIR2(kThumbBCond, 0 /* offset to be patched */,
                         ArmConditionEncoding(cc));
   branch->target = target;
   return branch;
@@ -373,18 +417,21 @@
 }
 
 LIR* ArmMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) {
+  UNUSED(r_dest, r_base, offset, move_type);
   UNIMPLEMENTED(FATAL);
-  return nullptr;
+  UNREACHABLE();
 }
 
 LIR* ArmMir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
+  UNUSED(r_base, offset, r_src, move_type);
   UNIMPLEMENTED(FATAL);
-  return nullptr;
+  UNREACHABLE();
 }
 
 LIR* ArmMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
+  UNUSED(op, cc, r_dest, r_src);
   LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
@@ -461,7 +508,6 @@
 }
 
 LIR* ArmMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
-  LIR* res;
   bool neg = (value < 0);
   int32_t abs_value = (neg) ? -value : value;
   ArmOpcode opcode = kThumbBkpt;
@@ -494,7 +540,7 @@
           (value <= 1020) && ((value & 0x3) == 0)) {
         return NewLIR3(kThumbAddPcRel, r_dest.GetReg(), r_src1.GetReg(), value >> 2);
       }
-      // Note: intentional fallthrough
+      FALLTHROUGH_INTENDED;
     case kOpSub:
       if (all_low_regs && ((abs_value & 0x7) == abs_value)) {
         if (op == kOpAdd)
@@ -509,7 +555,7 @@
           op = (op == kOpAdd) ? kOpSub : kOpAdd;
         }
       }
-      if (mod_imm < 0 && (abs_value & 0x3ff) == abs_value) {
+      if (mod_imm < 0 && (abs_value >> 12) == 0) {
         // This is deliberately used only if modified immediate encoding is inadequate since
         // we sometimes actually use the flags for small values but not necessarily low regs.
         if (op == kOpAdd)
@@ -541,6 +587,12 @@
     case kOpOr:
       opcode = kThumb2OrrRRI8M;
       alt_opcode = kThumb2OrrRRR;
+      if (mod_imm < 0) {
+        mod_imm = ModifiedImmediate(~value);
+        if (mod_imm >= 0) {
+          opcode = kThumb2OrnRRI8M;
+        }
+      }
       break;
     case kOpAnd:
       if (mod_imm < 0) {
@@ -587,6 +639,7 @@
   } else {
     RegStorage r_scratch = AllocTemp();
     LoadConstant(r_scratch, value);
+    LIR* res;
     if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
       res = NewLIR4(alt_opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), 0);
     else
@@ -853,12 +906,12 @@
  */
 LIR* ArmMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
                                   OpSize size) {
-  LIR* load = NULL;
-  ArmOpcode opcode = kThumbBkpt;
+  LIR* load = nullptr;
+  ArmOpcode opcode16 = kThumbBkpt;  // 16-bit Thumb opcode.
+  ArmOpcode opcode32 = kThumbBkpt;  // 32-bit Thumb2 opcode.
   bool short_form = false;
-  bool thumb2Form = (displacement < 4092 && displacement >= 0);
   bool all_low = r_dest.Is32Bit() && r_base.Low8() && r_dest.Low8();
-  int encoded_disp = displacement;
+  int scale = 0;  // Used for opcode16 and some indexed loads.
   bool already_generated = false;
   switch (size) {
     case kDouble:
@@ -886,57 +939,45 @@
         already_generated = true;
         break;
       }
+      DCHECK_EQ((displacement & 0x3), 0);
+      scale = 2;
       if (r_dest.Low8() && (r_base == rs_rARM_PC) && (displacement <= 1020) &&
           (displacement >= 0)) {
         short_form = true;
-        encoded_disp >>= 2;
-        opcode = kThumbLdrPcRel;
+        opcode16 = kThumbLdrPcRel;
       } else if (r_dest.Low8() && (r_base == rs_rARM_SP) && (displacement <= 1020) &&
                  (displacement >= 0)) {
         short_form = true;
-        encoded_disp >>= 2;
-        opcode = kThumbLdrSpRel;
-      } else if (all_low && displacement < 128 && displacement >= 0) {
-        DCHECK_EQ((displacement & 0x3), 0);
-        short_form = true;
-        encoded_disp >>= 2;
-        opcode = kThumbLdrRRI5;
-      } else if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2LdrRRI12;
+        opcode16 = kThumbLdrSpRel;
+      } else {
+        short_form = all_low && (displacement >> (5 + scale)) == 0;
+        opcode16 = kThumbLdrRRI5;
+        opcode32 = kThumb2LdrRRI12;
       }
       break;
     case kUnsignedHalf:
-      if (all_low && displacement < 64 && displacement >= 0) {
-        DCHECK_EQ((displacement & 0x1), 0);
-        short_form = true;
-        encoded_disp >>= 1;
-        opcode = kThumbLdrhRRI5;
-      } else if (displacement < 4092 && displacement >= 0) {
-        short_form = true;
-        opcode = kThumb2LdrhRRI12;
-      }
+      DCHECK_EQ((displacement & 0x1), 0);
+      scale = 1;
+      short_form = all_low && (displacement >> (5 + scale)) == 0;
+      opcode16 = kThumbLdrhRRI5;
+      opcode32 = kThumb2LdrhRRI12;
       break;
     case kSignedHalf:
-      if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2LdrshRRI12;
-      }
+      DCHECK_EQ((displacement & 0x1), 0);
+      scale = 1;
+      DCHECK_EQ(opcode16, kThumbBkpt);  // Not available.
+      opcode32 = kThumb2LdrshRRI12;
       break;
     case kUnsignedByte:
-      if (all_low && displacement < 32 && displacement >= 0) {
-        short_form = true;
-        opcode = kThumbLdrbRRI5;
-      } else if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2LdrbRRI12;
-      }
+      DCHECK_EQ(scale, 0);  // Keep scale = 0.
+      short_form = all_low && (displacement >> (5 + scale)) == 0;
+      opcode16 = kThumbLdrbRRI5;
+      opcode32 = kThumb2LdrbRRI12;
       break;
     case kSignedByte:
-      if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2LdrsbRRI12;
-      }
+      DCHECK_EQ(scale, 0);  // Keep scale = 0.
+      DCHECK_EQ(opcode16, kThumbBkpt);  // Not available.
+      opcode32 = kThumb2LdrsbRRI12;
       break;
     default:
       LOG(FATAL) << "Bad size: " << size;
@@ -944,19 +985,40 @@
 
   if (!already_generated) {
     if (short_form) {
-      load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), encoded_disp);
+      load = NewLIR3(opcode16, r_dest.GetReg(), r_base.GetReg(), displacement >> scale);
+    } else if ((displacement >> 12) == 0) {  // Thumb2 form.
+      load = NewLIR3(opcode32, r_dest.GetReg(), r_base.GetReg(), displacement);
+    } else if (!InexpensiveConstantInt(displacement >> scale, Instruction::CONST) &&
+        InexpensiveConstantInt(displacement & ~0x00000fff, Instruction::ADD_INT)) {
+      // In this case, using LoadIndexed would emit 3 insns (movw+movt+ldr) but we can
+      // actually do it in two because we know that the kOpAdd is a single insn. On the
+      // other hand, we introduce an extra dependency, so this is not necessarily faster.
+      if (opcode16 != kThumbBkpt && r_dest.Low8() &&
+          InexpensiveConstantInt(displacement & ~(0x1f << scale), Instruction::ADD_INT)) {
+        // We can use the 16-bit Thumb opcode for the load.
+        OpRegRegImm(kOpAdd, r_dest, r_base, displacement & ~(0x1f << scale));
+        load = NewLIR3(opcode16, r_dest.GetReg(), r_dest.GetReg(), (displacement >> scale) & 0x1f);
+      } else {
+        DCHECK_NE(opcode32, kThumbBkpt);
+        OpRegRegImm(kOpAdd, r_dest, r_base, displacement & ~0x00000fff);
+        load = NewLIR3(opcode32, r_dest.GetReg(), r_dest.GetReg(), displacement & 0x00000fff);
+      }
     } else {
+      if (!InexpensiveConstantInt(displacement >> scale, Instruction::CONST) ||
+          (scale != 0 && InexpensiveConstantInt(displacement, Instruction::CONST))) {
+        scale = 0;  // Prefer unscaled indexing if the same number of insns.
+      }
       RegStorage reg_offset = AllocTemp();
-      LoadConstant(reg_offset, encoded_disp);
+      LoadConstant(reg_offset, displacement >> scale);
       DCHECK(!r_dest.IsFloat());
-      load = LoadBaseIndexed(r_base, reg_offset, r_dest, 0, size);
+      load = LoadBaseIndexed(r_base, reg_offset, r_dest, scale, size);
       FreeTemp(reg_offset);
     }
   }
 
   // TODO: in future may need to differentiate Dalvik accesses w/ spills
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rARM_SP);
+    DCHECK_EQ(r_base, rs_rARM_SP);
     AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
   }
   return load;
@@ -969,18 +1031,17 @@
     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()->HasAtomicLdrdAndStrd()) {
     // 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().
     // Use LDREXD for the atomic load. (Expect displacement > 0, don't optimize for == 0.)
     RegStorage r_ptr = AllocTemp();
     OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
-    LIR* lir = NewLIR3(kThumb2Ldrexd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_ptr.GetReg());
+    load = NewLIR3(kThumb2Ldrexd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_ptr.GetReg());
     FreeTemp(r_ptr);
-    return lir;
   } else {
     load = LoadBaseDispBody(r_base, displacement, r_dest, size);
   }
@@ -995,18 +1056,24 @@
 
 LIR* ArmMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
                                    OpSize size) {
-  LIR* store = NULL;
-  ArmOpcode opcode = kThumbBkpt;
+  LIR* store = nullptr;
+  ArmOpcode opcode16 = kThumbBkpt;  // 16-bit Thumb opcode.
+  ArmOpcode opcode32 = kThumbBkpt;  // 32-bit Thumb2 opcode.
   bool short_form = false;
-  bool thumb2Form = (displacement < 4092 && displacement >= 0);
   bool all_low = r_src.Is32Bit() && r_base.Low8() && r_src.Low8();
-  int encoded_disp = displacement;
+  int scale = 0;  // Used for opcode16 and some indexed loads.
   bool already_generated = false;
   switch (size) {
     case kDouble:
     // Intentional fall-though.
     case k64:
       if (r_src.IsFloat()) {
+        // Note: If the register is retrieved by register allocator, it should never be a pair.
+        // But some functions in mir2lir assume 64-bit registers are 32-bit register pairs.
+        // TODO: Rework Mir2Lir::LoadArg() and Mir2Lir::LoadArgDirect().
+        if (r_src.IsPair()) {
+          r_src = As64BitFloatReg(r_src);
+        }
         DCHECK(!r_src.IsPair());
         store = LoadStoreUsingInsnWithOffsetImm8Shl2(kThumb2Vstrd, r_base, displacement, r_src);
       } else {
@@ -1026,60 +1093,74 @@
         already_generated = true;
         break;
       }
+      DCHECK_EQ((displacement & 0x3), 0);
+      scale = 2;
       if (r_src.Low8() && (r_base == rs_r13sp) && (displacement <= 1020) && (displacement >= 0)) {
         short_form = true;
-        encoded_disp >>= 2;
-        opcode = kThumbStrSpRel;
-      } else if (all_low && displacement < 128 && displacement >= 0) {
-        DCHECK_EQ((displacement & 0x3), 0);
-        short_form = true;
-        encoded_disp >>= 2;
-        opcode = kThumbStrRRI5;
-      } else if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2StrRRI12;
+        opcode16 = kThumbStrSpRel;
+      } else {
+        short_form = all_low && (displacement >> (5 + scale)) == 0;
+        opcode16 = kThumbStrRRI5;
+        opcode32 = kThumb2StrRRI12;
       }
       break;
     case kUnsignedHalf:
     case kSignedHalf:
-      if (all_low && displacement < 64 && displacement >= 0) {
-        DCHECK_EQ((displacement & 0x1), 0);
-        short_form = true;
-        encoded_disp >>= 1;
-        opcode = kThumbStrhRRI5;
-      } else if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2StrhRRI12;
-      }
+      DCHECK_EQ((displacement & 0x1), 0);
+      scale = 1;
+      short_form = all_low && (displacement >> (5 + scale)) == 0;
+      opcode16 = kThumbStrhRRI5;
+      opcode32 = kThumb2StrhRRI12;
       break;
     case kUnsignedByte:
     case kSignedByte:
-      if (all_low && displacement < 32 && displacement >= 0) {
-        short_form = true;
-        opcode = kThumbStrbRRI5;
-      } else if (thumb2Form) {
-        short_form = true;
-        opcode = kThumb2StrbRRI12;
-      }
+      DCHECK_EQ(scale, 0);  // Keep scale = 0.
+      short_form = all_low && (displacement >> (5 + scale)) == 0;
+      opcode16 = kThumbStrbRRI5;
+      opcode32 = kThumb2StrbRRI12;
       break;
     default:
       LOG(FATAL) << "Bad size: " << size;
   }
   if (!already_generated) {
     if (short_form) {
-      store = NewLIR3(opcode, r_src.GetReg(), r_base.GetReg(), encoded_disp);
-    } else {
+      store = NewLIR3(opcode16, r_src.GetReg(), r_base.GetReg(), displacement >> scale);
+    } else if ((displacement >> 12) == 0) {
+      store = NewLIR3(opcode32, r_src.GetReg(), r_base.GetReg(), displacement);
+    } else if (!InexpensiveConstantInt(displacement >> scale, Instruction::CONST) &&
+        InexpensiveConstantInt(displacement & ~0x00000fff, Instruction::ADD_INT)) {
+      // In this case, using StoreIndexed would emit 3 insns (movw+movt+str) but we can
+      // actually do it in two because we know that the kOpAdd is a single insn. On the
+      // other hand, we introduce an extra dependency, so this is not necessarily faster.
       RegStorage r_scratch = AllocTemp();
-      LoadConstant(r_scratch, encoded_disp);
+      if (opcode16 != kThumbBkpt && r_src.Low8() && r_scratch.Low8() &&
+          InexpensiveConstantInt(displacement & ~(0x1f << scale), Instruction::ADD_INT)) {
+        // We can use the 16-bit Thumb opcode for the load.
+        OpRegRegImm(kOpAdd, r_scratch, r_base, displacement & ~(0x1f << scale));
+        store = NewLIR3(opcode16, r_src.GetReg(), r_scratch.GetReg(),
+                        (displacement >> scale) & 0x1f);
+      } else {
+        DCHECK_NE(opcode32, kThumbBkpt);
+        OpRegRegImm(kOpAdd, r_scratch, r_base, displacement & ~0x00000fff);
+        store = NewLIR3(opcode32, r_src.GetReg(), r_scratch.GetReg(), displacement & 0x00000fff);
+      }
+      FreeTemp(r_scratch);
+    } else {
+      if (!InexpensiveConstantInt(displacement >> scale, Instruction::CONST) ||
+          (scale != 0 && InexpensiveConstantInt(displacement, Instruction::CONST))) {
+        scale = 0;  // Prefer unscaled indexing if the same number of insns.
+      }
+      RegStorage r_scratch = AllocTemp();
+      LoadConstant(r_scratch, displacement >> scale);
       DCHECK(!r_src.IsFloat());
-      store = StoreBaseIndexed(r_base, r_scratch, r_src, 0, size);
+      store = StoreBaseIndexed(r_base, r_scratch, r_src, scale, size);
       FreeTemp(r_scratch);
     }
   }
 
   // TODO: In future, may need to differentiate Dalvik & spill accesses
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rARM_SP);
+    DCHECK_EQ(r_base, rs_rARM_SP);
     AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
   }
   return store;
@@ -1092,10 +1173,10 @@
     GenMemBarrier(kAnyStore);
   }
 
-  LIR* store;
-  if (UNLIKELY(is_volatile == kVolatile &&
-               (size == k64 || size == kDouble) &&
-               !cu_->compiler_driver->GetInstructionSetFeatures().HasLpae())) {
+  LIR* null_ck_insn;
+  if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
+      !cu_->compiler_driver->GetInstructionSetFeatures()->
+          AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()) {
     // 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.)
@@ -1109,17 +1190,16 @@
     RegStorage r_temp = AllocTemp();
     RegStorage r_temp_high = AllocTemp(false);  // We may not have another temp.
     if (r_temp_high.Valid()) {
-      NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_temp_high.GetReg(), r_ptr.GetReg());
+      null_ck_insn = NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_temp_high.GetReg(), r_ptr.GetReg());
       FreeTemp(r_temp_high);
       FreeTemp(r_temp);
     } else {
       // If we don't have another temp, clobber r_ptr in LDREXD and reload it.
-      NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_ptr.GetReg(), r_ptr.GetReg());
+      null_ck_insn = NewLIR3(kThumb2Ldrexd, r_temp.GetReg(), r_ptr.GetReg(), r_ptr.GetReg());
       FreeTemp(r_temp);  // May need the temp for kOpAdd.
       OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
     }
-    store = NewLIR4(kThumb2Strexd, r_temp.GetReg(), r_src.GetLowReg(), r_src.GetHighReg(),
-                    r_ptr.GetReg());
+    NewLIR4(kThumb2Strexd, r_temp.GetReg(), r_src.GetLowReg(), r_src.GetHighReg(), r_ptr.GetReg());
     OpCmpImmBranch(kCondNe, r_temp, 0, fail_target);
     FreeTemp(r_ptr);
   } else {
@@ -1128,7 +1208,7 @@
       size = k32;
     }
 
-    store = StoreBaseDispBody(r_base, displacement, r_src, size);
+    null_ck_insn = StoreBaseDispBody(r_base, displacement, r_src, size);
   }
 
   if (UNLIKELY(is_volatile == kVolatile)) {
@@ -1137,7 +1217,7 @@
     GenMemBarrier(kAnyAny);
   }
 
-  return store;
+  return null_ck_insn;
 }
 
 LIR* ArmMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
@@ -1161,11 +1241,13 @@
 }
 
 LIR* ArmMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
+  UNUSED(op, r_base, disp);
   LOG(FATAL) << "Unexpected use of OpMem for Arm";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* ArmMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
+  UNUSED(trampoline);  // The address of the trampoline is already loaded into r_tgt.
   return OpReg(op, r_tgt);
 }
 
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index ab71921..943c5c1 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -117,6 +117,7 @@
 #define IS_SIGNED_IMM14(value) IS_SIGNED_IMM(14, value)
 #define IS_SIGNED_IMM19(value) IS_SIGNED_IMM(19, value)
 #define IS_SIGNED_IMM21(value) IS_SIGNED_IMM(21, value)
+#define IS_SIGNED_IMM26(value) IS_SIGNED_IMM(26, value)
 
 // Quick macro used to define the registers.
 #define A64_REGISTER_CODE_LIST(R) \
@@ -126,7 +127,7 @@
   R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
 
 // Registers (integer) values.
-enum A64NativeRegisterPool {
+enum A64NativeRegisterPool {  // private marker to avoid generate-operator-out.py from processing.
 #  define A64_DEFINE_REGISTERS(nr) \
     rw##nr = RegStorage::k32BitSolo | RegStorage::kCoreRegister | nr, \
     rx##nr = RegStorage::k64BitSolo | RegStorage::kCoreRegister | nr, \
@@ -240,6 +241,7 @@
   kA64B2ct,          // b.cond [01010100] imm_19[23-5] [0] cond[3-0].
   kA64Blr1x,         // blr [1101011000111111000000] rn[9-5] [00000].
   kA64Br1x,          // br  [1101011000011111000000] rn[9-5] [00000].
+  kA64Bl1t,          // bl  [100101] imm26[25-0].
   kA64Brk1d,         // brk [11010100001] imm_16[20-5] [00000].
   kA64B1t,           // b   [00010100] offset_26[25-0].
   kA64Cbnz2rt,       // cbnz[00110101] imm_19[23-5] rt[4-0].
@@ -310,6 +312,7 @@
   kA64Lsl3rrr,       // lsl [s0011010110] rm[20-16] [001000] rn[9-5] rd[4-0].
   kA64Lsr3rrd,       // lsr alias of "ubfm arg0, arg1, arg2, #{31/63}".
   kA64Lsr3rrr,       // lsr [s0011010110] rm[20-16] [001001] rn[9-5] rd[4-0].
+  kA64Madd4rrrr,     // madd[s0011011000] rm[20-16] [0] ra[14-10] rn[9-5] rd[4-0].
   kA64Movk3rdM,      // mov [010100101] hw[22-21] imm_16[20-5] rd[4-0].
   kA64Movn3rdM,      // mov [000100101] hw[22-21] imm_16[20-5] rd[4-0].
   kA64Movz3rdM,      // mov [011100101] hw[22-21] imm_16[20-5] rd[4-0].
@@ -318,6 +321,7 @@
   kA64Mul3rrr,       // mul [00011011000] rm[20-16] [011111] rn[9-5] rd[4-0].
   kA64Msub4rrrr,     // msub[s0011011000] rm[20-16] [1] ra[14-10] rn[9-5] rd[4-0].
   kA64Neg3rro,       // neg alias of "sub arg0, rzr, arg1, arg2".
+  kA64Nop0,          // nop alias of "hint #0" [11010101000000110010000000011111].
   kA64Orr3Rrl,       // orr [s01100100] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
   kA64Orr4rrro,      // orr [s0101010] shift[23-22] [0] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
   kA64Ret,           // ret [11010110010111110000001111000000].
@@ -330,7 +334,7 @@
   kA64Scvtf2fw,      // scvtf  [000111100s100010000000] rn[9-5] rd[4-0].
   kA64Scvtf2fx,      // scvtf  [100111100s100010000000] rn[9-5] rd[4-0].
   kA64Sdiv3rrr,      // sdiv[s0011010110] rm[20-16] [000011] rn[9-5] rd[4-0].
-  kA64Smaddl4xwwx,   // smaddl [10011011001] rm[20-16] [0] ra[14-10] rn[9-5] rd[4-0].
+  kA64Smull3xww,     // smull [10011011001] rm[20-16] [011111] rn[9-5] rd[4-0].
   kA64Smulh3xxx,     // smulh [10011011010] rm[20-16] [011111] rn[9-5] rd[4-0].
   kA64Stp4ffXD,      // stp [0s10110100] imm_7[21-15] rt2[14-10] rn[9-5] rt[4-0].
   kA64Stp4rrXD,      // stp [s010100100] imm_7[21-15] rt2[14-10] rn[9-5] rt[4-0].
@@ -360,9 +364,10 @@
   kA64Tbz3rht,       // tbz imm_6_b5[31] [0110110] imm_6_b40[23-19] imm_14[18-5] rt[4-0].
   kA64Ubfm4rrdd,     // ubfm[s10100110] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
   kA64Last,
-  kA64NotWide = 0,   // Flag used to select the first instruction variant.
-  kA64Wide = 0x1000  // Flag used to select the second instruction variant.
+  kA64NotWide = kA64First,  // 0 - Flag used to select the first instruction variant.
+  kA64Wide = 0x1000         // Flag used to select the second instruction variant.
 };
+std::ostream& operator<<(std::ostream& os, const A64Opcode& rhs);
 
 /*
  * The A64 instruction set provides two variants for many instructions. For example, "mov wN, wM"
@@ -412,6 +417,7 @@
   kFmtExtend,     // Register extend, 9-bit at [23..21, 15..10].
   kFmtSkip,       // Unused field, but continue to next.
 };
+std::ostream& operator<<(std::ostream& os, const A64EncodingKind & rhs);
 
 // Struct used to define the snippet positions for each A64 opcode.
 struct A64EncodingMap {
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index b1cf279..d45ec49 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#include "arm64_lir.h"
 #include "codegen_arm64.h"
+
+#include "arch/arm64/instruction_set_features_arm64.h"
+#include "arm64_lir.h"
 #include "dex/quick/mir_to_lir-inl.h"
 
 namespace art {
@@ -155,6 +157,10 @@
                  kFmtRegX, 9, 5, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE0 | IS_BRANCH,
                  "br", "!0x", kFixupNone),
+    ENCODING_MAP(kA64Bl1t, NO_VARIANTS(0x94000000),
+                 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR | NEEDS_FIXUP,
+                 "bl", "!0T", kFixupLabel),
     ENCODING_MAP(kA64Brk1d, NO_VARIANTS(0xd4200000),
                  kFmtBitBlt, 20, 5, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
@@ -439,6 +445,10 @@
                  kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "lsr", "!0r, !1r, !2r", kFixupNone),
+    ENCODING_MAP(WIDE(kA64Madd4rrrr), SF_VARIANTS(0x1b000000),
+                 kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
+                 kFmtRegR, 14, 10, IS_QUAD_OP | REG_DEF0_USE123 | NEEDS_FIXUP,
+                 "madd", "!0r, !1r, !2r, !3r", kFixupA53Erratum835769),
     ENCODING_MAP(WIDE(kA64Movk3rdM), SF_VARIANTS(0x72800000),
                  kFmtRegR, 4, 0, kFmtBitBlt, 20, 5, kFmtBitBlt, 22, 21,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE0,
@@ -464,13 +474,17 @@
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "mul", "!0r, !1r, !2r", kFixupNone),
     ENCODING_MAP(WIDE(kA64Msub4rrrr), SF_VARIANTS(0x1b008000),
-                 kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 14, 10,
-                 kFmtRegR, 20, 16, IS_QUAD_OP | REG_DEF0_USE123,
-                 "msub", "!0r, !1r, !3r, !2r", kFixupNone),
+                 kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
+                 kFmtRegR, 14, 10, IS_QUAD_OP | REG_DEF0_USE123 | NEEDS_FIXUP,
+                 "msub", "!0r, !1r, !2r, !3r", kFixupA53Erratum835769),
     ENCODING_MAP(WIDE(kA64Neg3rro), SF_VARIANTS(0x4b0003e0),
                  kFmtRegR, 4, 0, kFmtRegR, 20, 16, kFmtShift, -1, -1,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "neg", "!0r, !1r!2o", kFixupNone),
+    ENCODING_MAP(kA64Nop0, NO_VARIANTS(0xd503201f),
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "nop", "", kFixupNone),
     ENCODING_MAP(WIDE(kA64Orr3Rrl), SF_VARIANTS(0x32000000),
                  kFmtRegROrSp, 4, 0, kFmtRegR, 9, 5, kFmtBitBlt, 22, 10,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
@@ -519,10 +533,10 @@
                  kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "sdiv", "!0r, !1r, !2r", kFixupNone),
-    ENCODING_MAP(WIDE(kA64Smaddl4xwwx), NO_VARIANTS(0x9b200000),
+    ENCODING_MAP(kA64Smull3xww, NO_VARIANTS(0x9b207c00),
                  kFmtRegX, 4, 0, kFmtRegW, 9, 5, kFmtRegW, 20, 16,
-                 kFmtRegX, 14, 10, IS_QUAD_OP | REG_DEF0_USE123,
-                 "smaddl", "!0x, !1w, !2w, !3x", kFixupNone),
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "smull", "!0x, !1w, !2w", kFixupNone),
     ENCODING_MAP(kA64Smulh3xxx, NO_VARIANTS(0x9b407c00),
                  kFmtRegX, 4, 0, kFmtRegX, 9, 5, kFmtRegX, 20, 16,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
@@ -701,16 +715,16 @@
               switch (kind) {
                 case kFmtRegX:
                   want_64_bit = true;
-                  // Intentional fall-through.
+                  FALLTHROUGH_INTENDED;
                 case kFmtRegW:
                   want_var_size = false;
-                  // Intentional fall-through.
+                  FALLTHROUGH_INTENDED;
                 case kFmtRegR:
                   want_zero = true;
                   break;
                 case kFmtRegXOrSp:
                   want_64_bit = true;
-                  // Intentional fall-through.
+                  FALLTHROUGH_INTENDED;
                 case kFmtRegWOrSp:
                   want_var_size = false;
                   break;
@@ -718,10 +732,10 @@
                   break;
                 case kFmtRegD:
                   want_64_bit = true;
-                  // Intentional fall-through.
+                  FALLTHROUGH_INTENDED;
                 case kFmtRegS:
                   want_var_size = false;
-                  // Intentional fall-through.
+                  FALLTHROUGH_INTENDED;
                 case kFmtRegF:
                   want_float = true;
                   break;
@@ -775,8 +789,8 @@
             // and zr. This means that these two registers do not need any special treatment, as
             // their bottom 5 bits are correctly set to 31 == 0b11111, which is the right
             // value for encoding both sp and zr.
-            COMPILE_ASSERT((rxzr & 0x1f) == 0x1f, rzr_register_number_must_be_31);
-            COMPILE_ASSERT((rsp & 0x1f) == 0x1f, rsp_register_number_must_be_31);
+            static_assert((rxzr & 0x1f) == 0x1f, "rzr register number must be 31");
+            static_assert((rsp & 0x1f) == 0x1f, "rsp register number must be 31");
           }
 
           value = (operand << encoder->field_loc[i].start) &
@@ -830,6 +844,20 @@
 // are better set directly from the code (they will require no more than 2 instructions).
 #define ALIGNED_DATA_OFFSET(offset) (((offset) + 0x7) & ~0x7)
 
+/*
+ * Get the LIR which emits the instruction preceding the given LIR.
+ * Returns nullptr, if no previous emitting insn found.
+ */
+static LIR* GetPrevEmittingLIR(LIR* lir) {
+  DCHECK(lir != nullptr);
+  LIR* prev_lir = lir->prev;
+  while ((prev_lir != nullptr) &&
+         (prev_lir->flags.is_nop || Mir2Lir::IsPseudoLirOp(prev_lir->opcode))) {
+    prev_lir = prev_lir->prev;
+  }
+  return prev_lir;
+}
+
 // Assemble the LIR into binary instruction format.
 void Arm64Mir2Lir::AssembleLIR() {
   LIR* lir;
@@ -873,10 +901,18 @@
               ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
           int32_t delta = target - pc;
           DCHECK_EQ(delta & 0x3, 0);
-          if (!IS_SIGNED_IMM19(delta >> 2)) {
+          if (!IS_SIGNED_IMM26(delta >> 2)) {
             LOG(FATAL) << "Invalid jump range in kFixupT1Branch";
           }
           lir->operands[0] = delta >> 2;
+          if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && lir->operands[0] == 1) {
+            // Useless branch.
+            offset_adjustment -= lir->flags.size;
+            lir->flags.is_nop = true;
+            // Don't unlink - just set to do-nothing.
+            lir->flags.fixup = kFixupNone;
+            res = kRetryAll;
+          }
           break;
         }
         case kFixupLoad:
@@ -924,14 +960,13 @@
           // Check if branch offset can be encoded in tbz/tbnz.
           if (!IS_SIGNED_IMM14(delta >> 2)) {
             DexOffset dalvik_offset = lir->dalvik_offset;
-            int16_t opcode = lir->opcode;
-            LIR* target = lir->target;
+            LIR* targetLIR = lir->target;
             // "tbz/tbnz Rt, #imm, label" -> "tst Rt, #(1<<imm)".
             offset_adjustment -= lir->flags.size;
-            int32_t imm = EncodeLogicalImmediate(IS_WIDE(opcode), 1 << lir->operands[1]);
-            DCHECK_NE(imm, -1);
+            int32_t encodedImm = EncodeLogicalImmediate(IS_WIDE(opcode), 1 << lir->operands[1]);
+            DCHECK_NE(encodedImm, -1);
             lir->opcode = IS_WIDE(opcode) ? WIDE(kA64Tst2rl) : kA64Tst2rl;
-            lir->operands[1] = imm;
+            lir->operands[1] = encodedImm;
             lir->target = nullptr;
             lir->flags.fixup = EncodingMap[kA64Tst2rl].fixup;
             lir->flags.size = EncodingMap[kA64Tst2rl].size;
@@ -940,7 +975,7 @@
             opcode = UNWIDE(opcode);
             DCHECK(opcode == kA64Tbz3rht || opcode == kA64Tbnz3rht);
             LIR* new_lir = RawLIR(dalvik_offset, kA64B2ct,
-                opcode == kA64Tbz3rht ? kArmCondEq : kArmCondNe, 0, 0, 0, 0, target);
+                opcode == kA64Tbz3rht ? kArmCondEq : kArmCondNe, 0, 0, 0, 0, targetLIR);
             InsertLIRAfter(lir, new_lir);
             new_lir->offset = lir->offset + lir->flags.size;
             new_lir->flags.generation = generation;
@@ -977,6 +1012,34 @@
           lir->operands[1] = delta;
           break;
         }
+        case kFixupA53Erratum835769:
+          // Avoid emitting code that could trigger Cortex A53's erratum 835769.
+          // This fixup should be carried out for all multiply-accumulate instructions: madd, msub,
+          // smaddl, smsubl, umaddl and umsubl.
+          if (cu_->GetInstructionSetFeatures()->AsArm64InstructionSetFeatures()
+              ->NeedFixCortexA53_835769()) {
+            // Check that this is a 64-bit multiply-accumulate.
+            if (IS_WIDE(lir->opcode)) {
+              LIR* prev_insn = GetPrevEmittingLIR(lir);
+              if (prev_insn == nullptr) {
+                break;
+              }
+              uint64_t prev_insn_flags = EncodingMap[UNWIDE(prev_insn->opcode)].flags;
+              // Check that the instruction preceding the multiply-accumulate is a load or store.
+              if ((prev_insn_flags & IS_LOAD) != 0 || (prev_insn_flags & IS_STORE) != 0) {
+                // insert a NOP between the load/store and the multiply-accumulate.
+                LIR* new_lir = RawLIR(lir->dalvik_offset, kA64Nop0, 0, 0, 0, 0, 0, NULL);
+                new_lir->offset = lir->offset;
+                new_lir->flags.fixup = kFixupNone;
+                new_lir->flags.size = EncodingMap[kA64Nop0].size;
+                InsertLIRBefore(lir, new_lir);
+                lir->offset += new_lir->flags.size;
+                offset_adjustment += new_lir->flags.size;
+                res = kRetryAll;
+              }
+            }
+          }
+          break;
         default:
           LOG(FATAL) << "Unexpected case " << lir->flags.fixup;
       }
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 6081f28..089e4b6 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -21,6 +21,8 @@
 #include "dex/quick/mir_to_lir-inl.h"
 #include "gc/accounting/card_table.h"
 #include "entrypoints/quick/quick_entrypoints.h"
+#include "mirror/art_method.h"
+#include "mirror/object_array-inl.h"
 
 namespace art {
 
@@ -147,41 +149,6 @@
 }
 
 /*
- * Array data table format:
- *  ushort ident = 0x0300   magic value
- *  ushort width            width of each element in the table
- *  uint   size             number of elements in the table
- *  ubyte  data[size*width] table of data values (may contain a single-byte
- *                          padding at the end)
- *
- * Total size is 4+(width * size + 1)/2 16-bit code units.
- */
-void Arm64Mir2Lir::GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
-  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
-  // Add the table to the list - we'll process it later
-  FillArrayData *tab_rec =
-      static_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData), kArenaAllocData));
-  tab_rec->table = table;
-  tab_rec->vaddr = current_dalvik_offset_;
-  uint16_t width = tab_rec->table[1];
-  uint32_t size = tab_rec->table[2] | ((static_cast<uint32_t>(tab_rec->table[3])) << 16);
-  tab_rec->size = (size * width) + 8;
-
-  fill_array_data_.push_back(tab_rec);
-
-  // Making a call - use explicit registers
-  FlushAllRegs();   /* Everything to home location */
-  LoadValueDirectFixed(rl_src, rs_x0);
-  LoadWordDisp(rs_xSELF, QUICK_ENTRYPOINT_OFFSET(8, pHandleFillArrayData).Int32Value(),
-               rs_xLR);
-  // Materialize a pointer to the fill data image
-  NewLIR3(kA64Adr2xd, rx1, 0, WrapPointer(tab_rec));
-  ClobberCallerSave();
-  LIR* call_inst = OpReg(kOpBlx, rs_xLR);
-  MarkSafepointPC(call_inst);
-}
-
-/*
  * Handle unlocked -> thin locked transition inline or else call out to quick entrypoint. For more
  * details see monitor.cc.
  */
@@ -284,20 +251,14 @@
   StoreValue(rl_dest, rl_result);
 }
 
-/*
- * Mark garbage collection card. Skip if the value we're storing is null.
- */
-void Arm64Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void Arm64Mir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) {
   RegStorage reg_card_base = AllocTempWide();
   RegStorage reg_card_no = AllocTempWide();  // Needs to be wide as addr is ref=64b
-  LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   LoadWordDisp(rs_xSELF, Thread::CardTableOffset<8>().Int32Value(), reg_card_base);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   // TODO(Arm64): generate "strb wB, [xB, wC, uxtw]" rather than "strb wB, [xB, xC]"?
   StoreBaseIndexed(reg_card_base, reg_card_no, As32BitReg(reg_card_base),
                    0, kUnsignedByte);
-  LIR* target = NewLIR0(kPseudoTargetLabel);
-  branch_over->target = target;
   FreeTemp(reg_card_base);
   FreeTemp(reg_card_no);
 }
@@ -329,7 +290,8 @@
    * We can safely skip the stack overflow check if we're
    * a leaf *and* our frame size < fudge factor.
    */
-  bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, kArm64);
+  bool skip_overflow_check = mir_graph_->MethodIsLeaf() &&
+    !FrameNeedsStackCheck(frame_size_, kArm64);
 
   NewLIR0(kPseudoMethodEntry);
 
@@ -353,7 +315,7 @@
       // TODO: If the frame size is small enough, is it possible to make this a pre-indexed load,
       //       so that we can avoid the following "sub sp" when spilling?
       OpRegRegImm(kOpSub, rs_x8, rs_sp, GetStackOverflowReservedBytes(kArm64));
-      LoadWordDisp(rs_x8, 0, rs_x8);
+      Load32Disp(rs_x8, 0, rs_wzr);
       MarkPossibleStackOverflowException();
     }
   }
@@ -433,4 +395,119 @@
   NewLIR0(kA64Ret);
 }
 
+static bool Arm64UseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) {
+  UNUSED(cu, target_method);
+  // Always emit relative calls.
+  return true;
+}
+
+/*
+ * Bit of a hack here - in the absence of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+static int Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
+                               int state, const MethodReference& target_method,
+                               uint32_t unused_idx,
+                               uintptr_t direct_code, uintptr_t direct_method,
+                               InvokeType type) {
+  UNUSED(info, unused_idx);
+  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
+  if (direct_code != 0 && direct_method != 0) {
+    switch (state) {
+    case 0:  // Get the current Method* [sets kArg0]
+      if (direct_code != static_cast<uintptr_t>(-1)) {
+        cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
+      } else if (Arm64UseRelativeCall(cu, target_method)) {
+        // Defer to linker patch.
+      } else {
+        cg->LoadCodeAddress(target_method, type, kInvokeTgt);
+      }
+      if (direct_method != static_cast<uintptr_t>(-1)) {
+        cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method);
+      } else {
+        cg->LoadMethodAddress(target_method, type, kArg0);
+      }
+      break;
+    default:
+      return -1;
+    }
+  } else {
+    RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
+    switch (state) {
+    case 0:  // Get the current Method* [sets kArg0]
+      // TUNING: we can save a reg copy if Method* has been promoted.
+      cg->LoadCurrMethodDirect(arg0_ref);
+      break;
+    case 1:  // Get method->dex_cache_resolved_methods_
+      cg->LoadRefDisp(arg0_ref,
+                      mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+                      arg0_ref,
+                      kNotVolatile);
+      // Set up direct code if known.
+      if (direct_code != 0) {
+        if (direct_code != static_cast<uintptr_t>(-1)) {
+          cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
+        } else if (Arm64UseRelativeCall(cu, target_method)) {
+          // Defer to linker patch.
+        } else {
+          CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
+          cg->LoadCodeAddress(target_method, type, kInvokeTgt);
+        }
+      }
+      break;
+    case 2:  // Grab target method*
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
+      cg->LoadRefDisp(arg0_ref,
+                      mirror::ObjectArray<mirror::Object>::OffsetOfElement(
+                          target_method.dex_method_index).Int32Value(),
+                      arg0_ref,
+                      kNotVolatile);
+      break;
+    case 3:  // Grab the code from the method*
+      if (direct_code == 0) {
+        // kInvokeTgt := arg0_ref->entrypoint
+        cg->LoadWordDisp(arg0_ref,
+                         mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+                             kArm64PointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt));
+      }
+      break;
+    default:
+      return -1;
+    }
+  }
+  return state + 1;
+}
+
+NextCallInsn Arm64Mir2Lir::GetNextSDCallInsn() {
+  return Arm64NextSDCallInsn;
+}
+
+LIR* Arm64Mir2Lir::CallWithLinkerFixup(const MethodReference& target_method, InvokeType type) {
+  // For ARM64, just generate a relative BL instruction that will be filled in at 'link time'.
+  // If the target turns out to be too far, the linker will generate a thunk for dispatch.
+  int target_method_idx = target_method.dex_method_index;
+  const DexFile* target_dex_file = target_method.dex_file;
+
+  // Generate the call instruction and save index, dex_file, and type.
+  // NOTE: Method deduplication takes linker patches into account, so we can just pass 0
+  // as a placeholder for the offset.
+  LIR* call = RawLIR(current_dalvik_offset_, kA64Bl1t, 0,
+                     target_method_idx, WrapPointer(const_cast<DexFile*>(target_dex_file)), type);
+  AppendLIR(call);
+  call_method_insns_.push_back(call);
+  return call;
+}
+
+LIR* Arm64Mir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info) {
+  LIR* call_insn;
+  if (method_info.FastPath() && Arm64UseRelativeCall(cu_, method_info.GetTargetMethod()) &&
+      (method_info.GetSharpType() == kDirect || method_info.GetSharpType() == kStatic) &&
+      method_info.DirectCode() == static_cast<uintptr_t>(-1)) {
+    call_insn = CallWithLinkerFixup(method_info.GetTargetMethod(), method_info.GetSharpType());
+  } else {
+    call_insn = OpReg(kOpBlx, TargetPtrReg(kInvokeTgt));
+  }
+  return call_insn;
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 55cc938..c68b1d0 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -27,38 +27,25 @@
 
 class Arm64Mir2Lir FINAL : public Mir2Lir {
  protected:
-  // TODO: consolidate 64-bit target support.
-  class InToRegStorageMapper {
-   public:
-    virtual RegStorage GetNextReg(bool is_double_or_float, bool is_wide, bool is_ref) = 0;
-    virtual ~InToRegStorageMapper() {}
-  };
-
   class InToRegStorageArm64Mapper : public InToRegStorageMapper {
    public:
     InToRegStorageArm64Mapper() : cur_core_reg_(0), cur_fp_reg_(0) {}
     virtual ~InToRegStorageArm64Mapper() {}
-    virtual RegStorage GetNextReg(bool is_double_or_float, bool is_wide, bool is_ref);
+    virtual RegStorage GetNextReg(ShortyArg arg);
+    virtual void Reset() OVERRIDE {
+      cur_core_reg_ = 0;
+      cur_fp_reg_ = 0;
+    }
    private:
-    int cur_core_reg_;
-    int cur_fp_reg_;
+    size_t cur_core_reg_;
+    size_t cur_fp_reg_;
   };
 
-  class InToRegStorageMapping {
-   public:
-    InToRegStorageMapping() : max_mapped_in_(0), is_there_stack_mapped_(false),
-    initialized_(false) {}
-    void Initialize(RegLocation* arg_locs, int count, InToRegStorageMapper* mapper);
-    int GetMaxMappedIn() { return max_mapped_in_; }
-    bool IsThereStackMapped() { return is_there_stack_mapped_; }
-    RegStorage Get(int in_position);
-    bool IsInitialized() { return initialized_; }
-   private:
-    std::map<int, RegStorage> mapping_;
-    int max_mapped_in_;
-    bool is_there_stack_mapped_;
-    bool initialized_;
-  };
+  InToRegStorageArm64Mapper in_to_reg_storage_arm64_mapper_;
+  InToRegStorageMapper* GetResetedInToRegStorageMapper() OVERRIDE {
+    in_to_reg_storage_arm64_mapper_.Reset();
+    return &in_to_reg_storage_arm64_mapper_;
+  }
 
  public:
   Arm64Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
@@ -71,26 +58,26 @@
   bool HandleEasyDivRem64(Instruction::Code dalvik_opcode, bool is_div,
                           RegLocation rl_src, RegLocation rl_dest, int64_t lit);
   bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
+  void GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                  int32_t constant) OVERRIDE;
+  void GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                   int64_t constant) OVERRIDE;
   LIR* CheckSuspendUsingLoad() OVERRIDE;
   RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
   LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
                     OpSize size, VolatileKind is_volatile) OVERRIDE;
-  LIR* LoadRefDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                   VolatileKind is_volatile) OVERRIDE;
   LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                        OpSize size) OVERRIDE;
-  LIR* LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale)
-      OVERRIDE;
   LIR* LoadConstantNoClobber(RegStorage r_dest, int value) OVERRIDE;
   LIR* LoadConstantWide(RegStorage r_dest, int64_t value) OVERRIDE;
   LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
                      VolatileKind is_volatile) OVERRIDE;
-  LIR* StoreRefDisp(RegStorage r_base, int displacement, RegStorage r_src, VolatileKind is_volatile)
-      OVERRIDE;
   LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                         OpSize size) OVERRIDE;
-  LIR* StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale) OVERRIDE;
-  void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) OVERRIDE;
+
+  /// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
+  void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
+
   LIR* OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
                          int offset, int check_value, LIR* target, LIR** compare) OVERRIDE;
 
@@ -106,7 +93,6 @@
   RegStorage TargetPtrReg(SpecialTargetRegister symbolic_reg) OVERRIDE {
     return As64BitReg(TargetReg(symbolic_reg));
   }
-  RegStorage GetArgMappingToPhysicalReg(int arg_num) OVERRIDE;
   RegLocation GetReturnAlt() OVERRIDE;
   RegLocation GetReturnWideAlt() OVERRIDE;
   RegLocation LocCReturn() OVERRIDE;
@@ -141,13 +127,13 @@
   void GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                       RegLocation lr_shift) OVERRIDE;
   void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                         RegLocation rl_src2) OVERRIDE;
+                         RegLocation rl_src2, int flags) OVERRIDE;
   void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, RegLocation rl_index,
                    RegLocation rl_dest, int scale) OVERRIDE;
   void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, RegLocation rl_index,
                    RegLocation rl_src, int scale, bool card_mark) OVERRIDE;
   void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                         RegLocation rl_shift) OVERRIDE;
+                         RegLocation rl_shift, int flags) OVERRIDE;
   void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                         RegLocation rl_src2) OVERRIDE;
   void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
@@ -173,7 +159,7 @@
   bool GenInlinedArrayCopyCharArray(CallInfo* info) OVERRIDE;
   void GenIntToLong(RegLocation rl_dest, RegLocation rl_src) OVERRIDE;
   void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                      RegLocation rl_src2) OVERRIDE;
+                      RegLocation rl_src2, int flags) OVERRIDE;
   RegLocation GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi, bool is_div)
       OVERRIDE;
   RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div)
@@ -183,13 +169,12 @@
   void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
   void GenExitSequence() OVERRIDE;
   void GenSpecialExitSequence() OVERRIDE;
-  void GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) OVERRIDE;
   void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) OVERRIDE;
   void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) OVERRIDE;
   void GenSelect(BasicBlock* bb, MIR* mir) OVERRIDE;
   void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                         int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                        int dest_reg_class) OVERRIDE;
+                        RegisterClass dest_reg_class) OVERRIDE;
 
   bool GenMemBarrier(MemBarrierKind barrier_kind) OVERRIDE;
   void GenMonitorEnter(int opt_flags, RegLocation rl_src) OVERRIDE;
@@ -201,6 +186,10 @@
   void GenNegFloat(RegLocation rl_dest, RegLocation rl_src) OVERRIDE;
   void GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) OVERRIDE;
   void GenLargeSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) OVERRIDE;
+  void GenMaddMsubInt(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                      RegLocation rl_src3, bool is_sub);
+  void GenMaddMsubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                       RegLocation rl_src3, bool is_sub);
 
   // Required for target - single operation generators.
   LIR* OpUnconditionalBranch(LIR* target) OVERRIDE;
@@ -234,31 +223,39 @@
   bool InexpensiveConstantLong(int64_t value) OVERRIDE;
   bool InexpensiveConstantDouble(int64_t value) OVERRIDE;
 
-  void FlushIns(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
+  void GenMachineSpecificExtendedMethodMIR(BasicBlock* bb, MIR* mir) OVERRIDE;
 
-  int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                           NextCallInsn next_call_insn,
-                           const MethodReference& target_method,
-                           uint32_t vtable_idx,
-                           uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                           bool skip_this) OVERRIDE;
-
-  int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                         NextCallInsn next_call_insn,
-                         const MethodReference& target_method,
-                         uint32_t vtable_idx,
-                         uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                         bool skip_this) OVERRIDE;
-
-  bool WideGPRsAreAliases() OVERRIDE {
+  bool WideGPRsAreAliases() const OVERRIDE {
     return true;  // 64b architecture.
   }
-  bool WideFPRsAreAliases() OVERRIDE {
+  bool WideFPRsAreAliases() const OVERRIDE {
     return true;  // 64b architecture.
   }
 
   size_t GetInstructionOffset(LIR* lir) OVERRIDE;
 
+  NextCallInsn GetNextSDCallInsn() OVERRIDE;
+
+  /*
+   * @brief Generate a relative call to the method that will be patched at link time.
+   * @param target_method The MethodReference of the method to be invoked.
+   * @param type How the method will be invoked.
+   * @returns Call instruction
+   */
+  LIR* CallWithLinkerFixup(const MethodReference& target_method, InvokeType type);
+
+  /*
+   * @brief Generate the actual call insn based on the method info.
+   * @param method_info the lowering info for the method call.
+   * @returns Call instruction
+   */
+  virtual LIR* GenCallInsn(const MirMethodLoweringInfo& method_info) OVERRIDE;
+
+  /*
+   * @brief Handle ARM specific literals.
+   */
+  void InstallLiteralPools() OVERRIDE;
+
   LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
 
  private:
@@ -342,8 +339,8 @@
   void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
   void AssignDataOffsets();
   RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
-                        bool is_div, bool check_zero);
-  RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);
+                        bool is_div, int flags) OVERRIDE;
+  RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) OVERRIDE;
   size_t GetLoadStoreSize(LIR* lir);
 
   bool SmallLiteralDivRem64(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
@@ -392,10 +389,13 @@
   void GenNotLong(RegLocation rl_dest, RegLocation rl_src);
   void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
   void GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                     RegLocation rl_src2, bool is_div);
+                     RegLocation rl_src2, bool is_div, int flags);
 
-  InToRegStorageMapping in_to_reg_storage_mapping_;
   static const A64EncodingMap EncodingMap[kA64Last];
+
+  ArenaVector<LIR*> call_method_insns_;
+
+  int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE;
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/arm64/fp_arm64.cc b/compiler/dex/quick/arm64/fp_arm64.cc
index db24d12..ff692b7 100644
--- a/compiler/dex/quick/arm64/fp_arm64.cc
+++ b/compiler/dex/quick/arm64/fp_arm64.cc
@@ -116,6 +116,32 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+void Arm64Mir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                              int32_t constant) {
+  RegLocation rl_result;
+  RegStorage r_tmp = AllocTempSingle();
+  LoadConstantNoClobber(r_tmp, constant);
+  rl_src1 = LoadValue(rl_src1, kFPReg);
+  rl_result = EvalLoc(rl_dest, kFPReg, true);
+  NewLIR3(kA64Fmul3fff, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
+  StoreValue(rl_dest, rl_result);
+}
+
+void Arm64Mir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                               int64_t constant) {
+  RegLocation rl_result;
+  RegStorage r_tmp = AllocTempDouble();
+  DCHECK(r_tmp.IsDouble());
+  LoadConstantWide(r_tmp, constant);
+  rl_src1 = LoadValueWide(rl_src1, kFPReg);
+  DCHECK(rl_src1.wide);
+  rl_result = EvalLocWide(rl_dest, kFPReg, true);
+  DCHECK(rl_dest.wide);
+  DCHECK(rl_result.wide);
+  NewLIR3(WIDE(kA64Fmul3fff), rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
+  StoreValueWide(rl_dest, rl_result);
+}
+
 void Arm64Mir2Lir::GenConversion(Instruction::Code opcode,
                                  RegLocation rl_dest, RegLocation rl_src) {
   int op = kA64Brk1d;
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 88123e1..88ab6f8 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -16,12 +16,13 @@
 
 /* This file contains codegen for the Thumb2 ISA. */
 
+#include "arch/instruction_set_features.h"
 #include "arm64_lir.h"
 #include "codegen_arm64.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "entrypoints/quick/quick_entrypoints.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -32,11 +33,13 @@
 }
 
 LIR* Arm64Mir2Lir::OpIT(ConditionCode ccode, const char* guide) {
+  UNUSED(ccode, guide);
   LOG(FATAL) << "Unexpected use of OpIT for Arm64";
-  return NULL;
+  UNREACHABLE();
 }
 
 void Arm64Mir2Lir::OpEndIT(LIR* it) {
+  UNUSED(it);
   LOG(FATAL) << "Unexpected use of OpEndIT for Arm64";
 }
 
@@ -174,13 +177,14 @@
 
 void Arm64Mir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                                     int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                                    int dest_reg_class) {
+                                    RegisterClass dest_reg_class) {
   DCHECK(rs_dest.Valid());
   OpRegReg(kOpCmp, left_op, right_op);
   GenSelect(true_val, false_val, code, rs_dest, dest_reg_class);
 }
 
 void Arm64Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb);
   RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
   rl_src = LoadValue(rl_src, rl_src.ref ? kRefReg : kCoreReg);
   // rl_src may be aliased with rl_result/rl_dest, so do compare early.
@@ -406,6 +410,7 @@
 // Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
 bool Arm64Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                       RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(dalvik_opcode);
   if ((lit < 0) || (lit >= static_cast<int>(arraysize(magic_table)))) {
     return false;
   }
@@ -423,8 +428,7 @@
   rl_src = LoadValue(rl_src, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   RegStorage r_long_mul = AllocTemp();
-  NewLIR4(kA64Smaddl4xwwx, As64BitReg(r_long_mul).GetReg(),
-          r_magic.GetReg(), rl_src.reg.GetReg(), rxzr);
+  NewLIR3(kA64Smull3xww, As64BitReg(r_long_mul).GetReg(), r_magic.GetReg(), rl_src.reg.GetReg());
   switch (pattern) {
     case Divide3:
       OpRegRegImm(kOpLsr, As64BitReg(r_long_mul), As64BitReg(r_long_mul), 32);
@@ -450,6 +454,7 @@
 
 bool Arm64Mir2Lir::SmallLiteralDivRem64(Instruction::Code dalvik_opcode, bool is_div,
                                         RegLocation rl_src, RegLocation rl_dest, int64_t lit) {
+  UNUSED(dalvik_opcode);
   if ((lit < 0) || (lit >= static_cast<int>(arraysize(magic_table)))) {
     return false;
   }
@@ -538,7 +543,7 @@
       return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, static_cast<int32_t>(lit));
     }
   }
-  int k = LowestSetBit(lit);
+  int k = CTZ(lit);
   if (k >= nbits - 2) {
     // Avoid special cases.
     return false;
@@ -590,13 +595,16 @@
 }
 
 bool Arm64Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(rl_src, rl_dest, lit);
   LOG(FATAL) << "Unexpected use of EasyMultiply for Arm64";
-  return false;
+  UNREACHABLE();
 }
 
-RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
+RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit,
+                                       bool is_div) {
+  UNUSED(rl_dest, rl_src1, lit, is_div);
   LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm64";
-  return rl_dest;
+  UNREACHABLE();
 }
 
 RegLocation Arm64Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
@@ -614,9 +622,10 @@
 }
 
 RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                                    RegLocation rl_src2, bool is_div, bool check_zero) {
+                                    RegLocation rl_src2, bool is_div, int flags) {
+  UNUSED(rl_dest, rl_src1, rl_src2, is_div, flags);
   LOG(FATAL) << "Unexpected use of GenDivRem for Arm64";
-  return rl_dest;
+  UNREACHABLE();
 }
 
 RegLocation Arm64Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage r_src1, RegStorage r_src2,
@@ -640,7 +649,7 @@
     }
     OpRegRegReg(kOpDiv, temp, r_src1, r_src2);
     NewLIR4(kA64Msub4rrrr | wide, rl_result.reg.GetReg(), temp.GetReg(),
-            r_src1.GetReg(), r_src2.GetReg());
+            r_src2.GetReg(), r_src1.GetReg());
     FreeTemp(temp);
   }
   return rl_result;
@@ -750,7 +759,7 @@
 
   if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
     // Mark card for object assuming new value is stored.
-    MarkGCCard(rl_new_value.reg, rl_object.reg);
+    MarkGCCard(0, rl_new_value.reg, rl_object.reg);
   }
 
   RegStorage r_ptr = AllocTempRef();
@@ -925,29 +934,54 @@
 
 LIR* Arm64Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
   ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
-  return RawLIR(current_dalvik_offset_, WIDE(kA64Ldr2rp), reg.GetReg(), 0, 0, 0, 0, target);
+  return RawLIR(current_dalvik_offset_, kA64Ldr2rp, As32BitReg(reg).GetReg(), 0, 0, 0, 0, target);
 }
 
 LIR* Arm64Mir2Lir::OpVldm(RegStorage r_base, int count) {
+  UNUSED(r_base, count);
   LOG(FATAL) << "Unexpected use of OpVldm for Arm64";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* Arm64Mir2Lir::OpVstm(RegStorage r_base, int count) {
+  UNUSED(r_base, count);
   LOG(FATAL) << "Unexpected use of OpVstm for Arm64";
-  return NULL;
+  UNREACHABLE();
+}
+
+void Arm64Mir2Lir::GenMaddMsubInt(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                  RegLocation rl_src3, bool is_sub) {
+  rl_src1 = LoadValue(rl_src1, kCoreReg);
+  rl_src2 = LoadValue(rl_src2, kCoreReg);
+  rl_src3 = LoadValue(rl_src3, kCoreReg);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  NewLIR4(is_sub ? kA64Msub4rrrr : kA64Madd4rrrr, rl_result.reg.GetReg(), rl_src1.reg.GetReg(),
+          rl_src2.reg.GetReg(), rl_src3.reg.GetReg());
+  StoreValue(rl_dest, rl_result);
+}
+
+void Arm64Mir2Lir::GenMaddMsubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                   RegLocation rl_src3, bool is_sub) {
+  rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+  rl_src2 = LoadValueWide(rl_src2, kCoreReg);
+  rl_src3 = LoadValueWide(rl_src3, kCoreReg);
+  RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+  NewLIR4(is_sub ? WIDE(kA64Msub4rrrr) : WIDE(kA64Madd4rrrr), rl_result.reg.GetReg(),
+          rl_src1.reg.GetReg(), rl_src2.reg.GetReg(), rl_src3.reg.GetReg());
+  StoreValueWide(rl_dest, rl_result);
 }
 
 void Arm64Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
-                                               RegLocation rl_result, int lit,
-                                               int first_bit, int second_bit) {
-  OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg, EncodeShift(kA64Lsl, second_bit - first_bit));
+                                                 RegLocation rl_result, int lit ATTRIBUTE_UNUSED,
+                                                 int first_bit, int second_bit) {
+  OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg,
+                   EncodeShift(kA64Lsl, second_bit - first_bit));
   if (first_bit != 0) {
     OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
   }
 }
 
-void Arm64Mir2Lir::GenDivZeroCheckWide(RegStorage reg) {
+void Arm64Mir2Lir::GenDivZeroCheckWide(RegStorage reg ATTRIBUTE_UNUSED) {
   LOG(FATAL) << "Unexpected use of GenDivZero for Arm64";
 }
 
@@ -969,7 +1003,9 @@
 }
 
 bool Arm64Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
-#if ANDROID_SMP != 0
+  if (!cu_->GetInstructionSetFeatures()->IsSmp()) {
+    return false;
+  }
   // Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
   LIR* barrier = last_lir_insn_;
 
@@ -1005,9 +1041,6 @@
   DCHECK(!barrier->flags.use_def_invalid);
   barrier->u.m.def_mask = &kEncodeAll;
   return ret;
-#else
-  return false;
-#endif
 }
 
 void Arm64Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
@@ -1020,7 +1053,7 @@
 }
 
 void Arm64Mir2Lir::GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest,
-                                 RegLocation rl_src1, RegLocation rl_src2, bool is_div) {
+                                 RegLocation rl_src1, RegLocation rl_src2, bool is_div, int flags) {
   if (rl_src2.is_const) {
     DCHECK(rl_src2.wide);
     int64_t lit = mir_graph_->ConstantValueWide(rl_src2);
@@ -1032,7 +1065,9 @@
   RegLocation rl_result;
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
-  GenDivZeroCheck(rl_src2.reg);
+  if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
+    GenDivZeroCheck(rl_src2.reg);
+  }
   rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, is_div);
   StoreValueWide(rl_dest, rl_result);
 }
@@ -1067,7 +1102,7 @@
 }
 
 void Arm64Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                  RegLocation rl_src1, RegLocation rl_src2) {
+                                  RegLocation rl_src1, RegLocation rl_src2, int flags) {
   switch (opcode) {
     case Instruction::NOT_LONG:
       GenNotLong(rl_dest, rl_src2);
@@ -1086,11 +1121,11 @@
       return;
     case Instruction::DIV_LONG:
     case Instruction::DIV_LONG_2ADDR:
-      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true);
+      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true, flags);
       return;
     case Instruction::REM_LONG:
     case Instruction::REM_LONG_2ADDR:
-      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false);
+      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false, flags);
       return;
     case Instruction::AND_LONG_2ADDR:
     case Instruction::AND_LONG:
@@ -1135,11 +1170,6 @@
     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
   }
 
-  // If index is constant, just fold it into the data offset
-  if (constant_index) {
-    data_offset += mir_graph_->ConstantValue(rl_index) << scale;
-  }
-
   /* null object? */
   GenNullCheck(rl_array.reg, opt_flags);
 
@@ -1153,43 +1183,22 @@
   } else {
     ForceImplicitNullCheck(rl_array.reg, opt_flags);
   }
-  if (rl_dest.wide || rl_dest.fp || constant_index) {
-    RegStorage reg_ptr;
-    if (constant_index) {
-      reg_ptr = rl_array.reg;  // NOTE: must not alter reg_ptr in constant case.
-    } else {
-      // No special indexed operation, lea + load w/ displacement
-      reg_ptr = AllocTempRef();
-      OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, As64BitReg(rl_index.reg),
-                       EncodeShift(kA64Lsl, scale));
-      FreeTemp(rl_index.reg);
-    }
+  if (constant_index) {
     rl_result = EvalLoc(rl_dest, reg_class, true);
 
     if (needs_range_check) {
-      if (constant_index) {
-        GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
-      } else {
-        GenArrayBoundsCheck(rl_index.reg, reg_len);
-      }
+      GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
       FreeTemp(reg_len);
     }
+    // Fold the constant index into the data offset.
+    data_offset += mir_graph_->ConstantValue(rl_index) << scale;
     if (rl_result.ref) {
-      LoadRefDisp(reg_ptr, data_offset, rl_result.reg, kNotVolatile);
+      LoadRefDisp(rl_array.reg, data_offset, rl_result.reg, kNotVolatile);
     } else {
-      LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size, kNotVolatile);
-    }
-    MarkPossibleNullPointerException(opt_flags);
-    if (!constant_index) {
-      FreeTemp(reg_ptr);
-    }
-    if (rl_dest.wide) {
-      StoreValueWide(rl_dest, rl_result);
-    } else {
-      StoreValue(rl_dest, rl_result);
+      LoadBaseDisp(rl_array.reg, data_offset, rl_result.reg, size, kNotVolatile);
     }
   } else {
-    // Offset base, then use indexed load
+    // Offset base, then use indexed load.
     RegStorage reg_ptr = AllocTempRef();
     OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
     FreeTemp(rl_array.reg);
@@ -1200,12 +1209,15 @@
       FreeTemp(reg_len);
     }
     if (rl_result.ref) {
-      LoadRefIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale);
+      LoadRefIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale);
     } else {
-      LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale, size);
+      LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
     }
-    MarkPossibleNullPointerException(opt_flags);
     FreeTemp(reg_ptr);
+  }
+  if (rl_dest.wide) {
+    StoreValueWide(rl_dest, rl_result);
+  } else {
     StoreValue(rl_dest, rl_result);
   }
 }
@@ -1227,11 +1239,6 @@
     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
   }
 
-  // If index is constant, just fold it into the data offset.
-  if (constant_index) {
-    data_offset += mir_graph_->ConstantValue(rl_index) << scale;
-  }
-
   rl_array = LoadValue(rl_array, kRefReg);
   if (!constant_index) {
     rl_index = LoadValue(rl_index, kCoreReg);
@@ -1264,55 +1271,47 @@
     ForceImplicitNullCheck(rl_array.reg, opt_flags);
   }
   /* at this point, reg_ptr points to array, 2 live temps */
-  if (rl_src.wide || rl_src.fp || constant_index) {
-    if (rl_src.wide) {
-      rl_src = LoadValueWide(rl_src, reg_class);
-    } else {
-      rl_src = LoadValue(rl_src, reg_class);
-    }
-    if (!constant_index) {
-      OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, As64BitReg(rl_index.reg),
-                       EncodeShift(kA64Lsl, scale));
-    }
+  if (rl_src.wide) {
+    rl_src = LoadValueWide(rl_src, reg_class);
+  } else {
+    rl_src = LoadValue(rl_src, reg_class);
+  }
+  if (constant_index) {
     if (needs_range_check) {
-      if (constant_index) {
-        GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
-      } else {
-        GenArrayBoundsCheck(rl_index.reg, reg_len);
-      }
+      GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
       FreeTemp(reg_len);
     }
+    // Fold the constant index into the data offset.
+    data_offset += mir_graph_->ConstantValue(rl_index) << scale;
     if (rl_src.ref) {
       StoreRefDisp(reg_ptr, data_offset, rl_src.reg, kNotVolatile);
     } else {
       StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size, kNotVolatile);
     }
-    MarkPossibleNullPointerException(opt_flags);
   } else {
     /* reg_ptr -> array data */
     OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
-    rl_src = LoadValue(rl_src, reg_class);
     if (needs_range_check) {
       GenArrayBoundsCheck(rl_index.reg, reg_len);
       FreeTemp(reg_len);
     }
     if (rl_src.ref) {
-      StoreRefIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg, scale);
+      StoreRefIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale);
     } else {
-      StoreBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg, scale, size);
+      StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
     }
-    MarkPossibleNullPointerException(opt_flags);
   }
   if (allocated_reg_ptr_temp) {
     FreeTemp(reg_ptr);
   }
   if (card_mark) {
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
 void Arm64Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
-                                     RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
+                                     RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift,
+                                     int flags ATTRIBUTE_UNUSED) {
   OpKind op = kOpBkpt;
   // Per spec, we only care about low 6 bits of shift amount.
   int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
@@ -1344,7 +1343,7 @@
 }
 
 void Arm64Mir2Lir::GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                     RegLocation rl_src1, RegLocation rl_src2) {
+                                     RegLocation rl_src1, RegLocation rl_src2, int flags) {
   OpKind op = kOpBkpt;
   switch (opcode) {
     case Instruction::ADD_LONG:
@@ -1373,7 +1372,7 @@
 
   if (op == kOpSub) {
     if (!rl_src2.is_const) {
-      return GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+      return GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
     }
   } else {
     // Associativity.
@@ -1468,8 +1467,8 @@
   }
 }
 
-static int SpillRegsPreSub(Arm64Mir2Lir* m2l, RegStorage base, uint32_t core_reg_mask,
-                           uint32_t fp_reg_mask, int frame_size) {
+static int SpillRegsPreSub(Arm64Mir2Lir* m2l, uint32_t core_reg_mask, uint32_t fp_reg_mask,
+                           int frame_size) {
   m2l->OpRegRegImm(kOpSub, rs_sp, rs_sp, frame_size);
 
   int core_count = POPCOUNT(core_reg_mask);
@@ -1491,7 +1490,7 @@
 }
 
 static int SpillRegsPreIndexed(Arm64Mir2Lir* m2l, RegStorage base, uint32_t core_reg_mask,
-                               uint32_t fp_reg_mask, int frame_size) {
+                               uint32_t fp_reg_mask) {
   // Otherwise, spill both core and fp regs at the same time.
   // The very first instruction will be an stp with pre-indexed address, moving the stack pointer
   // down. From then on, we fill upwards. This will generate overall the same number of instructions
@@ -1614,9 +1613,9 @@
   // This case is also optimal when we have an odd number of core spills, and an even (non-zero)
   // number of fp spills.
   if ((RoundUp(frame_size, 8) / 8 <= 63)) {
-    return SpillRegsPreSub(this, base, core_reg_mask, fp_reg_mask, frame_size);
+    return SpillRegsPreSub(this, core_reg_mask, fp_reg_mask, frame_size);
   } else {
-    return SpillRegsPreIndexed(this, base, core_reg_mask, fp_reg_mask, frame_size);
+    return SpillRegsPreIndexed(this, base, core_reg_mask, fp_reg_mask);
   }
 }
 
@@ -1654,6 +1653,7 @@
 
 void Arm64Mir2Lir::UnspillRegs(RegStorage base, uint32_t core_reg_mask, uint32_t fp_reg_mask,
                                int frame_size) {
+  DCHECK_EQ(base, rs_sp);
   // Restore saves and drop stack frame.
   // 2 versions:
   //
@@ -1709,7 +1709,8 @@
   RegLocation rl_src_i = info->args[0];
   RegLocation rl_dest = IsWide(size) ? InlineTargetWide(info) : InlineTarget(info);  // result reg
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  RegLocation rl_i = IsWide(size) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
+  RegLocation rl_i = IsWide(size) ?
+      LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
   NewLIR2(kA64Rbit2rr | wide, rl_result.reg.GetReg(), rl_i.reg.GetReg());
   IsWide(size) ? StoreValueWide(rl_dest, rl_result) : StoreValue(rl_dest, rl_result);
   return true;
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index 0462530..ee7e818 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -585,14 +585,14 @@
 }
 
 Arm64Mir2Lir::Arm64Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
-    : Mir2Lir(cu, mir_graph, arena) {
+    : Mir2Lir(cu, mir_graph, arena),
+      call_method_insns_(arena->Adapter()) {
   // Sanity check - make sure encoding map lines up.
   for (int i = 0; i < kA64Last; i++) {
-    if (UNWIDE(Arm64Mir2Lir::EncodingMap[i].opcode) != i) {
-      LOG(FATAL) << "Encoding order for " << Arm64Mir2Lir::EncodingMap[i].name
-                 << " is wrong: expecting " << i << ", seeing "
-                 << static_cast<int>(Arm64Mir2Lir::EncodingMap[i].opcode);
-    }
+    DCHECK_EQ(UNWIDE(Arm64Mir2Lir::EncodingMap[i].opcode), i)
+        << "Encoding order for " << Arm64Mir2Lir::EncodingMap[i].name
+        << " is wrong: expecting " << i << ", seeing "
+        << static_cast<int>(Arm64Mir2Lir::EncodingMap[i].opcode);
   }
 }
 
@@ -759,6 +759,7 @@
   FreeTemp(rs_f5);
   FreeTemp(rs_f6);
   FreeTemp(rs_f7);
+  FreeTemp(TargetReg(kHiddenArg));
 }
 
 RegStorage Arm64Mir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
@@ -790,27 +791,23 @@
   return Arm64Mir2Lir::EncodingMap[UNWIDE(opcode)].fmt;
 }
 
-RegStorage Arm64Mir2Lir::InToRegStorageArm64Mapper::GetNextReg(bool is_double_or_float,
-                                                               bool is_wide,
-                                                               bool is_ref) {
+RegStorage Arm64Mir2Lir::InToRegStorageArm64Mapper::GetNextReg(ShortyArg arg) {
   const RegStorage coreArgMappingToPhysicalReg[] =
       {rs_x1, rs_x2, rs_x3, rs_x4, rs_x5, rs_x6, rs_x7};
-  const int coreArgMappingToPhysicalRegSize =
-      sizeof(coreArgMappingToPhysicalReg) / sizeof(RegStorage);
+  const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
   const RegStorage fpArgMappingToPhysicalReg[] =
       {rs_f0, rs_f1, rs_f2, rs_f3, rs_f4, rs_f5, rs_f6, rs_f7};
-  const int fpArgMappingToPhysicalRegSize =
-      sizeof(fpArgMappingToPhysicalReg) / sizeof(RegStorage);
+  const size_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
 
   RegStorage result = RegStorage::InvalidReg();
-  if (is_double_or_float) {
+  if (arg.IsFP()) {
     if (cur_fp_reg_ < fpArgMappingToPhysicalRegSize) {
-      DCHECK(!is_ref);
+      DCHECK(!arg.IsRef());
       result = fpArgMappingToPhysicalReg[cur_fp_reg_++];
       if (result.Valid()) {
         // TODO: switching between widths remains a bit ugly.  Better way?
         int res_reg = result.GetReg();
-        result = is_wide ? RegStorage::FloatSolo64(res_reg) : RegStorage::FloatSolo32(res_reg);
+        result = arg.IsWide() ? RegStorage::FloatSolo64(res_reg) : RegStorage::FloatSolo32(res_reg);
       }
     }
   } else {
@@ -819,386 +816,69 @@
       if (result.Valid()) {
         // TODO: switching between widths remains a bit ugly.  Better way?
         int res_reg = result.GetReg();
-        DCHECK(!(is_wide && is_ref));
-        result = (is_wide || is_ref) ? RegStorage::Solo64(res_reg) : RegStorage::Solo32(res_reg);
+        DCHECK(!(arg.IsWide() && arg.IsRef()));
+        result = (arg.IsWide() || arg.IsRef()) ?
+                 RegStorage::Solo64(res_reg) : RegStorage::Solo32(res_reg);
       }
     }
   }
   return result;
 }
 
-RegStorage Arm64Mir2Lir::InToRegStorageMapping::Get(int in_position) {
-  DCHECK(IsInitialized());
-  auto res = mapping_.find(in_position);
-  return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
-}
+void Arm64Mir2Lir::InstallLiteralPools() {
+  // PC-relative calls to methods.
+  patches_.reserve(call_method_insns_.size());
+  for (LIR* p : call_method_insns_) {
+      DCHECK_EQ(p->opcode, kA64Bl1t);
+      uint32_t target_method_idx = p->operands[1];
+      const DexFile* target_dex_file =
+          reinterpret_cast<const DexFile*>(UnwrapPointer(p->operands[2]));
 
-void Arm64Mir2Lir::InToRegStorageMapping::Initialize(RegLocation* arg_locs, int count,
-                                                     InToRegStorageMapper* mapper) {
-  DCHECK(mapper != nullptr);
-  max_mapped_in_ = -1;
-  is_there_stack_mapped_ = false;
-  for (int in_position = 0; in_position < count; in_position++) {
-     RegStorage reg = mapper->GetNextReg(arg_locs[in_position].fp,
-                                         arg_locs[in_position].wide,
-                                         arg_locs[in_position].ref);
-     if (reg.Valid()) {
-       mapping_[in_position] = reg;
-       if (arg_locs[in_position].wide) {
-         // We covered 2 args, so skip the next one
-         in_position++;
-       }
-       max_mapped_in_ = std::max(max_mapped_in_, in_position);
-     } else {
-       is_there_stack_mapped_ = true;
-     }
+      patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
+                                                        target_dex_file, target_method_idx));
   }
-  initialized_ = true;
+
+  // And do the normal processing.
+  Mir2Lir::InstallLiteralPools();
 }
 
-
-// Deprecate.  Use the new mechanism.
-// TODO(Arm64): reuse info in QuickArgumentVisitor?
-static RegStorage GetArgPhysicalReg(RegLocation* loc, int* num_gpr_used, int* num_fpr_used,
-                                    OpSize* op_size) {
-  if (loc->fp) {
-    int n = *num_fpr_used;
-    if (n < 8) {
-      *num_fpr_used = n + 1;
-      RegStorage::RegStorageKind reg_kind;
-      if (loc->wide) {
-        *op_size = kDouble;
-        reg_kind = RegStorage::k64BitSolo;
-      } else {
-        *op_size = kSingle;
-        reg_kind = RegStorage::k32BitSolo;
-      }
-      return RegStorage(RegStorage::kValid | reg_kind | RegStorage::kFloatingPoint | n);
-    }
-  } else {
-    int n = *num_gpr_used;
-    if (n < 8) {
-      *num_gpr_used = n + 1;
-      if (loc->wide || loc->ref) {
-        *op_size = k64;
-        return RegStorage::Solo64(n);
-      } else {
-        *op_size = k32;
-        return RegStorage::Solo32(n);
-      }
-    }
-  }
-  *op_size = kWord;
-  return RegStorage::InvalidReg();
-}
-
-RegStorage Arm64Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
-  if (!in_to_reg_storage_mapping_.IsInitialized()) {
-    int start_vreg = mir_graph_->GetFirstInVR();
-    RegLocation* arg_locs = &mir_graph_->reg_location_[start_vreg];
-
-    InToRegStorageArm64Mapper mapper;
-    in_to_reg_storage_mapping_.Initialize(arg_locs, mir_graph_->GetNumOfInVRs(), &mapper);
-  }
-  return in_to_reg_storage_mapping_.Get(arg_num);
-}
-
-
-/*
- * If there are any ins passed in registers that have not been promoted
- * to a callee-save register, flush them to the frame.  Perform initial
- * assignment of promoted arguments.
- *
- * ArgLocs is an array of location records describing the incoming arguments
- * with one location record per word of argument.
- */
-void Arm64Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
-  int num_gpr_used = 1;
-  int num_fpr_used = 0;
-
+int Arm64Mir2Lir::GenDalvikArgsBulkCopy(CallInfo* /*info*/, int /*first*/, int count) {
   /*
-   * Dummy up a RegLocation for the incoming StackReference<mirror::ArtMethod>
-   * It will attempt to keep kArg0 live (or copy it to home location
-   * if promoted).
+   * TODO: Improve by adding block copy for large number of arguments.  For now, just
+   * copy a Dalvik vreg at a time.
    */
-  RegLocation rl_src = rl_method;
-  rl_src.location = kLocPhysReg;
-  rl_src.reg = TargetReg(kArg0, kRef);
-  rl_src.home = false;
-  MarkLive(rl_src);
-  StoreValue(rl_method, rl_src);
-  // If Method* has been promoted, explicitly flush
-  if (rl_method.location == kLocPhysReg) {
-    StoreRefDisp(TargetPtrReg(kSp), 0, rl_src.reg, kNotVolatile);
-  }
-
-  if (mir_graph_->GetNumOfInVRs() == 0) {
-    return;
-  }
-
-  // Handle dalvik registers.
-  ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-  int start_vreg = mir_graph_->GetFirstInVR();
-  for (uint32_t i = 0; i < mir_graph_->GetNumOfInVRs(); i++) {
-    RegLocation* t_loc = &ArgLocs[i];
-    OpSize op_size;
-    RegStorage reg = GetArgPhysicalReg(t_loc, &num_gpr_used, &num_fpr_used, &op_size);
-
-    if (reg.Valid()) {
-      // If arriving in register.
-
-      // We have already updated the arg location with promoted info
-      // so we can be based on it.
-      if (t_loc->location == kLocPhysReg) {
-        // Just copy it.
-        OpRegCopy(t_loc->reg, reg);
-      } else {
-        // Needs flush.
-        if (t_loc->ref) {
-          StoreRefDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg, kNotVolatile);
-        } else {
-          StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg, t_loc->wide ? k64 : k32,
-              kNotVolatile);
-        }
-      }
-    } else {
-      // If arriving in frame & promoted.
-      if (t_loc->location == kLocPhysReg) {
-        if (t_loc->ref) {
-          LoadRefDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), t_loc->reg, kNotVolatile);
-        } else {
-          LoadBaseDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), t_loc->reg,
-                       t_loc->wide ? k64 : k32, kNotVolatile);
-        }
-      }
-    }
-    if (t_loc->wide) {
-      // Increment i to skip the next one.
-      i++;
-    }
-    //      if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
-    //        OpRegCopy(RegStorage::Solo32(v_map->core_reg), reg);
-    //      } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
-    //        OpRegCopy(RegStorage::Solo32(v_map->fp_reg), reg);
-    //      } else {
-    //        StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, op_size, kNotVolatile);
-    //        if (reg.Is64Bit()) {
-    //          if (SRegOffset(start_vreg + i) + 4 != SRegOffset(start_vreg + i + 1)) {
-    //            LOG(FATAL) << "64 bit value stored in non-consecutive 4 bytes slots";
-    //          }
-    //          i += 1;
-    //        }
-    //      }
-    //    } else {
-    //      // If arriving in frame & promoted
-    //      if (v_map->core_location == kLocPhysReg) {
-    //        LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
-    //                     RegStorage::Solo32(v_map->core_reg));
-    //      }
-    //      if (v_map->fp_location == kLocPhysReg) {
-    //        LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i), RegStorage::Solo32(v_map->fp_reg));
-    //      }
-  }
+  return count;
 }
 
-/*
- * Load up to 5 arguments, the first three of which will be in
- * kArg1 .. kArg3.  On entry kArg0 contains the current method pointer,
- * and as part of the load sequence, it must be replaced with
- * the target method pointer.
- */
-int Arm64Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
-                                       int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                       const MethodReference& target_method,
-                                       uint32_t vtable_idx, uintptr_t direct_code,
-                                       uintptr_t direct_method, InvokeType type, bool skip_this) {
-  return GenDalvikArgsRange(info,
-                       call_state, pcrLabel, next_call_insn,
-                       target_method,
-                       vtable_idx, direct_code,
-                       direct_method, type, skip_this);
-}
-
-/*
- * May have 0+ arguments (also used for jumbo).  Note that
- * source virtual registers may be in physical registers, so may
- * need to be flushed to home location before copying.  This
- * applies to arg3 and above (see below).
- *
- * FIXME: update comments.
- *
- * Two general strategies:
- *    If < 20 arguments
- *       Pass args 3-18 using vldm/vstm block copy
- *       Pass arg0, arg1 & arg2 in kArg1-kArg3
- *    If 20+ arguments
- *       Pass args arg19+ using memcpy block copy
- *       Pass arg0, arg1 & arg2 in kArg1-kArg3
- *
- */
-int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
-                                     LIR** pcrLabel, NextCallInsn next_call_insn,
-                                     const MethodReference& target_method,
-                                     uint32_t vtable_idx, uintptr_t direct_code,
-                                     uintptr_t direct_method, InvokeType type, bool skip_this) {
-  /* If no arguments, just return */
-  if (info->num_arg_words == 0)
-    return call_state;
-
-  const int start_index = skip_this ? 1 : 0;
-
-  InToRegStorageArm64Mapper mapper;
-  InToRegStorageMapping in_to_reg_storage_mapping;
-  in_to_reg_storage_mapping.Initialize(info->args, info->num_arg_words, &mapper);
-  const int last_mapped_in = in_to_reg_storage_mapping.GetMaxMappedIn();
-  int regs_left_to_pass_via_stack = info->num_arg_words - (last_mapped_in + 1);
-
-  // First of all, check whether it makes sense to use bulk copying.
-  // Bulk copying is done only for the range case.
-  // TODO: make a constant instead of 2
-  if (info->is_range && regs_left_to_pass_via_stack >= 2) {
-    // Scan the rest of the args - if in phys_reg flush to memory
-    for (int next_arg = last_mapped_in + 1; next_arg < info->num_arg_words;) {
-      RegLocation loc = info->args[next_arg];
-      if (loc.wide) {
-        loc = UpdateLocWide(loc);
-        if (loc.location == kLocPhysReg) {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
-        }
-        next_arg += 2;
-      } else {
-        loc = UpdateLoc(loc);
-        if (loc.location == kLocPhysReg) {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          if (loc.ref) {
-            StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile);
-          } else {
-            StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32,
-                          kNotVolatile);
-          }
-        }
-        next_arg++;
-      }
-    }
-
-    // The rest can be copied together
-    int start_offset = SRegOffset(info->args[last_mapped_in + 1].s_reg_low);
-    int outs_offset = StackVisitor::GetOutVROffset(last_mapped_in + 1,
-                                                   cu_->instruction_set);
-
-    int current_src_offset = start_offset;
-    int current_dest_offset = outs_offset;
-
-    // Only davik regs are accessed in this loop; no next_call_insn() calls.
-    ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    while (regs_left_to_pass_via_stack > 0) {
-      /*
-       * TODO: Improve by adding block copy for large number of arguments.  This
-       * should be done, if possible, as a target-depending helper.  For now, just
-       * copy a Dalvik vreg at a time.
-       */
-      // Moving 32-bits via general purpose register.
-      size_t bytes_to_move = sizeof(uint32_t);
-
-      // Instead of allocating a new temp, simply reuse one of the registers being used
-      // for argument passing.
-      RegStorage temp = TargetReg(kArg3, kNotWide);
-
-      // Now load the argument VR and store to the outs.
-      Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
-      Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
-
-      current_src_offset += bytes_to_move;
-      current_dest_offset += bytes_to_move;
-      regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
-    }
-    DCHECK_EQ(regs_left_to_pass_via_stack, 0);
+void Arm64Mir2Lir::GenMachineSpecificExtendedMethodMIR(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb);
+  DCHECK(MIR::DecodedInstruction::IsPseudoMirOp(mir->dalvikInsn.opcode));
+  RegLocation rl_src[3];
+  RegLocation rl_dest = mir_graph_->GetBadLoc();
+  rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
+  ExtendedMIROpcode opcode = static_cast<ExtendedMIROpcode>(mir->dalvikInsn.opcode);
+  switch (opcode) {
+    case kMirOpMaddInt:
+    case kMirOpMsubInt:
+      rl_dest = mir_graph_->GetDest(mir);
+      rl_src[0] = mir_graph_->GetSrc(mir, 0);
+      rl_src[1] = mir_graph_->GetSrc(mir, 1);
+      rl_src[2]= mir_graph_->GetSrc(mir, 2);
+      GenMaddMsubInt(rl_dest, rl_src[0], rl_src[1], rl_src[2],
+                     (opcode == kMirOpMsubInt) ? true : false);
+      break;
+    case kMirOpMaddLong:
+    case kMirOpMsubLong:
+      rl_dest = mir_graph_->GetDestWide(mir);
+      rl_src[0] = mir_graph_->GetSrcWide(mir, 0);
+      rl_src[1] = mir_graph_->GetSrcWide(mir, 2);
+      rl_src[2] = mir_graph_->GetSrcWide(mir, 4);
+      GenMaddMsubLong(rl_dest, rl_src[0], rl_src[1], rl_src[2],
+                      (opcode == kMirOpMsubLong) ? true : false);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected opcode: " << static_cast<int>(opcode);
   }
-
-  // Now handle rest not registers if they are
-  if (in_to_reg_storage_mapping.IsThereStackMapped()) {
-    RegStorage regWide = TargetReg(kArg3, kWide);
-    for (int i = start_index; i <= last_mapped_in + regs_left_to_pass_via_stack; i++) {
-      RegLocation rl_arg = info->args[i];
-      rl_arg = UpdateRawLoc(rl_arg);
-      RegStorage reg = in_to_reg_storage_mapping.Get(i);
-      if (!reg.Valid()) {
-        int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
-
-        {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          if (rl_arg.wide) {
-            if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
-            } else {
-              LoadValueDirectWideFixed(rl_arg, regWide);
-              StoreBaseDisp(TargetPtrReg(kSp), out_offset, regWide, k64, kNotVolatile);
-            }
-          } else {
-            if (rl_arg.location == kLocPhysReg) {
-              if (rl_arg.ref) {
-                StoreRefDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, kNotVolatile);
-              } else {
-                StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
-              }
-            } else {
-              if (rl_arg.ref) {
-                RegStorage regSingle = TargetReg(kArg2, kRef);
-                LoadValueDirectFixed(rl_arg, regSingle);
-                StoreRefDisp(TargetPtrReg(kSp), out_offset, regSingle, kNotVolatile);
-              } else {
-                RegStorage regSingle = TargetReg(kArg2, kNotWide);
-                LoadValueDirectFixed(rl_arg, regSingle);
-                StoreBaseDisp(TargetPtrReg(kSp), out_offset, regSingle, k32, kNotVolatile);
-              }
-            }
-          }
-        }
-        call_state = next_call_insn(cu_, info, call_state, target_method,
-                                    vtable_idx, direct_code, direct_method, type);
-      }
-      if (rl_arg.wide) {
-        i++;
-      }
-    }
-  }
-
-  // Finish with mapped registers
-  for (int i = start_index; i <= last_mapped_in; i++) {
-    RegLocation rl_arg = info->args[i];
-    rl_arg = UpdateRawLoc(rl_arg);
-    RegStorage reg = in_to_reg_storage_mapping.Get(i);
-    if (reg.Valid()) {
-      if (rl_arg.wide) {
-        LoadValueDirectWideFixed(rl_arg, reg);
-      } else {
-        LoadValueDirectFixed(rl_arg, reg);
-      }
-      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                                  direct_code, direct_method, type);
-    }
-    if (rl_arg.wide) {
-      i++;
-    }
-  }
-
-  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                           direct_code, direct_method, type);
-  if (pcrLabel) {
-    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
-      *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
-    } else {
-      *pcrLabel = nullptr;
-      // In lieu of generating a check for kArg1 being null, we need to
-      // perform a load when doing implicit checks.
-      RegStorage tmp = AllocTemp();
-      Load32Disp(TargetReg(kArg1, kRef), 0, tmp);
-      MarkPossibleNullPointerException(info->opt_flags);
-      FreeTemp(tmp);
-    }
-  }
-  return call_state;
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index 38670ff..a331f41 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -306,7 +306,7 @@
 // algorithm will give it a low priority for promotion, even when it is referenced many times in
 // the code.
 
-bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value) {
+bool Arm64Mir2Lir::InexpensiveConstantInt(int32_t value ATTRIBUTE_UNUSED) {
   // A 32-bit int can always be loaded with 2 instructions (and without using the literal pool).
   // We therefore return true and give it a low priority for promotion.
   return true;
@@ -345,7 +345,7 @@
   case Instruction::SUB_INT_2ADDR:
     // The code below is consistent with the implementation of OpRegRegImm().
     {
-      int32_t abs_value = std::abs(value);
+      uint32_t abs_value = (value == INT_MIN) ? value : std::abs(value);
       if (abs_value < 0x1000) {
         return true;
       } else if ((abs_value & UINT64_C(0xfff)) == 0 && ((abs_value >> 12) < 0x1000)) {
@@ -673,19 +673,24 @@
   }
 }
 
-LIR* Arm64Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) {
+LIR* Arm64Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
+                               MoveType move_type) {
+  UNUSED(r_dest, r_base, offset, move_type);
   UNIMPLEMENTED(FATAL);
-  return nullptr;
+  UNREACHABLE();
 }
 
-LIR* Arm64Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
+LIR* Arm64Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src,
+                               MoveType move_type) {
+  UNUSED(r_base, offset, r_src, move_type);
   UNIMPLEMENTED(FATAL);
   return nullptr;
 }
 
 LIR* Arm64Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
+  UNUSED(op, cc, r_dest, r_src);
   LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm64";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* Arm64Mir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
@@ -768,8 +773,8 @@
       opcode = kA64Sub4RRre;
       break;
     default:
-      LOG(FATAL) << "Unimplemented opcode: " << op;
-      break;
+      UNIMPLEMENTED(FATAL) << "Unimplemented opcode: " << op;
+      UNREACHABLE();
   }
   A64Opcode widened_opcode = r_dest.Is64Bit() ? WIDE(opcode) : opcode;
 
@@ -805,7 +810,7 @@
 LIR* Arm64Mir2Lir::OpRegRegImm64(OpKind op, RegStorage r_dest, RegStorage r_src1, int64_t value) {
   LIR* res;
   bool neg = (value < 0);
-  int64_t abs_value = (neg) ? -value : value;
+  uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
   A64Opcode opcode = kA64Brk1d;
   A64Opcode alt_opcode = kA64Brk1d;
   bool is_logical = false;
@@ -833,7 +838,7 @@
                      value);
     case kOpAdd:
       neg = !neg;
-      // Note: intentional fallthrough
+      FALLTHROUGH_INTENDED;
     case kOpSub:
       // Add and sub below read/write sp rather than xzr.
       if (abs_value < 0x1000) {
@@ -938,7 +943,7 @@
   A64Opcode neg_opcode = kA64Brk1d;
   bool shift;
   bool neg = (value < 0);
-  uint64_t abs_value = (neg) ? -value : value;
+  uint64_t abs_value = (neg & !(value == LLONG_MIN)) ? -value : value;
 
   if (LIKELY(abs_value < 0x1000)) {
     // abs_value is a 12-bit immediate.
@@ -1057,9 +1062,11 @@
       opcode = WIDE(kA64Ldr4rXxG);
       expected_scale = 3;
       break;
-    case kSingle:     // Intentional fall-through.
-    case k32:         // Intentional fall-through.
     case kReference:
+      r_dest = As32BitReg(r_dest);
+      FALLTHROUGH_INTENDED;
+    case kSingle:     // Intentional fall-through.
+    case k32:
       r_dest = Check32BitReg(r_dest);
       opcode = kA64Ldr4rXxG;
       expected_scale = 2;
@@ -1100,11 +1107,6 @@
   return load;
 }
 
-LIR* Arm64Mir2Lir::LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
-                                  int scale) {
-  return LoadBaseIndexed(r_base, r_index, As32BitReg(r_dest), scale, kReference);
-}
-
 LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                     int scale, OpSize size) {
   LIR* store;
@@ -1145,9 +1147,11 @@
       opcode = WIDE(kA64Str4rXxG);
       expected_scale = 3;
       break;
-    case kSingle:     // Intentional fall-trough.
-    case k32:         // Intentional fall-trough.
     case kReference:
+      r_src = As32BitReg(r_src);
+      FALLTHROUGH_INTENDED;
+    case kSingle:     // Intentional fall-trough.
+    case k32:
       r_src = Check32BitReg(r_src);
       opcode = kA64Str4rXxG;
       expected_scale = 2;
@@ -1180,11 +1184,6 @@
   return store;
 }
 
-LIR* Arm64Mir2Lir::StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
-                                   int scale) {
-  return StoreBaseIndexed(r_base, r_index, As32BitReg(r_src), scale, kReference);
-}
-
 /*
  * Load value from base + displacement.  Optionally perform null check
  * on base (which must have an associated s_reg and MIR).  If not
@@ -1212,9 +1211,11 @@
         alt_opcode = WIDE(kA64Ldur3rXd);
       }
       break;
-    case kSingle:     // Intentional fall-through.
-    case k32:         // Intentional fall-trough.
     case kReference:
+      r_dest = As32BitReg(r_dest);
+      FALLTHROUGH_INTENDED;
+    case kSingle:     // Intentional fall-through.
+    case k32:
       r_dest = Check32BitReg(r_dest);
       scale = 2;
       if (r_dest.IsFloat()) {
@@ -1255,13 +1256,15 @@
     // TODO: cleaner support for index/displacement registers?  Not a reference, but must match width.
     RegStorage r_scratch = AllocTempWide();
     LoadConstantWide(r_scratch, displacement);
-    load = LoadBaseIndexed(r_base, r_scratch, r_dest, 0, size);
+    load = LoadBaseIndexed(r_base, r_scratch,
+                           (size == kReference) ? As64BitReg(r_dest) : r_dest,
+                           0, size);
     FreeTemp(r_scratch);
   }
 
   // TODO: in future may need to differentiate Dalvik accesses w/ spills
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_sp);
+    DCHECK_EQ(r_base, rs_sp);
     AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
   }
   return load;
@@ -1282,11 +1285,6 @@
   return load;
 }
 
-LIR* Arm64Mir2Lir::LoadRefDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                               VolatileKind is_volatile) {
-  return LoadBaseDisp(r_base, displacement, As32BitReg(r_dest), kReference, is_volatile);
-}
-
 LIR* Arm64Mir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
                                      OpSize size) {
   LIR* store = NULL;
@@ -1309,9 +1307,11 @@
         alt_opcode = WIDE(kA64Stur3rXd);
       }
       break;
-    case kSingle:     // Intentional fall-through.
-    case k32:         // Intentional fall-trough.
     case kReference:
+      r_src = As32BitReg(r_src);
+      FALLTHROUGH_INTENDED;
+    case kSingle:     // Intentional fall-through.
+    case k32:
       r_src = Check32BitReg(r_src);
       scale = 2;
       if (r_src.IsFloat()) {
@@ -1346,13 +1346,15 @@
     // Use long sequence.
     RegStorage r_scratch = AllocTempWide();
     LoadConstantWide(r_scratch, displacement);
-    store = StoreBaseIndexed(r_base, r_scratch, r_src, 0, size);
+    store = StoreBaseIndexed(r_base, r_scratch,
+                             (size == kReference) ? As64BitReg(r_src) : r_src,
+                             0, size);
     FreeTemp(r_scratch);
   }
 
   // TODO: In future, may need to differentiate Dalvik & spill accesses.
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_sp);
+    DCHECK_EQ(r_base, rs_sp);
     AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
   }
   return store;
@@ -1380,22 +1382,21 @@
   return store;
 }
 
-LIR* Arm64Mir2Lir::StoreRefDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                                VolatileKind is_volatile) {
-  return StoreBaseDisp(r_base, displacement, As32BitReg(r_src), kReference, is_volatile);
-}
-
 LIR* Arm64Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
+  UNUSED(r_dest, r_src);
   LOG(FATAL) << "Unexpected use of OpFpRegCopy for Arm64";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* Arm64Mir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
+  UNUSED(op, r_base, disp);
   LOG(FATAL) << "Unexpected use of OpMem for Arm64";
-  return NULL;
+  UNREACHABLE();
 }
 
-LIR* Arm64Mir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
+LIR* Arm64Mir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt,
+                                    QuickEntrypointEnum trampoline ATTRIBUTE_UNUSED) {
+  // The address of the trampoline is already loaded into r_tgt.
   return OpReg(op, r_tgt);
 }
 
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index f305017..ae9b0f4 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -105,17 +105,17 @@
 void Mir2Lir::UnlinkLIR(LIR* lir) {
   if (UNLIKELY(lir == first_lir_insn_)) {
     first_lir_insn_ = lir->next;
-    if (lir->next != NULL) {
-      lir->next->prev = NULL;
+    if (lir->next != nullptr) {
+      lir->next->prev = nullptr;
     } else {
-      DCHECK(lir->next == NULL);
+      DCHECK(lir->next == nullptr);
       DCHECK(lir == last_lir_insn_);
-      last_lir_insn_ = NULL;
+      last_lir_insn_ = nullptr;
     }
   } else if (lir == last_lir_insn_) {
     last_lir_insn_ = lir->prev;
-    lir->prev->next = NULL;
-  } else if ((lir->prev != NULL) && (lir->next != NULL)) {
+    lir->prev->next = nullptr;
+  } else if ((lir->prev != nullptr) && (lir->next != nullptr)) {
     lir->prev->next = lir->next;
     lir->next->prev = lir->prev;
   }
@@ -314,6 +314,19 @@
   }
 }
 
+void Mir2Lir::MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg) {
+  DCHECK(val_reg.Valid());
+  DCHECK_EQ(val_reg.Is64Bit(), cu_->target64);
+  if ((opt_flags & MIR_STORE_NON_NULL_VALUE) != 0) {
+    UnconditionallyMarkGCCard(tgt_addr_reg);
+  } else {
+    LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, nullptr);
+    UnconditionallyMarkGCCard(tgt_addr_reg);
+    LIR* target = NewLIR0(kPseudoTargetLabel);
+    branch_over->target = target;
+  }
+}
+
 /* Dump instructions and constant pool contents */
 void Mir2Lir::CodegenDump() {
   LOG(INFO) << "Dumping LIR insns for "
@@ -334,10 +347,10 @@
             << static_cast<float>(total_size_) / static_cast<float>(insns_size * 2);
   DumpPromotionMap();
   UpdateLIROffsets();
-  for (lir_insn = first_lir_insn_; lir_insn != NULL; lir_insn = lir_insn->next) {
+  for (lir_insn = first_lir_insn_; lir_insn != nullptr; lir_insn = lir_insn->next) {
     DumpLIRInsn(lir_insn, 0);
   }
-  for (lir_insn = literal_list_; lir_insn != NULL; lir_insn = lir_insn->next) {
+  for (lir_insn = literal_list_; lir_insn != nullptr; lir_insn = lir_insn->next) {
     LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)", lir_insn->offset, lir_insn->offset,
                               lir_insn->operands[0]);
   }
@@ -368,13 +381,13 @@
       return data_target;
     data_target = data_target->next;
   }
-  return NULL;
+  return nullptr;
 }
 
 /* Search the existing constants in the literal pool for an exact wide match */
 LIR* Mir2Lir::ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi) {
   bool lo_match = false;
-  LIR* lo_target = NULL;
+  LIR* lo_target = nullptr;
   while (data_target) {
     if (lo_match && (data_target->operands[0] == val_hi)) {
       // Record high word in case we need to expand this later.
@@ -388,7 +401,7 @@
     }
     data_target = data_target->next;
   }
-  return NULL;
+  return nullptr;
 }
 
 /* Search the existing constants in the literal pool for an exact method match */
@@ -431,7 +444,7 @@
     estimated_native_code_size_ += sizeof(value);
     return new_value;
   }
-  return NULL;
+  return nullptr;
 }
 
 /* Add a 64-bit constant to the constant pool or mixed with code */
@@ -447,15 +460,16 @@
   buf.push_back((data >> 24) & 0xff);
 }
 
-// Push 8 bytes on 64-bit target systems; 4 on 32-bit target systems.
-static void PushPointer(std::vector<uint8_t>&buf, const void* pointer, bool target64) {
-  uint64_t data = reinterpret_cast<uintptr_t>(pointer);
-  if (target64) {
-    Push32(buf, data & 0xFFFFFFFF);
-    Push32(buf, (data >> 32) & 0xFFFFFFFF);
-  } else {
-    Push32(buf, static_cast<uint32_t>(data));
-  }
+/**
+ * @brief Push a compressed reference which needs patching at link/patchoat-time.
+ * @details This needs to be kept consistent with the code which actually does the patching in
+ *   oat_writer.cc and in the patchoat tool.
+ */
+static void PushUnpatchedReference(std::vector<uint8_t>&buf) {
+  // Note that we can safely initialize the patches to zero. The code deduplication mechanism takes
+  // the patches into account when determining whether two pieces of codes are functionally
+  // equivalent.
+  Push32(buf, UINT32_C(0));
 }
 
 static void AlignBuffer(std::vector<uint8_t>&buf, size_t offset) {
@@ -468,47 +482,41 @@
 void Mir2Lir::InstallLiteralPools() {
   AlignBuffer(code_buffer_, data_offset_);
   LIR* data_lir = literal_list_;
-  while (data_lir != NULL) {
+  while (data_lir != nullptr) {
     Push32(code_buffer_, data_lir->operands[0]);
     data_lir = NEXT_LIR(data_lir);
   }
   // TODO: patches_.reserve() as needed.
   // Push code and method literals, record offsets for the compiler to patch.
   data_lir = code_literal_list_;
-  while (data_lir != NULL) {
+  while (data_lir != nullptr) {
     uint32_t target_method_idx = data_lir->operands[0];
     const DexFile* target_dex_file =
         reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
     patches_.push_back(LinkerPatch::CodePatch(code_buffer_.size(),
                                               target_dex_file, target_method_idx));
-    const DexFile::MethodId& target_method_id = target_dex_file->GetMethodId(target_method_idx);
-    // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &target_method_id, cu_->target64);
+    PushUnpatchedReference(code_buffer_);
     data_lir = NEXT_LIR(data_lir);
   }
   data_lir = method_literal_list_;
-  while (data_lir != NULL) {
+  while (data_lir != nullptr) {
     uint32_t target_method_idx = data_lir->operands[0];
     const DexFile* target_dex_file =
         reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
     patches_.push_back(LinkerPatch::MethodPatch(code_buffer_.size(),
                                                 target_dex_file, target_method_idx));
-    const DexFile::MethodId& target_method_id = target_dex_file->GetMethodId(target_method_idx);
-    // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &target_method_id, cu_->target64);
+    PushUnpatchedReference(code_buffer_);
     data_lir = NEXT_LIR(data_lir);
   }
   // Push class literals.
   data_lir = class_literal_list_;
-  while (data_lir != NULL) {
+  while (data_lir != nullptr) {
     uint32_t target_type_idx = data_lir->operands[0];
     const DexFile* class_dex_file =
       reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
     patches_.push_back(LinkerPatch::TypePatch(code_buffer_.size(),
                                               class_dex_file, target_type_idx));
-    const DexFile::TypeId& target_method_id = class_dex_file->GetTypeId(target_type_idx);
-    // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &target_method_id, cu_->target64);
+    PushUnpatchedReference(code_buffer_);
     data_lir = NEXT_LIR(data_lir);
   }
 }
@@ -530,9 +538,12 @@
         bx_offset = tab_rec->anchor->offset + 4;
         break;
       case kX86:
-      case kX86_64:
         bx_offset = 0;
         break;
+      case kX86_64:
+        // RIP relative to switch table.
+        bx_offset = tab_rec->offset;
+        break;
       case kArm64:
       case kMips:
         bx_offset = tab_rec->anchor->offset;
@@ -582,7 +593,7 @@
 }
 
 static int AssignLiteralOffsetCommon(LIR* lir, CodeOffset offset) {
-  for (; lir != NULL; lir = lir->next) {
+  for (; lir != nullptr; lir = lir->next) {
     lir->offset = offset;
     offset += 4;
   }
@@ -593,7 +604,7 @@
                                             unsigned int element_size) {
   // Align to natural pointer size.
   offset = RoundUp(offset, element_size);
-  for (; lir != NULL; lir = lir->next) {
+  for (; lir != nullptr; lir = lir->next) {
     lir->offset = offset;
     offset += element_size;
   }
@@ -647,7 +658,7 @@
   uint32_t dex2pc_entries = 0u;
   uint32_t dex2pc_offset = 0u;
   uint32_t dex2pc_dalvik_offset = 0u;
-  for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+  for (LIR* tgt_lir = first_lir_insn_; tgt_lir != nullptr; tgt_lir = NEXT_LIR(tgt_lir)) {
     pc2dex_src_entries++;
     if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
       pc2dex_entries += 1;
@@ -687,7 +698,7 @@
   pc2dex_dalvik_offset = 0u;
   dex2pc_offset = 0u;
   dex2pc_dalvik_offset = 0u;
-  for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+  for (LIR* tgt_lir = first_lir_insn_; tgt_lir != nullptr; tgt_lir = NEXT_LIR(tgt_lir)) {
     if (generate_src_map && !tgt_lir->flags.is_nop) {
       src_mapping_table_.push_back(SrcMapElem({tgt_lir->offset,
               static_cast<int32_t>(tgt_lir->dalvik_offset)}));
@@ -722,7 +733,7 @@
     CHECK_EQ(table.PcToDexSize(), pc2dex_entries);
     auto it = table.PcToDexBegin();
     auto it2 = table.DexToPcBegin();
-    for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+    for (LIR* tgt_lir = first_lir_insn_; tgt_lir != nullptr; tgt_lir = NEXT_LIR(tgt_lir)) {
       if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
         CHECK_EQ(tgt_lir->offset, it.NativePcOffset());
         CHECK_EQ(tgt_lir->dalvik_offset, it.DexPc());
@@ -763,16 +774,22 @@
     uint32_t native_offset = it.NativePcOffset();
     uint32_t dex_pc = it.DexPc();
     const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
-    CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc <<
+    CHECK(references != nullptr) << "Missing ref for dex pc 0x" << std::hex << dex_pc <<
         ": " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
     native_gc_map_builder.AddEntry(native_offset, references);
   }
+
+  // Maybe not necessary, but this could help prevent errors where we access the verified method
+  // after it has been deleted.
+  mir_graph_->GetCurrentDexCompilationUnit()->ClearVerifiedMethod();
 }
 
 /* Determine the offset of each literal field */
 int Mir2Lir::AssignLiteralOffset(CodeOffset offset) {
   offset = AssignLiteralOffsetCommon(literal_list_, offset);
-  unsigned int ptr_size = GetInstructionSetPointerSize(cu_->instruction_set);
+  constexpr unsigned int ptr_size = sizeof(uint32_t);
+  static_assert(ptr_size >= sizeof(mirror::HeapReference<mirror::Object>),
+                "Pointer size cannot hold a heap reference");
   offset = AssignLiteralPointerOffsetCommon(code_literal_list_, offset, ptr_size);
   offset = AssignLiteralPointerOffsetCommon(method_literal_list_, offset, ptr_size);
   offset = AssignLiteralPointerOffsetCommon(class_literal_list_, offset, ptr_size);
@@ -907,32 +924,11 @@
 
 /* Set up special LIR to mark a Dalvik byte-code instruction start for pretty printing */
 void Mir2Lir::MarkBoundary(DexOffset offset, const char* inst_str) {
+  UNUSED(offset);
   // NOTE: only used for debug listings.
   NewLIR1(kPseudoDalvikByteCodeBoundary, WrapPointer(ArenaStrdup(inst_str)));
 }
 
-bool Mir2Lir::EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) {
-  bool is_taken;
-  switch (opcode) {
-    case Instruction::IF_EQ: is_taken = (src1 == src2); break;
-    case Instruction::IF_NE: is_taken = (src1 != src2); break;
-    case Instruction::IF_LT: is_taken = (src1 < src2); break;
-    case Instruction::IF_GE: is_taken = (src1 >= src2); break;
-    case Instruction::IF_GT: is_taken = (src1 > src2); break;
-    case Instruction::IF_LE: is_taken = (src1 <= src2); break;
-    case Instruction::IF_EQZ: is_taken = (src1 == 0); break;
-    case Instruction::IF_NEZ: is_taken = (src1 != 0); break;
-    case Instruction::IF_LTZ: is_taken = (src1 < 0); break;
-    case Instruction::IF_GEZ: is_taken = (src1 >= 0); break;
-    case Instruction::IF_GTZ: is_taken = (src1 > 0); break;
-    case Instruction::IF_LEZ: is_taken = (src1 <= 0); break;
-    default:
-      LOG(FATAL) << "Unexpected opcode " << opcode;
-      is_taken = false;
-  }
-  return is_taken;
-}
-
 // Convert relation of src1/src2 to src2/src1
 ConditionCode Mir2Lir::FlipComparisonOrder(ConditionCode before) {
   ConditionCode res;
@@ -944,8 +940,8 @@
     case kCondLe: res = kCondGe; break;
     case kCondGe: res = kCondLe; break;
     default:
-      res = static_cast<ConditionCode>(0);
       LOG(FATAL) << "Unexpected ccode " << before;
+      UNREACHABLE();
   }
   return res;
 }
@@ -960,8 +956,8 @@
     case kCondLe: res = kCondGt; break;
     case kCondGe: res = kCondLt; break;
     default:
-      res = static_cast<ConditionCode>(0);
       LOG(FATAL) << "Unexpected ccode " << before;
+      UNREACHABLE();
   }
   return res;
 }
@@ -969,11 +965,11 @@
 // TODO: move to mir_to_lir.cc
 Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
     : Backend(arena),
-      literal_list_(NULL),
-      method_literal_list_(NULL),
-      class_literal_list_(NULL),
-      code_literal_list_(NULL),
-      first_fixup_(NULL),
+      literal_list_(nullptr),
+      method_literal_list_(nullptr),
+      class_literal_list_(nullptr),
+      code_literal_list_(nullptr),
+      first_fixup_(nullptr),
       cu_(cu),
       mir_graph_(mir_graph),
       switch_tables_(arena->Adapter(kArenaAllocSwitchTable)),
@@ -983,8 +979,8 @@
       pointer_storage_(arena->Adapter()),
       data_offset_(0),
       total_size_(0),
-      block_label_list_(NULL),
-      promotion_map_(NULL),
+      block_label_list_(nullptr),
+      promotion_map_(nullptr),
       current_dalvik_offset_(0),
       estimated_native_code_size_(0),
       reg_pool_(nullptr),
@@ -997,19 +993,20 @@
       frame_size_(0),
       core_spill_mask_(0),
       fp_spill_mask_(0),
-      first_lir_insn_(NULL),
-      last_lir_insn_(NULL),
+      first_lir_insn_(nullptr),
+      last_lir_insn_(nullptr),
       slow_paths_(arena->Adapter(kArenaAllocSlowPaths)),
       mem_ref_type_(ResourceMask::kHeapRef),
-      mask_cache_(arena) {
+      mask_cache_(arena),
+      in_to_reg_storage_mapping_(arena) {
   switch_tables_.reserve(4);
   fill_array_data_.reserve(4);
   tempreg_info_.reserve(20);
   reginfo_map_.reserve(RegStorage::kMaxRegs);
   pointer_storage_.reserve(128);
   slow_paths_.reserve(32);
-  // Reserve pointer id 0 for NULL.
-  size_t null_idx = WrapPointer(NULL);
+  // Reserve pointer id 0 for nullptr.
+  size_t null_idx = WrapPointer(nullptr);
   DCHECK_EQ(null_idx, 0U);
 }
 
@@ -1089,12 +1086,20 @@
   });
 
   std::unique_ptr<std::vector<uint8_t>> cfi_info(ReturnFrameDescriptionEntry());
-  CompiledMethod* result =
-      new CompiledMethod(cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
-                         core_spill_mask_, fp_spill_mask_, &src_mapping_table_, encoded_mapping_table_,
-                         vmap_encoder.GetData(), native_gc_map_, cfi_info.get(),
-                         ArrayRef<LinkerPatch>(patches_));
-  return result;
+  ArrayRef<const uint8_t> cfi_ref;
+  if (cfi_info.get() != nullptr) {
+    cfi_ref = ArrayRef<const uint8_t>(*cfi_info);
+  }
+  return CompiledMethod::SwapAllocCompiledMethod(
+      cu_->compiler_driver, cu_->instruction_set,
+      ArrayRef<const uint8_t>(code_buffer_),
+      frame_size_, core_spill_mask_, fp_spill_mask_,
+      &src_mapping_table_,
+      ArrayRef<const uint8_t>(encoded_mapping_table_),
+      ArrayRef<const uint8_t>(vmap_encoder.GetData()),
+      ArrayRef<const uint8_t>(native_gc_map_),
+      cfi_ref,
+      ArrayRef<LinkerPatch>(patches_));
 }
 
 size_t Mir2Lir::GetMaxPossibleCompilerTemps() const {
@@ -1129,14 +1134,14 @@
  * unit
  */
 void Mir2Lir::AppendLIR(LIR* lir) {
-  if (first_lir_insn_ == NULL) {
-    DCHECK(last_lir_insn_ == NULL);
+  if (first_lir_insn_ == nullptr) {
+    DCHECK(last_lir_insn_ == nullptr);
     last_lir_insn_ = first_lir_insn_ = lir;
-    lir->prev = lir->next = NULL;
+    lir->prev = lir->next = nullptr;
   } else {
     last_lir_insn_->next = lir;
     lir->prev = last_lir_insn_;
-    lir->next = NULL;
+    lir->next = nullptr;
     last_lir_insn_ = lir;
   }
 }
@@ -1148,7 +1153,7 @@
  * prev_lir <-> new_lir <-> current_lir
  */
 void Mir2Lir::InsertLIRBefore(LIR* current_lir, LIR* new_lir) {
-  DCHECK(current_lir->prev != NULL);
+  DCHECK(current_lir->prev != nullptr);
   LIR *prev_lir = current_lir->prev;
 
   prev_lir->next = new_lir;
@@ -1170,30 +1175,18 @@
   new_lir->next->prev = new_lir;
 }
 
-bool Mir2Lir::IsPowerOfTwo(uint64_t x) {
-  return (x & (x - 1)) == 0;
-}
-
-// Returns the index of the lowest set bit in 'x'.
-int32_t Mir2Lir::LowestSetBit(uint64_t x) {
-  int bit_posn = 0;
-  while ((x & 0xf) == 0) {
-    bit_posn += 4;
-    x >>= 4;
-  }
-  while ((x & 1) == 0) {
-    bit_posn++;
-    x >>= 1;
-  }
-  return bit_posn;
-}
-
-bool Mir2Lir::BadOverlap(RegLocation rl_src, RegLocation rl_dest) {
+bool Mir2Lir::PartiallyIntersects(RegLocation rl_src, RegLocation rl_dest) {
   DCHECK(rl_src.wide);
   DCHECK(rl_dest.wide);
   return (abs(mir_graph_->SRegToVReg(rl_src.s_reg_low) - mir_graph_->SRegToVReg(rl_dest.s_reg_low)) == 1);
 }
 
+bool Mir2Lir::Intersects(RegLocation rl_src, RegLocation rl_dest) {
+  DCHECK(rl_src.wide);
+  DCHECK(rl_dest.wide);
+  return (abs(mir_graph_->SRegToVReg(rl_src.s_reg_low) - mir_graph_->SRegToVReg(rl_dest.s_reg_low)) <= 1);
+}
+
 LIR *Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
                                 int offset, int check_value, LIR* target, LIR** compare) {
   // Handle this for architectures that can't compare to memory.
@@ -1213,7 +1206,7 @@
 void Mir2Lir::LoadCodeAddress(const MethodReference& target_method, InvokeType type,
                               SpecialTargetRegister symbolic_reg) {
   LIR* data_target = ScanLiteralPoolMethod(code_literal_list_, target_method);
-  if (data_target == NULL) {
+  if (data_target == nullptr) {
     data_target = AddWordData(&code_literal_list_, target_method.dex_method_index);
     data_target->operands[1] = WrapPointer(const_cast<DexFile*>(target_method.dex_file));
     // NOTE: The invoke type doesn't contribute to the literal identity. In fact, we can have
@@ -1230,7 +1223,7 @@
 void Mir2Lir::LoadMethodAddress(const MethodReference& target_method, InvokeType type,
                                 SpecialTargetRegister symbolic_reg) {
   LIR* data_target = ScanLiteralPoolMethod(method_literal_list_, target_method);
-  if (data_target == NULL) {
+  if (data_target == nullptr) {
     data_target = AddWordData(&method_literal_list_, target_method.dex_method_index);
     data_target->operands[1] = WrapPointer(const_cast<DexFile*>(target_method.dex_file));
     // NOTE: The invoke type doesn't contribute to the literal identity. In fact, we can have
@@ -1288,7 +1281,9 @@
 }
 
 void Mir2Lir::GenMachineSpecificExtendedMethodMIR(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb, mir);
   LOG(FATAL) << "Unknown MIR opcode not supported on this architecture";
+  UNREACHABLE();
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 0f1d765..84c0d93 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -68,40 +68,41 @@
     false,  // kIntrinsicUnsafePut
     true,   // kIntrinsicSystemArrayCopyCharArray
 };
-COMPILE_ASSERT(arraysize(kIntrinsicIsStatic) == kInlineOpNop, check_arraysize_kIntrinsicIsStatic);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicDoubleCvt], DoubleCvt_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicFloatCvt], FloatCvt_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicReverseBits], ReverseBits_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicReverseBytes], ReverseBytes_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsInt], AbsInt_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsLong], AbsLong_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsFloat], AbsFloat_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicAbsDouble], AbsDouble_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxInt], MinMaxInt_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxLong], MinMaxLong_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], MinMaxFloat_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], MinMaxDouble_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicSqrt], Sqrt_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicCeil], Ceil_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicFloor], Floor_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRint], Rint_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRoundFloat], RoundFloat_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRoundDouble], RoundDouble_must_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], Get_must_not_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCharAt], CharAt_must_not_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCompareTo], CompareTo_must_not_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], IsEmptyOrLength_must_not_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicIndexOf], IndexOf_must_not_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicCurrentThread], CurrentThread_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicPeek], Peek_must_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicPoke], Poke_must_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCas], Cas_must_not_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], UnsafeGet_must_not_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicUnsafePut], UnsafePut_must_not_be_static);
-COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray],
-               SystemArrayCopyCharArray_must_be_static);
+static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop,
+              "arraysize of kIntrinsicIsStatic unexpected");
+static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAbsDouble], "AbsDouble must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong_must_be_static");
+static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat_must_be_static");
+static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble_must_be_static");
+static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicRint], "Rint must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicRoundFloat], "RoundFloat must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet_must_not_be_static");
+static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray],
+              "SystemArrayCopyCharArray must be static");
 
-MIR* AllocReplacementMIR(MIRGraph* mir_graph, MIR* invoke, MIR* move_return) {
+MIR* AllocReplacementMIR(MIRGraph* mir_graph, MIR* invoke) {
   MIR* insn = mir_graph->NewMIR();
   insn->offset = invoke->offset;
   insn->optimization_flags = MIR_CALLEE;
@@ -111,18 +112,18 @@
 uint32_t GetInvokeReg(MIR* invoke, uint32_t arg) {
   DCHECK_LT(arg, invoke->dalvikInsn.vA);
   DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode));
-  if (Instruction::FormatOf(invoke->dalvikInsn.opcode) == Instruction::k3rc) {
-    return invoke->dalvikInsn.vC + arg;  // Non-range invoke.
+  if (IsInvokeInstructionRange(invoke->dalvikInsn.opcode)) {
+    return invoke->dalvikInsn.vC + arg;  // Range invoke.
   } else {
     DCHECK_EQ(Instruction::FormatOf(invoke->dalvikInsn.opcode), Instruction::k35c);
-    return invoke->dalvikInsn.arg[arg];  // Range invoke.
+    return invoke->dalvikInsn.arg[arg];  // Non-range invoke.
   }
 }
 
 bool WideArgIsInConsecutiveDalvikRegs(MIR* invoke, uint32_t arg) {
   DCHECK_LT(arg + 1, invoke->dalvikInsn.vA);
   DCHECK(!MIR::DecodedInstruction::IsPseudoMirOp(invoke->dalvikInsn.opcode));
-  return Instruction::FormatOf(invoke->dalvikInsn.opcode) == Instruction::k3rc ||
+  return IsInvokeInstructionRange(invoke->dalvikInsn.opcode) ||
       invoke->dalvikInsn.arg[arg + 1u] == invoke->dalvikInsn.arg[arg] + 1u;
 }
 
@@ -292,9 +293,9 @@
     { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
 
     INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
-    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
+    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, kIntrinsicFlagToFloatingPoint),
     INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
-    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
+    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint),
 
     INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32),
     INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64),
@@ -395,12 +396,15 @@
 DexFileMethodInliner::DexFileMethodInliner()
     : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock),
       dex_file_(NULL) {
-  COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0);
-  COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames);
-  COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0);
-  COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames);
-  COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0);
-  COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
+  static_assert(kClassCacheFirst == 0, "kClassCacheFirst not 0");
+  static_assert(arraysize(kClassCacheNames) == kClassCacheLast,
+                "bad arraysize for kClassCacheNames");
+  static_assert(kNameCacheFirst == 0, "kNameCacheFirst not 0");
+  static_assert(arraysize(kNameCacheNames) == kNameCacheLast,
+                "bad arraysize for kNameCacheNames");
+  static_assert(kProtoCacheFirst == 0, "kProtoCacheFirst not 0");
+  static_assert(arraysize(kProtoCacheDefs) == kProtoCacheLast,
+                "bad arraysize kProtoCacheNames");
 }
 
 DexFileMethodInliner::~DexFileMethodInliner() {
@@ -555,11 +559,11 @@
       break;
     case kInlineOpIGet:
       move_result = mir_graph->FindMoveResult(bb, invoke);
-      result = GenInlineIGet(mir_graph, bb, invoke, move_result, method, method_idx);
+      result = GenInlineIGet(mir_graph, bb, invoke, move_result, method);
       break;
     case kInlineOpIPut:
       move_result = mir_graph->FindMoveResult(bb, invoke);
-      result = GenInlineIPut(mir_graph, bb, invoke, move_result, method, method_idx);
+      result = GenInlineIPut(mir_graph, bb, invoke, move_result, method);
       break;
     default:
       LOG(FATAL) << "Unexpected inline op: " << method.opcode;
@@ -569,8 +573,7 @@
     // If the invoke has not been eliminated yet, check now whether we should do it.
     // This is done so that dataflow analysis does not get tripped up seeing nop invoke.
     if (static_cast<int>(invoke->dalvikInsn.opcode) != kMirOpNop) {
-      bool is_static = invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC ||
-          invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE;
+      bool is_static = IsInstructionInvokeStatic(invoke->dalvikInsn.opcode);
       if (is_static || (invoke->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) {
         // No null object register involved here so we can eliminate the invoke.
         invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
@@ -737,7 +740,7 @@
              method.d.data == 0u));
 
   // Insert the CONST instruction.
-  MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result);
+  MIR* insn = AllocReplacementMIR(mir_graph, invoke);
   insn->dalvikInsn.opcode = Instruction::CONST;
   insn->dalvikInsn.vA = move_result->dalvikInsn.vA;
   insn->dalvikInsn.vB = method.d.data;
@@ -775,7 +778,7 @@
   }
 
   // Insert the move instruction
-  MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result);
+  MIR* insn = AllocReplacementMIR(mir_graph, invoke);
   insn->dalvikInsn.opcode = opcode;
   insn->dalvikInsn.vA = move_result->dalvikInsn.vA;
   insn->dalvikInsn.vB = arg;
@@ -784,8 +787,7 @@
 }
 
 bool DexFileMethodInliner::GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
-                                         MIR* move_result, const InlineMethod& method,
-                                         uint32_t method_idx) {
+                                         MIR* move_result, const InlineMethod& method) {
   CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit();
   if (cu->enable_debug & (1 << kDebugSlowFieldPath)) {
     return false;
@@ -801,9 +803,7 @@
     return !data.is_volatile;
   }
 
-  DCHECK_EQ(data.method_is_static != 0u,
-            invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC ||
-            invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE);
+  DCHECK_EQ(data.method_is_static != 0u, IsInstructionInvokeStatic(invoke->dalvikInsn.opcode));
   bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u);
   if (!object_is_this) {
     // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE).
@@ -819,7 +819,7 @@
     invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
   }
 
-  MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result);
+  MIR* insn = AllocReplacementMIR(mir_graph, invoke);
   insn->offset = invoke->offset;
   insn->dalvikInsn.opcode = opcode;
   insn->dalvikInsn.vA = move_result->dalvikInsn.vA;
@@ -836,8 +836,7 @@
 }
 
 bool DexFileMethodInliner::GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
-                                         MIR* move_result, const InlineMethod& method,
-                                         uint32_t method_idx) {
+                                         MIR* move_result, const InlineMethod& method) {
   CompilationUnit* cu = mir_graph->GetCurrentDexCompilationUnit()->GetCompilationUnit();
   if (cu->enable_debug & (1 << kDebugSlowFieldPath)) {
     return false;
@@ -863,9 +862,7 @@
     return false;
   }
 
-  DCHECK_EQ(data.method_is_static != 0u,
-            invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC ||
-            invoke->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE);
+  DCHECK_EQ(data.method_is_static != 0u, IsInstructionInvokeStatic(invoke->dalvikInsn.opcode));
   bool object_is_this = (data.method_is_static == 0u && data.object_arg == 0u);
   if (!object_is_this) {
     // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE).
@@ -881,7 +878,7 @@
     invoke->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
   }
 
-  MIR* insn = AllocReplacementMIR(mir_graph, invoke, move_result);
+  MIR* insn = AllocReplacementMIR(mir_graph, invoke);
   insn->dalvikInsn.opcode = opcode;
   insn->dalvikInsn.vA = src_reg;
   insn->dalvikInsn.vB = object_reg;
@@ -895,7 +892,7 @@
   bb->InsertMIRAfter(invoke, insn);
 
   if (move_result != nullptr) {
-    MIR* move = AllocReplacementMIR(mir_graph, invoke, move_result);
+    MIR* move = AllocReplacementMIR(mir_graph, invoke);
     move->offset = move_result->offset;
     if (move_result->dalvikInsn.opcode == Instruction::MOVE_RESULT) {
       move->dalvikInsn.opcode = Instruction::MOVE_FROM16;
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 30a2d90..cb521da 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -31,9 +31,9 @@
 class MethodVerifier;
 }  // namespace verifier
 
-struct BasicBlock;
+class BasicBlock;
 struct CallInfo;
-struct MIR;
+class MIR;
 class MIRGraph;
 class Mir2Lir;
 
@@ -315,9 +315,9 @@
     static bool GenInlineReturnArg(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
                                    MIR* move_result, const InlineMethod& method);
     static bool GenInlineIGet(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
-                              MIR* move_result, const InlineMethod& method, uint32_t method_idx);
+                              MIR* move_result, const InlineMethod& method);
     static bool GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MIR* invoke,
-                              MIR* move_result, const InlineMethod& method, uint32_t method_idx);
+                              MIR* move_result, const InlineMethod& method);
 
     ReaderWriterMutex lock_;
     /*
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 9f7a881..aa47cee 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -13,6 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <functional>
+
+#include "arch/arm/instruction_set_features_arm.h"
 #include "dex/compiler_ir.h"
 #include "dex/compiler_internals.h"
 #include "dex/quick/arm/arm_lir.h"
@@ -22,8 +26,8 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_reference.h"
+#include "utils.h"
 #include "verifier/method_verifier.h"
-#include <functional>
 
 namespace art {
 
@@ -66,8 +70,8 @@
 void Mir2Lir::AddDivZeroCheckSlowPath(LIR* branch) {
   class DivZeroCheckSlowPath : public Mir2Lir::LIRSlowPath {
    public:
-    DivZeroCheckSlowPath(Mir2Lir* m2l, LIR* branch)
-        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch) {
+    DivZeroCheckSlowPath(Mir2Lir* m2l, LIR* branch_in)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in) {
     }
 
     void Compile() OVERRIDE {
@@ -84,9 +88,10 @@
 void Mir2Lir::GenArrayBoundsCheck(RegStorage index, RegStorage length) {
   class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
    public:
-    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch, RegStorage index, RegStorage length)
-        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
-          index_(index), length_(length) {
+    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch_in, RegStorage index_in,
+                             RegStorage length_in)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in),
+          index_(index_in), length_(length_in) {
     }
 
     void Compile() OVERRIDE {
@@ -108,9 +113,9 @@
 void Mir2Lir::GenArrayBoundsCheck(int index, RegStorage length) {
   class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
    public:
-    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch, int index, RegStorage length)
-        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
-          index_(index), length_(length) {
+    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch_in, int index_in, RegStorage length_in)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in),
+          index_(index_in), length_(length_in) {
     }
 
     void Compile() OVERRIDE {
@@ -160,6 +165,10 @@
   if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
     return GenExplicitNullCheck(m_reg, opt_flags);
   }
+  // If null check has not been eliminated, reset redundant store tracking.
+  if ((opt_flags & MIR_IGNORE_NULL_CHECK) == 0) {
+    ResetDefTracking();
+  }
   return nullptr;
 }
 
@@ -212,11 +221,9 @@
 }
 
 void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
-                                  RegLocation rl_src2, LIR* taken,
-                                  LIR* fall_through) {
-  DCHECK(!rl_src1.fp);
-  DCHECK(!rl_src2.fp);
+                                  RegLocation rl_src2, LIR* taken) {
   ConditionCode cond;
+  RegisterClass reg_class = (rl_src1.ref || rl_src2.ref) ? kRefReg : kCoreReg;
   switch (opcode) {
     case Instruction::IF_EQ:
       cond = kCondEq;
@@ -249,7 +256,7 @@
     cond = FlipComparisonOrder(cond);
   }
 
-  rl_src1 = LoadValue(rl_src1);
+  rl_src1 = LoadValue(rl_src1, reg_class);
   // Is this really an immediate comparison?
   if (rl_src2.is_const) {
     // If it's already live in a register or not easily materialized, just keep going
@@ -273,15 +280,14 @@
     }
   }
 
-  rl_src2 = LoadValue(rl_src2);
+  rl_src2 = LoadValue(rl_src2, reg_class);
   OpCmpBranch(cond, rl_src1.reg, rl_src2.reg, taken);
 }
 
-void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken,
-                                      LIR* fall_through) {
+void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken) {
   ConditionCode cond;
-  DCHECK(!rl_src.fp);
-  rl_src = LoadValue(rl_src);
+  RegisterClass reg_class = rl_src.ref ? kRefReg : kCoreReg;
+  rl_src = LoadValue(rl_src, reg_class);
   switch (opcode) {
     case Instruction::IF_EQZ:
       cond = kCondEq;
@@ -319,6 +325,12 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+void Mir2Lir::GenLongToInt(RegLocation rl_dest, RegLocation rl_src) {
+  rl_src = UpdateLocWide(rl_src);
+  rl_src = NarrowRegLoc(rl_src);
+  StoreValue(rl_dest, rl_src);
+}
+
 void Mir2Lir::GenIntNarrowing(Instruction::Code opcode, RegLocation rl_dest,
                               RegLocation rl_src) {
   rl_src = LoadValue(rl_src, kCoreReg);
@@ -362,19 +374,19 @@
       // The fast path.
       if (!use_direct_type_ptr) {
         LoadClassType(*dex_file, type_idx, kArg0);
-        CallRuntimeHelperRegMethodRegLocation(kQuickAllocArrayResolved, TargetReg(kArg0, kNotWide),
+        CallRuntimeHelperRegRegLocationMethod(kQuickAllocArrayResolved, TargetReg(kArg0, kNotWide),
                                               rl_src, true);
       } else {
         // Use the direct pointer.
-        CallRuntimeHelperImmMethodRegLocation(kQuickAllocArrayResolved, direct_type_ptr, rl_src,
+        CallRuntimeHelperImmRegLocationMethod(kQuickAllocArrayResolved, direct_type_ptr, rl_src,
                                               true);
       }
     } else {
       // The slow path.
-      CallRuntimeHelperImmMethodRegLocation(kQuickAllocArray, type_idx, rl_src, true);
+      CallRuntimeHelperImmRegLocationMethod(kQuickAllocArray, type_idx, rl_src, true);
     }
   } else {
-    CallRuntimeHelperImmMethodRegLocation(kQuickAllocArrayWithAccessCheck, type_idx, rl_src, true);
+    CallRuntimeHelperImmRegLocationMethod(kQuickAllocArrayWithAccessCheck, type_idx, rl_src, true);
   }
   StoreValue(rl_dest, GetReturn(kRefReg));
 }
@@ -396,7 +408,7 @@
   } else {
     target = kQuickCheckAndAllocArrayWithAccessCheck;
   }
-  CallRuntimeHelperImmMethodImm(target, type_idx, elems, true);
+  CallRuntimeHelperImmImmMethod(target, type_idx, elems, true);
   FreeTemp(TargetReg(kArg2, kNotWide));
   FreeTemp(TargetReg(kArg1, kNotWide));
   /*
@@ -413,8 +425,8 @@
   // share array alignment with ints (see comment at head of function)
   size_t component_size = sizeof(int32_t);
 
-  // Having a range of 0 is legal
-  if (info->is_range && (elems > 0)) {
+  if (elems > 5) {
+    DCHECK(info->is_range);  // Non-range insn can't encode more than 5 elems.
     /*
      * Bit of ugliness here.  We're going generate a mem copy loop
      * on the register range, but it is possible that some regs
@@ -427,7 +439,11 @@
       RegLocation loc = UpdateLoc(info->args[i]);
       if (loc.location == kLocPhysReg) {
         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        Store32Disp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg);
+        if (loc.ref) {
+          StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile);
+        } else {
+          Store32Disp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg);
+        }
       }
     }
     /*
@@ -464,7 +480,7 @@
     // Set up the loop counter (known to be > 0)
     LoadConstant(r_idx, elems - 1);
     // Generate the copy loop.  Going backwards for convenience
-    LIR* target = NewLIR0(kPseudoTargetLabel);
+    LIR* loop_head_target = NewLIR0(kPseudoTargetLabel);
     // Copy next element
     {
       ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -474,43 +490,91 @@
     }
     StoreBaseIndexed(r_dst, r_idx, r_val, 2, k32);
     FreeTemp(r_val);
-    OpDecAndBranch(kCondGe, r_idx, target);
+    OpDecAndBranch(kCondGe, r_idx, loop_head_target);
     if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
       // Restore the target pointer
       OpRegRegImm(kOpAdd, ref_reg, r_dst,
                   -mirror::Array::DataOffset(component_size).Int32Value());
     }
-  } else if (!info->is_range) {
+    FreeTemp(r_idx);
+    FreeTemp(r_dst);
+    FreeTemp(r_src);
+  } else {
+    DCHECK_LE(elems, 5);  // Usually but not necessarily non-range.
     // TUNING: interleave
     for (int i = 0; i < elems; i++) {
-      RegLocation rl_arg = LoadValue(info->args[i], kCoreReg);
-      Store32Disp(ref_reg,
-                  mirror::Array::DataOffset(component_size).Int32Value() + i * 4, rl_arg.reg);
+      RegLocation rl_arg;
+      if (info->args[i].ref) {
+        rl_arg = LoadValue(info->args[i], kRefReg);
+        StoreRefDisp(ref_reg,
+                    mirror::Array::DataOffset(component_size).Int32Value() + i * 4, rl_arg.reg,
+                    kNotVolatile);
+      } else {
+        rl_arg = LoadValue(info->args[i], kCoreReg);
+        Store32Disp(ref_reg,
+                    mirror::Array::DataOffset(component_size).Int32Value() + i * 4, rl_arg.reg);
+      }
       // If the LoadValue caused a temp to be allocated, free it
       if (IsTemp(rl_arg.reg)) {
         FreeTemp(rl_arg.reg);
       }
     }
   }
+  if (elems != 0 && info->args[0].ref) {
+    // If there is at least one potentially non-null value, unconditionally mark the GC card.
+    for (int i = 0; i < elems; i++) {
+      if (!mir_graph_->IsConstantNullRef(info->args[i])) {
+        UnconditionallyMarkGCCard(ref_reg);
+        break;
+      }
+    }
+  }
   if (info->result.location != kLocInvalid) {
     StoreValue(info->result, GetReturn(kRefReg));
   }
 }
 
+/*
+ * Array data table format:
+ *  ushort ident = 0x0300   magic value
+ *  ushort width            width of each element in the table
+ *  uint   size             number of elements in the table
+ *  ubyte  data[size*width] table of data values (may contain a single-byte
+ *                          padding at the end)
+ *
+ * Total size is 4+(width * size + 1)/2 16-bit code units.
+ */
+void Mir2Lir::GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
+  if (kIsDebugBuild) {
+    const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
+    const Instruction::ArrayDataPayload* payload =
+        reinterpret_cast<const Instruction::ArrayDataPayload*>(table);
+    CHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
+  }
+  uint32_t table_offset_from_start = mir->offset + static_cast<int32_t>(table_offset);
+  CallRuntimeHelperImmRegLocation(kQuickHandleFillArrayData, table_offset_from_start, rl_src, true);
+}
+
 //
 // Slow path to ensure a class is initialized for sget/sput.
 //
 class StaticFieldSlowPath : public Mir2Lir::LIRSlowPath {
  public:
+  // There are up to two branches to the static field slow path, the "unresolved" when the type
+  // entry in the dex cache is null, and the "uninit" when the class is not yet initialized.
+  // At least one will be non-null here, otherwise we wouldn't generate the slow path.
   StaticFieldSlowPath(Mir2Lir* m2l, LIR* unresolved, LIR* uninit, LIR* cont, int storage_index,
-                      RegStorage r_base) :
-    LIRSlowPath(m2l, m2l->GetCurrentDexPc(), unresolved, cont), uninit_(uninit),
-               storage_index_(storage_index), r_base_(r_base) {
+                      RegStorage r_base)
+      : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), unresolved != nullptr ? unresolved : uninit, cont),
+        second_branch_(unresolved != nullptr ? uninit : nullptr),
+        storage_index_(storage_index), r_base_(r_base) {
   }
 
   void Compile() {
-    LIR* unresolved_target = GenerateTargetLabel();
-    uninit_->target = unresolved_target;
+    LIR* target = GenerateTargetLabel();
+    if (second_branch_ != nullptr) {
+      second_branch_->target = target;
+    }
     m2l_->CallRuntimeHelperImm(kQuickInitializeStaticStorage, storage_index_, true);
     // Copy helper's result into r_base, a no-op on all but MIPS.
     m2l_->OpRegCopy(r_base_,  m2l_->TargetReg(kRet0, kRef));
@@ -519,13 +583,16 @@
   }
 
  private:
-  LIR* const uninit_;
+  // Second branch to the slow path, or null if there's only one branch.
+  LIR* const second_branch_;
+
   const int storage_index_;
   const RegStorage r_base_;
 };
 
 void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, OpSize size) {
   const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
+  DCHECK_EQ(SPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
   cu_->compiler_driver->ProcessedStaticField(field_info.FastPut(), field_info.IsReferrersClass());
   if (!SLOW_FIELD_PATH && field_info.FastPut()) {
     DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
@@ -557,30 +624,38 @@
       int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
       LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile);
       // r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
-      if (!field_info.IsInitialized() &&
-          (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
-        // Check if r_base is NULL or a not yet initialized class.
-
-        // The slow path is invoked if the r_base is NULL or the class pointed
-        // to by it is not initialized.
-        LIR* unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL);
+      LIR* unresolved_branch = nullptr;
+      if (!field_info.IsClassInDexCache() &&
+          (mir->optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) == 0) {
+        // Check if r_base is NULL.
+        unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL);
+      }
+      LIR* uninit_branch = nullptr;
+      if (!field_info.IsClassInitialized() &&
+          (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
+        // Check if r_base is not yet initialized class.
         RegStorage r_tmp = TargetReg(kArg2, kNotWide);
         LockTemp(r_tmp);
-        LIR* uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
+        uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
                                           mirror::Class::StatusOffset().Int32Value(),
                                           mirror::Class::kStatusInitialized, nullptr, nullptr);
+        FreeTemp(r_tmp);
+      }
+      if (unresolved_branch != nullptr || uninit_branch != nullptr) {
+        // The slow path is invoked if the r_base is NULL or the class pointed
+        // to by it is not initialized.
         LIR* cont = NewLIR0(kPseudoTargetLabel);
-
         AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
                                                      field_info.StorageIndex(), r_base));
 
-        FreeTemp(r_tmp);
-        // Ensure load of status and store of value don't re-order.
-        // TODO: Presumably the actual value store is control-dependent on the status load,
-        // and will thus not be reordered in any case, since stores are never speculated.
-        // Does later code "know" that the class is now initialized?  If so, we still
-        // need the barrier to guard later static loads.
-        GenMemBarrier(kLoadAny);
+        if (uninit_branch != nullptr) {
+          // Ensure load of status and store of value don't re-order.
+          // TODO: Presumably the actual value store is control-dependent on the status load,
+          // and will thus not be reordered in any case, since stores are never speculated.
+          // Does later code "know" that the class is now initialized?  If so, we still
+          // need the barrier to guard later static loads.
+          GenMemBarrier(kLoadAny);
+        }
       }
       FreeTemp(r_method);
     }
@@ -599,7 +674,7 @@
                     field_info.IsVolatile() ? kVolatile : kNotVolatile);
     }
     if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
-      MarkGCCard(rl_src.reg, r_base);
+      MarkGCCard(mir->optimization_flags, rl_src.reg, r_base);
     }
     FreeTemp(r_base);
   } else {
@@ -636,6 +711,7 @@
 
 void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest, OpSize size, Primitive::Type type) {
   const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
+  DCHECK_EQ(SGetMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
   cu_->compiler_driver->ProcessedStaticField(field_info.FastGet(), field_info.IsReferrersClass());
 
   if (!SLOW_FIELD_PATH && field_info.FastGet()) {
@@ -664,26 +740,34 @@
       int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
       LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile);
       // r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
-      if (!field_info.IsInitialized() &&
-          (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
-        // Check if r_base is NULL or a not yet initialized class.
-
-        // The slow path is invoked if the r_base is NULL or the class pointed
-        // to by it is not initialized.
-        LIR* unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL);
+      LIR* unresolved_branch = nullptr;
+      if (!field_info.IsClassInDexCache() &&
+          (mir->optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) == 0) {
+        // Check if r_base is NULL.
+        unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL);
+      }
+      LIR* uninit_branch = nullptr;
+      if (!field_info.IsClassInitialized() &&
+          (mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
+        // Check if r_base is not yet initialized class.
         RegStorage r_tmp = TargetReg(kArg2, kNotWide);
         LockTemp(r_tmp);
-        LIR* uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
+        uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
                                           mirror::Class::StatusOffset().Int32Value(),
                                           mirror::Class::kStatusInitialized, nullptr, nullptr);
+        FreeTemp(r_tmp);
+      }
+      if (unresolved_branch != nullptr || uninit_branch != nullptr) {
+        // The slow path is invoked if the r_base is NULL or the class pointed
+        // to by it is not initialized.
         LIR* cont = NewLIR0(kPseudoTargetLabel);
-
         AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
                                                      field_info.StorageIndex(), r_base));
 
-        FreeTemp(r_tmp);
-        // Ensure load of status and load of value don't re-order.
-        GenMemBarrier(kLoadAny);
+        if (uninit_branch != nullptr) {
+          // Ensure load of status and load of value don't re-order.
+          GenMemBarrier(kLoadAny);
+        }
       }
       FreeTemp(r_method);
     }
@@ -766,6 +850,7 @@
 void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size, Primitive::Type type,
                       RegLocation rl_dest, RegLocation rl_obj) {
   const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
+  DCHECK_EQ(IGetMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
   cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet());
   if (!SLOW_FIELD_PATH && field_info.FastGet()) {
     RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile());
@@ -839,6 +924,7 @@
 void Mir2Lir::GenIPut(MIR* mir, int opt_flags, OpSize size,
                       RegLocation rl_src, RegLocation rl_obj) {
   const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
+  DCHECK_EQ(IPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
   cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut());
   if (!SLOW_FIELD_PATH && field_info.FastPut()) {
     RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile());
@@ -853,17 +939,17 @@
     }
     GenNullCheck(rl_obj.reg, opt_flags);
     int field_offset = field_info.FieldOffset().Int32Value();
-    LIR* store;
+    LIR* null_ck_insn;
     if (IsRef(size)) {
-      store = StoreRefDisp(rl_obj.reg, field_offset, rl_src.reg, field_info.IsVolatile() ?
+      null_ck_insn = StoreRefDisp(rl_obj.reg, field_offset, rl_src.reg, field_info.IsVolatile() ?
           kVolatile : kNotVolatile);
     } else {
-      store = StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, size,
-                            field_info.IsVolatile() ? kVolatile : kNotVolatile);
+      null_ck_insn = StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, size,
+                                   field_info.IsVolatile() ? kVolatile : kNotVolatile);
     }
-    MarkPossibleNullPointerExceptionAfter(opt_flags, store);
+    MarkPossibleNullPointerExceptionAfter(opt_flags, null_ck_insn);
     if (IsRef(size) && !mir_graph_->IsConstantNullRef(rl_src)) {
-      MarkGCCard(rl_src.reg, rl_obj.reg);
+      MarkGCCard(opt_flags, rl_src.reg, rl_obj.reg);
     }
   } else {
     QuickEntrypointEnum target;
@@ -913,7 +999,6 @@
   RegLocation rl_method = LoadCurrMethod();
   CheckRegLocation(rl_method);
   RegStorage res_reg = AllocTempRef();
-  RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
   if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
                                                         *cu_->dex_file,
                                                         type_idx)) {
@@ -923,6 +1008,7 @@
     RegLocation rl_result = GetReturn(kRefReg);
     StoreValue(rl_dest, rl_result);
   } else {
+    RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
     // We're don't need access checks, load type from dex cache
     int32_t dex_cache_offset =
         mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value();
@@ -939,10 +1025,10 @@
       // Object to generate the slow path for class resolution.
       class SlowPath : public LIRSlowPath {
        public:
-        SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, const int type_idx,
-                 const RegLocation& rl_method, const RegLocation& rl_result) :
-                   LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont), type_idx_(type_idx),
-                   rl_method_(rl_method), rl_result_(rl_result) {
+        SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont_in, const int type_idx_in,
+                 const RegLocation& rl_method_in, const RegLocation& rl_result_in) :
+                   LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont_in),
+                   type_idx_(type_idx_in), rl_method_(rl_method_in), rl_result_(rl_result_in) {
         }
 
         void Compile() {
@@ -991,7 +1077,11 @@
       r_method = TargetReg(kArg2, kRef);
       LoadCurrMethodDirect(r_method);
     }
-    LoadRefDisp(r_method, mirror::ArtMethod::DexCacheStringsOffset().Int32Value(),
+    // Method to declaring class.
+    LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
+                TargetReg(kArg0, kRef), kNotVolatile);
+    // Declaring class to dex cache strings.
+    LoadRefDisp(TargetReg(kArg0, kRef), mirror::Class::DexCacheStringsOffset().Int32Value(),
                 TargetReg(kArg0, kRef), kNotVolatile);
 
     // Might call out to helper, which will return resolved string in kRet0
@@ -1003,14 +1093,15 @@
       // Object to generate the slow path for string resolution.
       class SlowPath : public LIRSlowPath {
        public:
-        SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, RegStorage r_method, int32_t string_idx) :
-          LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont),
-          r_method_(r_method), string_idx_(string_idx) {
+        SlowPath(Mir2Lir* m2l, LIR* fromfast_in, LIR* cont_in, RegStorage r_method_in,
+                 int32_t string_idx_in) :
+            LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast_in, cont_in),
+            r_method_(r_method_in), string_idx_(string_idx_in) {
         }
 
         void Compile() {
           GenerateTargetLabel();
-          m2l_->CallRuntimeHelperRegImm(kQuickResolveString, r_method_, string_idx_, true);
+          m2l_->CallRuntimeHelperImmReg(kQuickResolveString, string_idx_, r_method_, true);
           m2l_->OpUnconditionalBranch(cont_);
         }
 
@@ -1028,7 +1119,9 @@
     RegLocation rl_method = LoadCurrMethod();
     RegStorage res_reg = AllocTempRef();
     RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
-    LoadRefDisp(rl_method.reg, mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), res_reg,
+    LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), res_reg,
+                kNotVolatile);
+    LoadRefDisp(res_reg, mirror::Class::DexCacheStringsOffset().Int32Value(), res_reg,
                 kNotVolatile);
     LoadRefDisp(res_reg, offset_of_string, rl_result.reg, kNotVolatile);
     StoreValue(rl_dest, rl_result);
@@ -1183,10 +1276,10 @@
 
       class InitTypeSlowPath : public Mir2Lir::LIRSlowPath {
        public:
-        InitTypeSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont, uint32_t type_idx,
-                         RegLocation rl_src)
-            : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont), type_idx_(type_idx),
-              rl_src_(rl_src) {
+        InitTypeSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont, uint32_t type_idx_in,
+                         RegLocation rl_src_in)
+            : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont), type_idx_(type_idx_in),
+              rl_src_(rl_src_in) {
         }
 
         void Compile() OVERRIDE {
@@ -1328,10 +1421,10 @@
       // Slow path to initialize the type.  Executed if the type is NULL.
       class SlowPath : public LIRSlowPath {
        public:
-        SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, const int type_idx,
-                 const RegStorage class_reg) :
-                   LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont), type_idx_(type_idx),
-                   class_reg_(class_reg) {
+        SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont_in, const int type_idx_in,
+                 const RegStorage class_reg_in) :
+                   LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont_in),
+                   type_idx_(type_idx_in), class_reg_(class_reg_in) {
         }
 
         void Compile() {
@@ -1481,7 +1574,7 @@
 
 
 void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
-                            RegLocation rl_src1, RegLocation rl_src2) {
+                            RegLocation rl_src1, RegLocation rl_src2, int flags) {
   DCHECK(cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64);
   OpKind op = kOpBkpt;
   bool is_div_rem = false;
@@ -1580,18 +1673,19 @@
     if (cu_->instruction_set == kMips || cu_->instruction_set == kArm64) {
       rl_src1 = LoadValue(rl_src1, kCoreReg);
       rl_src2 = LoadValue(rl_src2, kCoreReg);
-      if (check_zero) {
+      if (check_zero && (flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
         GenDivZeroCheck(rl_src2.reg);
       }
       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);
         rl_src2 = LoadValue(rl_src2, kCoreReg);
-        if (check_zero) {
+        if (check_zero && (flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
           GenDivZeroCheck(rl_src2.reg);
         }
         rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, op == kOpDiv);
@@ -1605,7 +1699,7 @@
       LoadValueDirectFixed(rl_src2, TargetReg(kArg1, kNotWide));
       RegStorage r_tgt = CallHelperSetup(kQuickIdivmod);
       LoadValueDirectFixed(rl_src1, TargetReg(kArg0, kNotWide));
-      if (check_zero) {
+      if (check_zero && (flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
         GenDivZeroCheck(TargetReg(kArg1, kNotWide));
       }
       // NOTE: callout here is not a safepoint.
@@ -1633,16 +1727,12 @@
 
 // Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
 // and store the result in 'rl_dest'.
-bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
+bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode ATTRIBUTE_UNUSED, bool is_div,
                                RegLocation rl_src, RegLocation rl_dest, int lit) {
-  if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
+  if ((lit < 2) || (!IsPowerOfTwo(lit))) {
     return false;
   }
-  // No divide instruction for Arm, so check for more special cases
-  if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
-    return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
-  }
-  int k = LowestSetBit(lit);
+  int k = CTZ(lit);
   if (k >= 30) {
     // Avoid special cases.
     return false;
@@ -1722,24 +1812,52 @@
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (power_of_two) {
     // Shift.
-    OpRegRegImm(kOpLsl, rl_result.reg, rl_src.reg, LowestSetBit(lit));
+    OpRegRegImm(kOpLsl, rl_result.reg, rl_src.reg, CTZ(lit));
   } else if (pop_count_le2) {
     // Shift and add and shift.
-    int first_bit = LowestSetBit(lit);
-    int second_bit = LowestSetBit(lit ^ (1 << first_bit));
+    int first_bit = CTZ(lit);
+    int second_bit = CTZ(lit ^ (1 << first_bit));
     GenMultiplyByTwoBitMultiplier(rl_src, rl_result, lit, first_bit, second_bit);
   } else {
     // Reverse subtract: (src << (shift + 1)) - src.
     DCHECK(power_of_two_minus_one);
-    // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
+    // TUNING: rsb dst, src, src lsl#CTZ(lit + 1)
     RegStorage t_reg = AllocTemp();
-    OpRegRegImm(kOpLsl, t_reg, rl_src.reg, LowestSetBit(lit + 1));
+    OpRegRegImm(kOpLsl, t_reg, rl_src.reg, CTZ(lit + 1));
     OpRegRegReg(kOpSub, rl_result.reg, t_reg, rl_src.reg);
   }
   StoreValue(rl_dest, rl_result);
   return true;
 }
 
+// Returns true if it generates instructions.
+bool Mir2Lir::HandleEasyFloatingPointDiv(RegLocation rl_dest, RegLocation rl_src1,
+                                         RegLocation rl_src2) {
+  if (!rl_src2.is_const ||
+      ((cu_->instruction_set != kThumb2) && (cu_->instruction_set != kArm64))) {
+    return false;
+  }
+
+  if (!rl_src2.wide) {
+    int32_t divisor = mir_graph_->ConstantValue(rl_src2);
+    if (CanDivideByReciprocalMultiplyFloat(divisor)) {
+      // Generate multiply by reciprocal instead of div.
+      float recip = 1.0f/bit_cast<int32_t, float>(divisor);
+      GenMultiplyByConstantFloat(rl_dest, rl_src1, bit_cast<float, int32_t>(recip));
+      return true;
+    }
+  } else {
+    int64_t divisor = mir_graph_->ConstantValueWide(rl_src2);
+    if (CanDivideByReciprocalMultiplyDouble(divisor)) {
+      // Generate multiply by reciprocal instead of div.
+      double recip = 1.0/bit_cast<double, int64_t>(divisor);
+      GenMultiplyByConstantDouble(rl_dest, rl_src1, bit_cast<double, int64_t>(recip));
+      return true;
+    }
+  }
+  return false;
+}
+
 void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src,
                                int lit) {
   RegLocation rl_result;
@@ -1765,7 +1883,7 @@
     case Instruction::SUB_INT:
     case Instruction::SUB_INT_2ADDR:
       lit = -lit;
-      // Intended fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::ADD_INT:
     case Instruction::ADD_INT_2ADDR:
     case Instruction::ADD_INT_LIT8:
@@ -1855,7 +1973,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);
@@ -1892,7 +2011,7 @@
 }
 
 void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                             RegLocation rl_src1, RegLocation rl_src2) {
+                             RegLocation rl_src1, RegLocation rl_src2, int flags) {
   RegLocation rl_result;
   OpKind first_op = kOpBkpt;
   OpKind second_op = kOpBkpt;
@@ -1977,7 +2096,9 @@
       RegStorage r_tmp2 = TargetReg(kArg2, kWide);
       LoadValueDirectWideFixed(rl_src2, r_tmp2);
       RegStorage r_tgt = CallHelperSetup(target);
-      GenDivZeroCheckWide(r_tmp2);
+      if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
+        GenDivZeroCheckWide(r_tmp2);
+      }
       LoadValueDirectWideFixed(rl_src1, r_tmp1);
       // NOTE: callout here is not a safepoint
       CallHelper(r_tgt, target, false /* not safepoint */);
@@ -2041,18 +2162,15 @@
 
 /* Check if we need to check for pending suspend request */
 void Mir2Lir::GenSuspendTest(int opt_flags) {
+  if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK) != 0) {
+    return;
+  }
   if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) {
-    if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
-      return;
-    }
     FlushAllRegs();
     LIR* branch = OpTestSuspend(NULL);
     LIR* cont = NewLIR0(kPseudoTargetLabel);
     AddSlowPath(new (arena_) SuspendCheckSlowPath(this, branch, cont));
   } else {
-    if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
-      return;
-    }
     FlushAllRegs();     // TODO: needed?
     LIR* inst = CheckSuspendUsingLoad();
     MarkSafepointPC(inst);
@@ -2061,11 +2179,11 @@
 
 /* Check if we need to check for pending suspend request */
 void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
+  if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK) != 0) {
+    OpUnconditionalBranch(target);
+    return;
+  }
   if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) {
-    if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
-      OpUnconditionalBranch(target);
-      return;
-    }
     OpTestSuspend(target);
     FlushAllRegs();
     LIR* branch = OpUnconditionalBranch(nullptr);
@@ -2073,10 +2191,6 @@
   } else {
     // For the implicit suspend check, just perform the trigger
     // load and branch to the target.
-    if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
-      OpUnconditionalBranch(target);
-      return;
-    }
     FlushAllRegs();
     LIR* inst = CheckSuspendUsingLoad();
     MarkSafepointPC(inst);
@@ -2086,12 +2200,14 @@
 
 /* Call out to helper assembly routine that will null check obj and then lock it. */
 void Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
+  UNUSED(opt_flags);  // TODO: avoid null check with specialized non-null helper.
   FlushAllRegs();
   CallRuntimeHelperRegLocation(kQuickLockObject, rl_src, true);
 }
 
 /* Call out to helper assembly routine that will null check obj and then unlock it. */
 void Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
+  UNUSED(opt_flags);  // TODO: avoid null check with specialized non-null helper.
   FlushAllRegs();
   CallRuntimeHelperRegLocation(kQuickUnlockObject, rl_src, true);
 }
@@ -2104,43 +2220,53 @@
 }
 
 void Mir2Lir::GenSmallPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
+  BasicBlock* bb = mir_graph_->GetBasicBlock(mir->bb);
+  DCHECK(bb != nullptr);
+  ArenaVector<SuccessorBlockInfo*>::const_iterator succ_bb_iter = bb->successor_blocks.cbegin();
   const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
   const uint16_t entries = table[1];
   // Chained cmp-and-branch.
   const int32_t* as_int32 = reinterpret_cast<const int32_t*>(&table[2]);
-  int32_t current_key = as_int32[0];
-  const int32_t* targets = &as_int32[1];
+  int32_t starting_key = as_int32[0];
   rl_src = LoadValue(rl_src, kCoreReg);
   int i = 0;
-  for (; i < entries; i++, current_key++) {
-    if (!InexpensiveConstantInt(current_key, Instruction::Code::IF_EQ)) {
+  for (; i < entries; ++i, ++succ_bb_iter) {
+    if (!InexpensiveConstantInt(starting_key + i, Instruction::Code::IF_EQ)) {
       // Switch to using a temp and add.
       break;
     }
-    BasicBlock* case_block =
-        mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
-    OpCmpImmBranch(kCondEq, rl_src.reg, current_key, &block_label_list_[case_block->id]);
+    SuccessorBlockInfo* successor_block_info = *succ_bb_iter;
+    DCHECK(successor_block_info != nullptr);
+    int case_block_id = successor_block_info->block;
+    DCHECK_EQ(starting_key + i, successor_block_info->key);
+    OpCmpImmBranch(kCondEq, rl_src.reg, starting_key + i, &block_label_list_[case_block_id]);
   }
   if (i < entries) {
     // The rest do not seem to be inexpensive. Try to allocate a temp and use add.
     RegStorage key_temp = AllocTypedTemp(false, kCoreReg, false);
     if (key_temp.Valid()) {
-      LoadConstantNoClobber(key_temp, current_key);
-      for (; i < entries - 1; i++, current_key++) {
-        BasicBlock* case_block =
-            mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
-        OpCmpBranch(kCondEq, rl_src.reg, key_temp, &block_label_list_[case_block->id]);
+      LoadConstantNoClobber(key_temp, starting_key + i);
+      for (; i < entries - 1; ++i, ++succ_bb_iter) {
+        SuccessorBlockInfo* successor_block_info = *succ_bb_iter;
+        DCHECK(successor_block_info != nullptr);
+        int case_block_id = successor_block_info->block;
+        DCHECK_EQ(starting_key + i, successor_block_info->key);
+        OpCmpBranch(kCondEq, rl_src.reg, key_temp, &block_label_list_[case_block_id]);
         OpRegImm(kOpAdd, key_temp, 1);  // Increment key.
       }
-      BasicBlock* case_block =
-          mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
-      OpCmpBranch(kCondEq, rl_src.reg, key_temp, &block_label_list_[case_block->id]);
+      SuccessorBlockInfo* successor_block_info = *succ_bb_iter;
+      DCHECK(successor_block_info != nullptr);
+      int case_block_id = successor_block_info->block;
+      DCHECK_EQ(starting_key + i, successor_block_info->key);
+      OpCmpBranch(kCondEq, rl_src.reg, key_temp, &block_label_list_[case_block_id]);
     } else {
       // No free temp, just finish the old loop.
-      for (; i < entries; i++, current_key++) {
-        BasicBlock* case_block =
-            mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
-        OpCmpImmBranch(kCondEq, rl_src.reg, current_key, &block_label_list_[case_block->id]);
+      for (; i < entries; ++i, ++succ_bb_iter) {
+        SuccessorBlockInfo* successor_block_info = *succ_bb_iter;
+        DCHECK(successor_block_info != nullptr);
+        int case_block_id = successor_block_info->block;
+        DCHECK_EQ(starting_key + i, successor_block_info->key);
+        OpCmpImmBranch(kCondEq, rl_src.reg, starting_key + i, &block_label_list_[case_block_id]);
       }
     }
   }
@@ -2149,7 +2275,7 @@
 void Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
   const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
   if (cu_->verbose) {
-    DumpSparseSwitchTable(table);
+    DumpPackedSwitchTable(table);
   }
 
   const uint16_t entries = table[1];
@@ -2162,18 +2288,20 @@
 }
 
 void Mir2Lir::GenSmallSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
+  BasicBlock* bb = mir_graph_->GetBasicBlock(mir->bb);
+  DCHECK(bb != nullptr);
   const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
   const uint16_t entries = table[1];
   // Chained cmp-and-branch.
-  const int32_t* keys = reinterpret_cast<const int32_t*>(&table[2]);
-  const int32_t* targets = &keys[entries];
   rl_src = LoadValue(rl_src, kCoreReg);
-  for (int i = 0; i < entries; i++) {
-    int key = keys[i];
-    BasicBlock* case_block =
-        mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
-    OpCmpImmBranch(kCondEq, rl_src.reg, key, &block_label_list_[case_block->id]);
+  int i = 0;
+  for (SuccessorBlockInfo* successor_block_info : bb->successor_blocks) {
+    int case_block_id = successor_block_info->block;
+    int key = successor_block_info->key;
+    OpCmpImmBranch(kCondEq, rl_src.reg, key, &block_label_list_[case_block_id]);
+    i++;
   }
+  DCHECK_EQ(i, entries);
 }
 
 void Mir2Lir::GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index c308932..2a6dfef 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -44,8 +44,8 @@
 void Mir2Lir::AddIntrinsicSlowPath(CallInfo* info, LIR* branch, LIR* resume) {
   class IntrinsicSlowPathPath : public Mir2Lir::LIRSlowPath {
    public:
-    IntrinsicSlowPathPath(Mir2Lir* m2l, CallInfo* info, LIR* branch, LIR* resume = nullptr)
-        : LIRSlowPath(m2l, info->offset, branch, resume), info_(info) {
+    IntrinsicSlowPathPath(Mir2Lir* m2l, CallInfo* info_in, LIR* branch_in, LIR* resume_in)
+        : LIRSlowPath(m2l, info_in->offset, branch_in, resume_in), info_(info_in) {
     }
 
     void Compile() {
@@ -201,16 +201,16 @@
   CallHelper(r_tgt, trampoline, safepoint_pc);
 }
 
-void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(QuickEntrypointEnum trampoline, RegStorage arg0,
-                                                    RegLocation arg2, bool safepoint_pc) {
+void Mir2Lir::CallRuntimeHelperRegRegLocationMethod(QuickEntrypointEnum trampoline, RegStorage arg0,
+                                                    RegLocation arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(trampoline);
-  DCHECK(!IsSameReg(TargetReg(kArg1, arg0.GetWideKind()), arg0));
+  DCHECK(!IsSameReg(TargetReg(kArg2, arg0.GetWideKind()), arg0));
   RegStorage r_tmp = TargetReg(kArg0, arg0.GetWideKind());
   if (r_tmp.NotExactlyEquals(arg0)) {
     OpRegCopy(r_tmp, arg0);
   }
-  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
-  LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
+  LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
+  LoadCurrMethodDirect(TargetReg(kArg2, kRef));
   ClobberCallerSave();
   CallHelper(r_tgt, trampoline, safepoint_pc);
 }
@@ -248,13 +248,13 @@
         if (cu_->instruction_set == kMips) {
           LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg1, kNotWide));
         } else {
-          LoadValueDirectFixed(arg1, TargetReg(kArg1, kNotWide));
+          LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg1 : kArg1, kNotWide));
         }
       } else {
         if (cu_->instruction_set == kMips) {
           LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kWide));
         } else {
-          LoadValueDirectWideFixed(arg1, TargetReg(kArg1, kWide));
+          LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg1 : kArg1, kWide));
         }
       }
     } else {
@@ -306,21 +306,21 @@
   CallHelper(r_tgt, trampoline, safepoint_pc);
 }
 
-void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(QuickEntrypointEnum trampoline, int arg0,
-                                                    RegLocation arg2, bool safepoint_pc) {
+void Mir2Lir::CallRuntimeHelperImmRegLocationMethod(QuickEntrypointEnum trampoline, int arg0,
+                                                    RegLocation arg1, bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(trampoline);
-  LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
-  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
+  LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
+  LoadCurrMethodDirect(TargetReg(kArg2, kRef));
   LoadConstant(TargetReg(kArg0, kNotWide), arg0);
   ClobberCallerSave();
   CallHelper(r_tgt, trampoline, safepoint_pc);
 }
 
-void Mir2Lir::CallRuntimeHelperImmMethodImm(QuickEntrypointEnum trampoline, int arg0, int arg2,
+void Mir2Lir::CallRuntimeHelperImmImmMethod(QuickEntrypointEnum trampoline, int arg0, int arg1,
                                             bool safepoint_pc) {
   RegStorage r_tgt = CallHelperSetup(trampoline);
-  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
-  LoadConstant(TargetReg(kArg2, kNotWide), arg2);
+  LoadCurrMethodDirect(TargetReg(kArg2, kRef));
+  LoadConstant(TargetReg(kArg1, kNotWide), arg1);
   LoadConstant(TargetReg(kArg0, kNotWide), arg0);
   ClobberCallerSave();
   CallHelper(r_tgt, trampoline, safepoint_pc);
@@ -365,6 +365,7 @@
  * ArgLocs is an array of location records describing the incoming arguments
  * with one location record per word of argument.
  */
+// TODO: Support 64-bit argument registers.
 void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
   /*
    * Dummy up a RegLocation for the incoming StackReference<mirror::ArtMethod>
@@ -400,59 +401,50 @@
    * half to memory as well.
    */
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-  for (uint32_t i = 0; i < mir_graph_->GetNumOfInVRs(); i++) {
-    PromotionMap* v_map = &promotion_map_[start_vreg + i];
+  RegLocation* t_loc = nullptr;
+  for (uint32_t i = 0; i < mir_graph_->GetNumOfInVRs(); i += t_loc->wide ? 2 : 1) {
+    // get reg corresponding to input
     RegStorage reg = GetArgMappingToPhysicalReg(i);
+    t_loc = &ArgLocs[i];
+
+    // If the wide input appeared as single, flush it and go
+    // as it comes from memory.
+    if (t_loc->wide && reg.Valid() && !reg.Is64Bit()) {
+      // The memory already holds the half. Don't do anything.
+      reg = RegStorage::InvalidReg();
+    }
 
     if (reg.Valid()) {
-      // If arriving in register
-      bool need_flush = true;
-      RegLocation* t_loc = &ArgLocs[i];
-      if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
-        OpRegCopy(RegStorage::Solo32(v_map->core_reg), reg);
-        need_flush = false;
-      } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
-        OpRegCopy(RegStorage::Solo32(v_map->fp_reg), reg);
-        need_flush = false;
-      } else {
-        need_flush = true;
-      }
+      // If arriving in register.
 
-      // For wide args, force flush if not fully promoted
-      if (t_loc->wide) {
-        PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
-        // Is only half promoted?
-        need_flush |= (p_map->core_location != v_map->core_location) ||
-            (p_map->fp_location != v_map->fp_location);
-        if ((cu_->instruction_set == kThumb2) && t_loc->fp && !need_flush) {
-          /*
-           * In Arm, a double is represented as a pair of consecutive single float
-           * registers starting at an even number.  It's possible that both Dalvik vRegs
-           * representing the incoming double were independently promoted as singles - but
-           * not in a form usable as a double.  If so, we need to flush - even though the
-           * incoming arg appears fully in register.  At this point in the code, both
-           * halves of the double are promoted.  Make sure they are in a usable form.
-           */
-          int lowreg_index = start_vreg + i + (t_loc->high_word ? -1 : 0);
-          int low_reg = promotion_map_[lowreg_index].fp_reg;
-          int high_reg = promotion_map_[lowreg_index + 1].fp_reg;
-          if (((low_reg & 0x1) != 0) || (high_reg != (low_reg + 1))) {
-            need_flush = true;
-          }
+      // We have already updated the arg location with promoted info
+      // so we can be based on it.
+      if (t_loc->location == kLocPhysReg) {
+        // Just copy it.
+        if (t_loc->wide) {
+          OpRegCopyWide(t_loc->reg, reg);
+        } else {
+          OpRegCopy(t_loc->reg, reg);
+        }
+      } else {
+        // Needs flush.
+        int offset = SRegOffset(start_vreg + i);
+        if (t_loc->ref) {
+          StoreRefDisp(TargetPtrReg(kSp), offset, reg, kNotVolatile);
+        } else {
+          StoreBaseDisp(TargetPtrReg(kSp), offset, reg, t_loc->wide ? k64 : k32, kNotVolatile);
         }
       }
-      if (need_flush) {
-        Store32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg);
-      }
     } else {
-      // If arriving in frame & promoted
-      if (v_map->core_location == kLocPhysReg) {
-        Load32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i),
-                   RegStorage::Solo32(v_map->core_reg));
-      }
-      if (v_map->fp_location == kLocPhysReg) {
-        Load32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i),
-                   RegStorage::Solo32(v_map->fp_reg));
+      // If arriving in frame & promoted.
+      if (t_loc->location == kLocPhysReg) {
+        int offset = SRegOffset(start_vreg + i);
+        if (t_loc->ref) {
+          LoadRefDisp(TargetPtrReg(kSp), offset, t_loc->reg, kNotVolatile);
+        } else {
+          LoadBaseDisp(TargetPtrReg(kSp), offset, t_loc->reg, t_loc->wide ? k64 : k32,
+                       kNotVolatile);
+        }
       }
     }
   }
@@ -472,13 +464,13 @@
   cg->MarkPossibleNullPointerException(info->opt_flags);
 }
 
-static bool CommonCallCodeLoadCodePointerIntoInvokeTgt(const CallInfo* info,
-                                                       const RegStorage* alt_from,
+static bool CommonCallCodeLoadCodePointerIntoInvokeTgt(const RegStorage* alt_from,
                                                        const CompilationUnit* cu, Mir2Lir* cg) {
   if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
+    int32_t offset = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+        InstructionSetPointerSize(cu->instruction_set)).Int32Value();
     // Get the compiled code address [use *alt_from or kArg0, set kInvokeTgt]
-    cg->LoadWordDisp(alt_from == nullptr ? cg->TargetReg(kArg0, kRef) : *alt_from,
-                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
+    cg->LoadWordDisp(alt_from == nullptr ? cg->TargetReg(kArg0, kRef) : *alt_from, offset,
                      cg->TargetPtrReg(kInvokeTgt));
     return true;
   }
@@ -487,89 +479,16 @@
 
 /*
  * Bit of a hack here - in the absence of a real scheduling pass,
- * emit the next instruction in static & direct invoke sequences.
- */
-static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
-                          int state, const MethodReference& target_method,
-                          uint32_t unused,
-                          uintptr_t direct_code, uintptr_t direct_method,
-                          InvokeType type) {
-  DCHECK(cu->instruction_set != kX86 && cu->instruction_set != kX86_64 &&
-         cu->instruction_set != kThumb2 && cu->instruction_set != kArm);
-  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
-  if (direct_code != 0 && direct_method != 0) {
-    switch (state) {
-    case 0:  // Get the current Method* [sets kArg0]
-      if (direct_code != static_cast<uintptr_t>(-1)) {
-        cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
-      } else {
-        cg->LoadCodeAddress(target_method, type, kInvokeTgt);
-      }
-      if (direct_method != static_cast<uintptr_t>(-1)) {
-        cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method);
-      } else {
-        cg->LoadMethodAddress(target_method, type, kArg0);
-      }
-      break;
-    default:
-      return -1;
-    }
-  } else {
-    RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
-    switch (state) {
-    case 0:  // Get the current Method* [sets kArg0]
-      // TUNING: we can save a reg copy if Method* has been promoted.
-      cg->LoadCurrMethodDirect(arg0_ref);
-      break;
-    case 1:  // Get method->dex_cache_resolved_methods_
-      cg->LoadRefDisp(arg0_ref,
-                      mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
-                      arg0_ref,
-                      kNotVolatile);
-      // Set up direct code if known.
-      if (direct_code != 0) {
-        if (direct_code != static_cast<uintptr_t>(-1)) {
-          cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
-        } else {
-          CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
-          cg->LoadCodeAddress(target_method, type, kInvokeTgt);
-        }
-      }
-      break;
-    case 2:  // Grab target method*
-      CHECK_EQ(cu->dex_file, target_method.dex_file);
-      cg->LoadRefDisp(arg0_ref,
-                      ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(),
-                      arg0_ref,
-                      kNotVolatile);
-      break;
-    case 3:  // Grab the code from the method*
-      if (direct_code == 0) {
-        if (CommonCallCodeLoadCodePointerIntoInvokeTgt(info, &arg0_ref, cu, cg)) {
-          break;                                    // kInvokeTgt := arg0_ref->entrypoint
-        }
-      } else {
-        break;
-      }
-      // Intentional fallthrough for x86
-    default:
-      return -1;
-    }
-  }
-  return state + 1;
-}
-
-/*
- * Bit of a hack here - in the absence of a real scheduling pass,
  * emit the next instruction in a virtual invoke sequence.
  * We can use kLr as a temp prior to target address loading
  * Note also that we'll load the first argument ("this") into
- * kArg1 here rather than the standard LoadArgRegs.
+ * kArg1 here rather than the standard GenDalvikArgs.
  */
 static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
                          int state, const MethodReference& target_method,
-                         uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
-                         InvokeType unused3) {
+                         uint32_t method_idx, uintptr_t, uintptr_t,
+                         InvokeType) {
+  UNUSED(target_method);
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
    * This is the fast path in which the target virtual method is
@@ -592,10 +511,11 @@
       break;
     }
     case 3:
-      if (CommonCallCodeLoadCodePointerIntoInvokeTgt(info, nullptr, cu, cg)) {
+      if (CommonCallCodeLoadCodePointerIntoInvokeTgt(nullptr, cu, cg)) {
         break;                                    // kInvokeTgt := kArg0->entrypoint
       }
-      // Intentional fallthrough for X86
+      DCHECK(cu->instruction_set == kX86 || cu->instruction_set == kX86_64);
+      FALLTHROUGH_INTENDED;
     default:
       return -1;
   }
@@ -606,12 +526,11 @@
  * Emit the next instruction in an invoke interface sequence. This will do a lookup in the
  * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if
  * more than one interface method map to the same index. Note also that we'll load the first
- * argument ("this") into kArg1 here rather than the standard LoadArgRegs.
+ * argument ("this") into kArg1 here rather than the standard GenDalvikArgs.
  */
 static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
                                  const MethodReference& target_method,
-                                 uint32_t method_idx, uintptr_t unused,
-                                 uintptr_t direct_method, InvokeType unused2) {
+                                 uint32_t method_idx, uintptr_t, uintptr_t, InvokeType) {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
 
   switch (state) {
@@ -637,10 +556,11 @@
       break;
     }
     case 4:
-      if (CommonCallCodeLoadCodePointerIntoInvokeTgt(info, nullptr, cu, cg)) {
+      if (CommonCallCodeLoadCodePointerIntoInvokeTgt(nullptr, cu, cg)) {
         break;                                    // kInvokeTgt := kArg0->entrypoint
       }
-      // Intentional fallthrough for X86
+      DCHECK(cu->instruction_set == kX86 || cu->instruction_set == kX86_64);
+      FALLTHROUGH_INTENDED;
     default:
       return -1;
   }
@@ -650,9 +570,9 @@
 static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info,
                             QuickEntrypointEnum trampoline, int state,
                             const MethodReference& target_method, uint32_t method_idx) {
+  UNUSED(info, method_idx);
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
 
-
   /*
    * This handles the case in which the base method is not fully
    * resolved at compile time, we bail to a runtime helper.
@@ -679,32 +599,28 @@
 static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
                                 int state,
                                 const MethodReference& target_method,
-                                uint32_t unused, uintptr_t unused2,
-                                uintptr_t unused3, InvokeType unused4) {
+                                uint32_t, uintptr_t, uintptr_t, InvokeType) {
   return NextInvokeInsnSP(cu, info, kQuickInvokeStaticTrampolineWithAccessCheck, state,
                           target_method, 0);
 }
 
 static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
                                 const MethodReference& target_method,
-                                uint32_t unused, uintptr_t unused2,
-                                uintptr_t unused3, InvokeType unused4) {
+                                uint32_t, uintptr_t, uintptr_t, InvokeType) {
   return NextInvokeInsnSP(cu, info, kQuickInvokeDirectTrampolineWithAccessCheck, state,
                           target_method, 0);
 }
 
 static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
                                const MethodReference& target_method,
-                               uint32_t unused, uintptr_t unused2,
-                               uintptr_t unused3, InvokeType unused4) {
+                               uint32_t, uintptr_t, uintptr_t, InvokeType) {
   return NextInvokeInsnSP(cu, info, kQuickInvokeSuperTrampolineWithAccessCheck, state,
                           target_method, 0);
 }
 
 static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
                            const MethodReference& target_method,
-                           uint32_t unused, uintptr_t unused2,
-                           uintptr_t unused3, InvokeType unused4) {
+                           uint32_t, uintptr_t, uintptr_t, InvokeType) {
   return NextInvokeInsnSP(cu, info, kQuickInvokeVirtualTrampolineWithAccessCheck, state,
                           target_method, 0);
 }
@@ -712,164 +628,11 @@
 static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
                                                 CallInfo* info, int state,
                                                 const MethodReference& target_method,
-                                                uint32_t unused, uintptr_t unused2,
-                                                uintptr_t unused3, InvokeType unused4) {
+                                                uint32_t, uintptr_t, uintptr_t, InvokeType) {
   return NextInvokeInsnSP(cu, info, kQuickInvokeInterfaceTrampolineWithAccessCheck, state,
                           target_method, 0);
 }
 
-int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
-                         NextCallInsn next_call_insn,
-                         const MethodReference& target_method,
-                         uint32_t vtable_idx, uintptr_t direct_code,
-                         uintptr_t direct_method, InvokeType type, bool skip_this) {
-  int last_arg_reg = 3 - 1;
-  int arg_regs[3] = {TargetReg(kArg1, kNotWide).GetReg(), TargetReg(kArg2, kNotWide).GetReg(),
-                     TargetReg(kArg3, kNotWide).GetReg()};
-
-  int next_reg = 0;
-  int next_arg = 0;
-  if (skip_this) {
-    next_reg++;
-    next_arg++;
-  }
-  for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
-    RegLocation rl_arg = info->args[next_arg++];
-    rl_arg = UpdateRawLoc(rl_arg);
-    if (rl_arg.wide && (next_reg <= last_arg_reg - 1)) {
-      RegStorage r_tmp(RegStorage::k64BitPair, arg_regs[next_reg], arg_regs[next_reg + 1]);
-      LoadValueDirectWideFixed(rl_arg, r_tmp);
-      next_reg++;
-      next_arg++;
-    } else {
-      if (rl_arg.wide) {
-        rl_arg = NarrowRegLoc(rl_arg);
-        rl_arg.is_const = false;
-      }
-      LoadValueDirectFixed(rl_arg, RegStorage::Solo32(arg_regs[next_reg]));
-    }
-    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                                direct_code, direct_method, type);
-  }
-  return call_state;
-}
-
-/*
- * Load up to 5 arguments, the first three of which will be in
- * kArg1 .. kArg3.  On entry kArg0 contains the current method pointer,
- * and as part of the load sequence, it must be replaced with
- * the target method pointer.  Note, this may also be called
- * for "range" variants if the number of arguments is 5 or fewer.
- */
-int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
-                                  int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                  const MethodReference& target_method,
-                                  uint32_t vtable_idx, uintptr_t direct_code,
-                                  uintptr_t direct_method, InvokeType type, bool skip_this) {
-  RegLocation rl_arg;
-
-  /* If no arguments, just return */
-  if (info->num_arg_words == 0)
-    return call_state;
-
-  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                              direct_code, direct_method, type);
-
-  DCHECK_LE(info->num_arg_words, 5);
-  if (info->num_arg_words > 3) {
-    int32_t next_use = 3;
-    // Detect special case of wide arg spanning arg3/arg4
-    RegLocation rl_use0 = info->args[0];
-    RegLocation rl_use1 = info->args[1];
-    RegLocation rl_use2 = info->args[2];
-    if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) && rl_use2.wide) {
-      RegStorage reg;
-      // Wide spans, we need the 2nd half of uses[2].
-      rl_arg = UpdateLocWide(rl_use2);
-      if (rl_arg.location == kLocPhysReg) {
-        if (rl_arg.reg.IsPair()) {
-          reg = rl_arg.reg.GetHigh();
-        } else {
-          RegisterInfo* info = GetRegInfo(rl_arg.reg);
-          info = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask);
-          if (info == nullptr) {
-            // NOTE: For hard float convention we won't split arguments across reg/mem.
-            UNIMPLEMENTED(FATAL) << "Needs hard float api.";
-          }
-          reg = info->GetReg();
-        }
-      } else {
-        // kArg2 & rArg3 can safely be used here
-        reg = TargetReg(kArg3, kNotWide);
-        {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
-        }
-        call_state = next_call_insn(cu_, info, call_state, target_method,
-                                    vtable_idx, direct_code, direct_method, type);
-      }
-      {
-        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        Store32Disp(TargetPtrReg(kSp), (next_use + 1) * 4, reg);
-      }
-      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                                  direct_code, direct_method, type);
-      next_use++;
-    }
-    // Loop through the rest
-    while (next_use < info->num_arg_words) {
-      RegStorage arg_reg;
-      rl_arg = info->args[next_use];
-      rl_arg = UpdateRawLoc(rl_arg);
-      if (rl_arg.location == kLocPhysReg) {
-        arg_reg = rl_arg.reg;
-      } else {
-        arg_reg = TargetReg(kArg2, rl_arg.wide ? kWide : kNotWide);
-        if (rl_arg.wide) {
-          LoadValueDirectWideFixed(rl_arg, arg_reg);
-        } else {
-          LoadValueDirectFixed(rl_arg, arg_reg);
-        }
-        call_state = next_call_insn(cu_, info, call_state, target_method,
-                                    vtable_idx, direct_code, direct_method, type);
-      }
-      int outs_offset = (next_use + 1) * 4;
-      {
-        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        if (rl_arg.wide) {
-          StoreBaseDisp(TargetPtrReg(kSp), outs_offset, arg_reg, k64, kNotVolatile);
-          next_use += 2;
-        } else {
-          Store32Disp(TargetPtrReg(kSp), outs_offset, arg_reg);
-          next_use++;
-        }
-      }
-      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                               direct_code, direct_method, type);
-    }
-  }
-
-  call_state = LoadArgRegs(info, call_state, next_call_insn,
-                           target_method, vtable_idx, direct_code, direct_method,
-                           type, skip_this);
-
-  if (pcrLabel) {
-    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
-      *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
-    } else {
-      *pcrLabel = nullptr;
-      if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
-          (info->opt_flags & MIR_IGNORE_NULL_CHECK)) {
-        return call_state;
-      }
-      // In lieu of generating a check for kArg1 being null, we need to
-      // perform a load when doing implicit checks.
-      GenImplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
-    }
-  }
-  return call_state;
-}
-
 // Default implementation of implicit null pointer check.
 // Overridden by arch specific as necessary.
 void Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
@@ -882,209 +645,196 @@
   FreeTemp(tmp);
 }
 
-
-/*
- * May have 0+ arguments (also used for jumbo).  Note that
- * source virtual registers may be in physical registers, so may
- * need to be flushed to home location before copying.  This
- * applies to arg3 and above (see below).
- *
- * Two general strategies:
- *    If < 20 arguments
- *       Pass args 3-18 using vldm/vstm block copy
- *       Pass arg0, arg1 & arg2 in kArg1-kArg3
- *    If 20+ arguments
- *       Pass args arg19+ using memcpy block copy
- *       Pass arg0, arg1 & arg2 in kArg1-kArg3
- *
+/**
+ * @brief Used to flush promoted registers if they are used as argument
+ * in an invocation.
+ * @param info the infromation about arguments for invocation.
+ * @param start the first argument we should start to look from.
  */
-int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
-                                LIR** pcrLabel, NextCallInsn next_call_insn,
-                                const MethodReference& target_method,
-                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
-                                InvokeType type, bool skip_this) {
-  // If we can treat it as non-range (Jumbo ops will use range form)
-  if (info->num_arg_words <= 5)
-    return GenDalvikArgsNoRange(info, call_state, pcrLabel,
-                                next_call_insn, target_method, vtable_idx,
-                                direct_code, direct_method, type, skip_this);
-  /*
-   * First load the non-register arguments.  Both forms expect all
-   * of the source arguments to be in their home frame location, so
-   * scan the s_reg names and flush any that have been promoted to
-   * frame backing storage.
-   */
+void Mir2Lir::GenDalvikArgsFlushPromoted(CallInfo* info, int start) {
+  if (cu_->disable_opt & (1 << kPromoteRegs)) {
+    // This make sense only if promotion is enabled.
+    return;
+  }
+  ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
   // Scan the rest of the args - if in phys_reg flush to memory
-  for (int next_arg = 0; next_arg < info->num_arg_words;) {
+  for (int next_arg = start; next_arg < info->num_arg_words;) {
     RegLocation loc = info->args[next_arg];
     if (loc.wide) {
       loc = UpdateLocWide(loc);
-      if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
-        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+      if (loc.location == kLocPhysReg) {
         StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
       }
       next_arg += 2;
     } else {
       loc = UpdateLoc(loc);
-      if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
-        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        Store32Disp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg);
+      if (loc.location == kLocPhysReg) {
+        if (loc.ref) {
+          StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile);
+        } else {
+          StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32,
+                        kNotVolatile);
+        }
       }
       next_arg++;
     }
   }
+}
 
-  // The first 3 arguments are passed via registers.
-  // TODO: For 64-bit, instead of hardcoding 4 for Method* size, we should either
-  // get size of uintptr_t or size of object reference according to model being used.
-  int outs_offset = 4 /* Method* */ + (3 * sizeof(uint32_t));
-  int start_offset = SRegOffset(info->args[3].s_reg_low);
-  int regs_left_to_pass_via_stack = info->num_arg_words - 3;
-  DCHECK_GT(regs_left_to_pass_via_stack, 0);
+/**
+ * @brief Used to optimize the copying of VRs which are arguments of invocation.
+ * Please note that you should flush promoted registers first if you copy.
+ * If implementation does copying it may skip several of the first VRs but must copy
+ * till the end. Implementation must return the number of skipped VRs
+ * (it might be all VRs).
+ * @see GenDalvikArgsFlushPromoted
+ * @param info the information about arguments for invocation.
+ * @param first the first argument we should start to look from.
+ * @param count the number of remaining arguments we can handle.
+ * @return the number of arguments which we did not handle. Unhandled arguments
+ * must be attached to the first one.
+ */
+int Mir2Lir::GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) {
+  // call is pretty expensive, let's use it if count is big.
+  if (count > 16) {
+    GenDalvikArgsFlushPromoted(info, first);
+    int start_offset = SRegOffset(info->args[first].s_reg_low);
+    int outs_offset = StackVisitor::GetOutVROffset(first, cu_->instruction_set);
 
-  if (cu_->instruction_set == kThumb2 && regs_left_to_pass_via_stack <= 16) {
-    // Use vldm/vstm pair using kArg3 as a temp
-    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                             direct_code, direct_method, type);
-    OpRegRegImm(kOpAdd, TargetReg(kArg3, kRef), TargetPtrReg(kSp), start_offset);
-    LIR* ld = nullptr;
-    {
-      ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-      ld = OpVldm(TargetReg(kArg3, kRef), regs_left_to_pass_via_stack);
-    }
-    // TUNING: loosen barrier
-    ld->u.m.def_mask = &kEncodeAll;
-    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                             direct_code, direct_method, type);
-    OpRegRegImm(kOpAdd, TargetReg(kArg3, kRef), TargetPtrReg(kSp), 4 /* Method* */ + (3 * 4));
-    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                             direct_code, direct_method, type);
-    LIR* st = nullptr;
-    {
-      ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-      st = OpVstm(TargetReg(kArg3, kRef), regs_left_to_pass_via_stack);
-    }
-    st->u.m.def_mask = &kEncodeAll;
-    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                             direct_code, direct_method, type);
-  } else if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
-    int current_src_offset = start_offset;
-    int current_dest_offset = outs_offset;
-
-    // Only davik regs are accessed in this loop; no next_call_insn() calls.
-    ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    while (regs_left_to_pass_via_stack > 0) {
-      // This is based on the knowledge that the stack itself is 16-byte aligned.
-      bool src_is_16b_aligned = (current_src_offset & 0xF) == 0;
-      bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0;
-      size_t bytes_to_move;
-
-      /*
-       * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a
-       * a 128-bit move because we won't get the chance to try to aligned. If there are more than
-       * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned.
-       * We do this because we could potentially do a smaller move to align.
-       */
-      if (regs_left_to_pass_via_stack == 4 ||
-          (regs_left_to_pass_via_stack > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) {
-        // Moving 128-bits via xmm register.
-        bytes_to_move = sizeof(uint32_t) * 4;
-
-        // Allocate a free xmm temp. Since we are working through the calling sequence,
-        // we expect to have an xmm temporary available.  AllocTempDouble will abort if
-        // there are no free registers.
-        RegStorage temp = AllocTempDouble();
-
-        LIR* ld1 = nullptr;
-        LIR* ld2 = nullptr;
-        LIR* st1 = nullptr;
-        LIR* st2 = nullptr;
-
-        /*
-         * The logic is similar for both loads and stores. If we have 16-byte alignment,
-         * do an aligned move. If we have 8-byte alignment, then do the move in two
-         * parts. This approach prevents possible cache line splits. Finally, fall back
-         * to doing an unaligned move. In most cases we likely won't split the cache
-         * line but we cannot prove it and thus take a conservative approach.
-         */
-        bool src_is_8b_aligned = (current_src_offset & 0x7) == 0;
-        bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0;
-
-        if (src_is_16b_aligned) {
-          ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovA128FP);
-        } else if (src_is_8b_aligned) {
-          ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovLo128FP);
-          ld2 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset + (bytes_to_move >> 1),
-                            kMovHi128FP);
-        } else {
-          ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovU128FP);
-        }
-
-        if (dest_is_16b_aligned) {
-          st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovA128FP);
-        } else if (dest_is_8b_aligned) {
-          st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovLo128FP);
-          st2 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset + (bytes_to_move >> 1),
-                            temp, kMovHi128FP);
-        } else {
-          st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovU128FP);
-        }
-
-        // TODO If we could keep track of aliasing information for memory accesses that are wider
-        // than 64-bit, we wouldn't need to set up a barrier.
-        if (ld1 != nullptr) {
-          if (ld2 != nullptr) {
-            // For 64-bit load we can actually set up the aliasing information.
-            AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true);
-            AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true,
-                                    true);
-          } else {
-            // Set barrier for 128-bit load.
-            ld1->u.m.def_mask = &kEncodeAll;
-          }
-        }
-        if (st1 != nullptr) {
-          if (st2 != nullptr) {
-            // For 64-bit store we can actually set up the aliasing information.
-            AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true);
-            AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false,
-                                    true);
-          } else {
-            // Set barrier for 128-bit store.
-            st1->u.m.def_mask = &kEncodeAll;
-          }
-        }
-
-        // Free the temporary used for the data movement.
-        FreeTemp(temp);
-      } else {
-        // Moving 32-bits via general purpose register.
-        bytes_to_move = sizeof(uint32_t);
-
-        // Instead of allocating a new temp, simply reuse one of the registers being used
-        // for argument passing.
-        RegStorage temp = TargetReg(kArg3, kNotWide);
-
-        // Now load the argument VR and store to the outs.
-        Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
-        Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
-      }
-
-      current_src_offset += bytes_to_move;
-      current_dest_offset += bytes_to_move;
-      regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
-    }
-  } else {
-    // Generate memcpy
     OpRegRegImm(kOpAdd, TargetReg(kArg0, kRef), TargetPtrReg(kSp), outs_offset);
     OpRegRegImm(kOpAdd, TargetReg(kArg1, kRef), TargetPtrReg(kSp), start_offset);
     CallRuntimeHelperRegRegImm(kQuickMemcpy, TargetReg(kArg0, kRef), TargetReg(kArg1, kRef),
-                               (info->num_arg_words - 3) * 4, false);
+                               count * 4, false);
+    count = 0;
+  }
+  return count;
+}
+
+int Mir2Lir::GenDalvikArgs(CallInfo* info, int call_state,
+                           LIR** pcrLabel, NextCallInsn next_call_insn,
+                           const MethodReference& target_method,
+                           uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
+                           InvokeType type, bool skip_this) {
+  // If no arguments, just return.
+  if (info->num_arg_words == 0)
+    return call_state;
+
+  const int start_index = skip_this ? 1 : 0;
+
+  // Get architecture dependent mapping between output VRs and physical registers
+  // basing on shorty of method to call.
+  InToRegStorageMapping in_to_reg_storage_mapping(arena_);
+  {
+    const char* target_shorty = mir_graph_->GetShortyFromMethodReference(target_method);
+    ShortyIterator shorty_iterator(target_shorty, type == kStatic);
+    in_to_reg_storage_mapping.Initialize(&shorty_iterator, GetResetedInToRegStorageMapper());
   }
 
-  call_state = LoadArgRegs(info, call_state, next_call_insn,
-                           target_method, vtable_idx, direct_code, direct_method,
-                           type, skip_this);
+  int stack_map_start = std::max(in_to_reg_storage_mapping.GetMaxMappedIn() + 1, start_index);
+  if ((stack_map_start < info->num_arg_words) && info->args[stack_map_start].high_word) {
+    // It is possible that the last mapped reg is 32 bit while arg is 64-bit.
+    // It will be handled together with low part mapped to register.
+    stack_map_start++;
+  }
+  int regs_left_to_pass_via_stack = info->num_arg_words - stack_map_start;
+
+  // If it is a range case we can try to copy remaining VRs (not mapped to physical registers)
+  // using more optimal algorithm.
+  if (info->is_range && regs_left_to_pass_via_stack > 1) {
+    regs_left_to_pass_via_stack = GenDalvikArgsBulkCopy(info, stack_map_start,
+                                                        regs_left_to_pass_via_stack);
+  }
+
+  // Now handle any remaining VRs mapped to stack.
+  if (in_to_reg_storage_mapping.HasArgumentsOnStack()) {
+    // Two temps but do not use kArg1, it might be this which we can skip.
+    // Separate single and wide - it can give some advantage.
+    RegStorage regRef = TargetReg(kArg3, kRef);
+    RegStorage regSingle = TargetReg(kArg3, kNotWide);
+    RegStorage regWide = TargetReg(kArg2, kWide);
+    for (int i = start_index;
+         i < stack_map_start + regs_left_to_pass_via_stack; i++) {
+      RegLocation rl_arg = info->args[i];
+      rl_arg = UpdateRawLoc(rl_arg);
+      RegStorage reg = in_to_reg_storage_mapping.Get(i);
+      if (!reg.Valid()) {
+        int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
+        {
+          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+          if (rl_arg.wide) {
+            if (rl_arg.location == kLocPhysReg) {
+              StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
+            } else {
+              LoadValueDirectWideFixed(rl_arg, regWide);
+              StoreBaseDisp(TargetPtrReg(kSp), out_offset, regWide, k64, kNotVolatile);
+            }
+          } else {
+            if (rl_arg.location == kLocPhysReg) {
+              if (rl_arg.ref) {
+                StoreRefDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, kNotVolatile);
+              } else {
+                StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
+              }
+            } else {
+              if (rl_arg.ref) {
+                LoadValueDirectFixed(rl_arg, regRef);
+                StoreRefDisp(TargetPtrReg(kSp), out_offset, regRef, kNotVolatile);
+              } else {
+                LoadValueDirectFixed(rl_arg, regSingle);
+                StoreBaseDisp(TargetPtrReg(kSp), out_offset, regSingle, k32, kNotVolatile);
+              }
+            }
+          }
+        }
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
+      }
+      if (rl_arg.wide) {
+        i++;
+      }
+    }
+  }
+
+  // Finish with VRs mapped to physical registers.
+  for (int i = start_index; i < stack_map_start; i++) {
+    RegLocation rl_arg = info->args[i];
+    rl_arg = UpdateRawLoc(rl_arg);
+    RegStorage reg = in_to_reg_storage_mapping.Get(i);
+    if (reg.Valid()) {
+      if (rl_arg.wide) {
+        // if reg is not 64-bit (it is half of 64-bit) then handle it separately.
+        if (!reg.Is64Bit()) {
+          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+          if (rl_arg.location == kLocPhysReg) {
+            int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
+            // Dump it to memory.
+            StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
+            LoadBaseDisp(TargetPtrReg(kSp), out_offset, reg, k32, kNotVolatile);
+          } else {
+            int high_offset = StackVisitor::GetOutVROffset(i + 1, cu_->instruction_set);
+            // First, use target reg for high part.
+            LoadBaseDisp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low + 1), reg, k32,
+                         kNotVolatile);
+            StoreBaseDisp(TargetPtrReg(kSp), high_offset, reg, k32, kNotVolatile);
+            // Now, use target reg for low part.
+            LoadBaseDisp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low), reg, k32, kNotVolatile);
+            int low_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
+            // And store it to the expected memory location.
+            StoreBaseDisp(TargetPtrReg(kSp), low_offset, reg, k32, kNotVolatile);
+          }
+        } else {
+          LoadValueDirectWideFixed(rl_arg, reg);
+        }
+      } else {
+        LoadValueDirectFixed(rl_arg, reg);
+      }
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                               direct_code, direct_method, type);
+    }
+    if (rl_arg.wide) {
+      i++;
+    }
+  }
 
   call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                            direct_code, direct_method, type);
@@ -1093,18 +843,20 @@
       *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
     } else {
       *pcrLabel = nullptr;
-      if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
-          (info->opt_flags & MIR_IGNORE_NULL_CHECK)) {
-        return call_state;
-      }
-      // In lieu of generating a check for kArg1 being null, we need to
-      // perform a load when doing implicit checks.
       GenImplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
     }
   }
   return call_state;
 }
 
+RegStorage Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
+  if (!in_to_reg_storage_mapping_.IsInitialized()) {
+    ShortyIterator shorty_iterator(cu_->shorty, cu_->invoke_type == kStatic);
+    in_to_reg_storage_mapping_.Initialize(&shorty_iterator, GetResetedInToRegStorageMapper());
+  }
+  return in_to_reg_storage_mapping_.Get(arg_num);
+}
+
 RegLocation Mir2Lir::InlineTarget(CallInfo* info) {
   RegLocation res;
   if (info->result.location == kLocInvalid) {
@@ -1166,8 +918,8 @@
 
   RegStorage reg_slow_path = AllocTemp();
   RegStorage reg_disabled = AllocTemp();
-  Load8Disp(reg_class, slow_path_flag_offset, reg_slow_path);
-  Load8Disp(reg_class, disable_flag_offset, reg_disabled);
+  LoadBaseDisp(reg_class, slow_path_flag_offset, reg_slow_path, kSignedByte, kNotVolatile);
+  LoadBaseDisp(reg_class, disable_flag_offset, reg_disabled, kSignedByte, kNotVolatile);
   FreeTemp(reg_class);
   LIR* or_inst = OpRegRegReg(kOpOr, reg_slow_path, reg_slow_path, reg_disabled);
   FreeTemp(reg_disabled);
@@ -1199,10 +951,6 @@
 }
 
 bool Mir2Lir::GenInlinedCharAt(CallInfo* info) {
-  if (cu_->instruction_set == kMips) {
-    // TODO - add Mips implementation
-    return false;
-  }
   // Location of reference to data array
   int value_offset = mirror::String::ValueOffset().Int32Value();
   // Location of count
@@ -1332,10 +1080,6 @@
 }
 
 bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
-  if (cu_->instruction_set == kMips) {
-    // TODO - add Mips implementation
-    return false;
-  }
   RegLocation rl_src = info->args[0];
   rl_src = LoadValue(rl_src, kCoreReg);
   RegLocation rl_dest = InlineTarget(info);
@@ -1350,10 +1094,6 @@
 }
 
 bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
-  if (cu_->instruction_set == kMips) {
-    // TODO - add Mips implementation
-    return false;
-  }
   RegLocation rl_src = info->args[0];
   rl_src = LoadValueWide(rl_src, kCoreReg);
   RegLocation rl_dest = InlineTargetWide(info);
@@ -1395,28 +1135,34 @@
 }
 
 bool Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
-  // Currently implemented only for ARM64
+  // Currently implemented only for ARM64.
+  UNUSED(info, size);
   return false;
 }
 
 bool Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
-  // Currently implemented only for ARM64
+  // Currently implemented only for ARM64.
+  UNUSED(info, is_min, is_double);
   return false;
 }
 
 bool Mir2Lir::GenInlinedCeil(CallInfo* info) {
+  UNUSED(info);
   return false;
 }
 
 bool Mir2Lir::GenInlinedFloor(CallInfo* info) {
+  UNUSED(info);
   return false;
 }
 
 bool Mir2Lir::GenInlinedRint(CallInfo* info) {
+  UNUSED(info);
   return false;
 }
 
 bool Mir2Lir::GenInlinedRound(CallInfo* info, bool is_double) {
+  UNUSED(info, is_double);
   return false;
 }
 
@@ -1443,6 +1189,7 @@
 }
 
 bool Mir2Lir::GenInlinedArrayCopyCharArray(CallInfo* info) {
+  UNUSED(info);
   return false;
 }
 
@@ -1452,14 +1199,6 @@
  * otherwise bails to standard library code.
  */
 bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
-  if (cu_->instruction_set == kMips) {
-    // TODO - add Mips implementation
-    return false;
-  }
-  if (cu_->instruction_set == kX86_64) {
-    // TODO - add kX86_64 implementation
-    return false;
-  }
   RegLocation rl_obj = info->args[0];
   RegLocation rl_char = info->args[1];
   if (rl_char.is_const && (mir_graph_->ConstantValue(rl_char) & ~0xFFFF) != 0) {
@@ -1548,23 +1287,13 @@
 
   RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
 
-  switch (cu_->instruction_set) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      // Fall-through.
-    case kMips:
-      Load32Disp(TargetPtrReg(kSelf), Thread::PeerOffset<4>().Int32Value(), rl_result.reg);
-      break;
-
-    case kArm64:
-      LoadRefDisp(TargetPtrReg(kSelf), Thread::PeerOffset<8>().Int32Value(), rl_result.reg,
-                  kNotVolatile);
-      break;
-
-    default:
-      LOG(FATAL) << "Unexpected isa " << cu_->instruction_set;
+  if (Is64BitInstructionSet(cu_->instruction_set)) {
+    LoadRefDisp(TargetPtrReg(kSelf), Thread::PeerOffset<8>().Int32Value(), rl_result.reg,
+                kNotVolatile);
+  } else {
+    Load32Disp(TargetPtrReg(kSelf), Thread::PeerOffset<4>().Int32Value(), rl_result.reg);
   }
+
   StoreValue(rl_dest, rl_result);
   return true;
 }
@@ -1643,7 +1372,7 @@
       FreeTemp(rl_temp_offset);
     }
   } else {
-    rl_value = LoadValue(rl_src_value);
+    rl_value = LoadValue(rl_src_value, LocToRegClass(rl_src_value));
     if (rl_value.ref) {
       StoreRefIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0);
     } else {
@@ -1660,7 +1389,7 @@
     GenMemBarrier(kAnyAny);
   }
   if (is_object) {
-    MarkGCCard(rl_value.reg, rl_object.reg);
+    MarkGCCard(0, rl_value.reg, rl_object.reg);
   }
   return true;
 }
@@ -1685,7 +1414,6 @@
 
   const MirMethodLoweringInfo& method_info = mir_graph_->GetMethodLoweringInfo(info->mir);
   cu_->compiler_driver->ProcessedInvoke(method_info.GetInvokeType(), method_info.StatsFlags());
-  BeginInvoke(info);
   InvokeType original_type = static_cast<InvokeType>(method_info.GetInvokeType());
   info->type = method_info.GetSharpType();
   bool fast_path = method_info.FastPath();
@@ -1712,27 +1440,19 @@
     skip_this = fast_path;
   }
   MethodReference target_method = method_info.GetTargetMethod();
-  if (!info->is_range) {
-    call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
-                                      next_call_insn, target_method, method_info.VTableIndex(),
-                                      method_info.DirectCode(), method_info.DirectMethod(),
-                                      original_type, skip_this);
-  } else {
-    call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
-                                    next_call_insn, target_method, method_info.VTableIndex(),
-                                    method_info.DirectCode(), method_info.DirectMethod(),
-                                    original_type, skip_this);
-  }
+  call_state = GenDalvikArgs(info, call_state, p_null_ck,
+                             next_call_insn, target_method, method_info.VTableIndex(),
+                             method_info.DirectCode(), method_info.DirectMethod(),
+                             original_type, skip_this);
   // Finish up any of the call sequence not interleaved in arg loading
   while (call_state >= 0) {
     call_state = next_call_insn(cu_, info, call_state, target_method, method_info.VTableIndex(),
                                 method_info.DirectCode(), method_info.DirectMethod(), original_type);
   }
   LIR* call_insn = GenCallInsn(method_info);
-  EndInvoke(info);
   MarkSafepointPC(call_insn);
 
-  ClobberCallerSave();
+  FreeCallTemps();
   if (info->result.location != kLocInvalid) {
     // We have a following MOVE_RESULT - do it now.
     if (info->result.wide) {
@@ -1745,14 +1465,4 @@
   }
 }
 
-NextCallInsn Mir2Lir::GetNextSDCallInsn() {
-  return NextSDCallInsn;
-}
-
-LIR* Mir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info) {
-  DCHECK(cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64 &&
-         cu_->instruction_set != kThumb2 && cu_->instruction_set != kArm);
-  return OpReg(kOpBlx, TargetPtrReg(kInvokeTgt));
-}
-
 }  // namespace art
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index e5798fd..d314601 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -149,8 +149,9 @@
       // Wrong register class, realloc, copy and transfer ownership.
       RegStorage new_reg = AllocTypedTemp(rl_src.fp, op_kind);
       OpRegCopy(new_reg, rl_src.reg);
-      // Clobber the old reg.
+      // Clobber the old regs and free it.
       Clobber(rl_src.reg);
+      FreeTemp(rl_src.reg);
       // ...and mark the new one live.
       rl_src.reg = new_reg;
       MarkLive(rl_src);
@@ -166,10 +167,6 @@
   return rl_src;
 }
 
-RegLocation Mir2Lir::LoadValue(RegLocation rl_src) {
-  return LoadValue(rl_src, LocToRegClass(rl_src));
-}
-
 void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) {
   /*
    * Sanity checking - should never try to store to the same
@@ -236,8 +233,9 @@
       // Wrong register class, realloc, copy and transfer ownership.
       RegStorage new_regs = AllocTypedTempWide(rl_src.fp, op_kind);
       OpRegCopyWide(new_regs, rl_src.reg);
-      // Clobber the old regs.
+      // Clobber the old regs and free it.
       Clobber(rl_src.reg);
+      FreeTemp(rl_src.reg);
       // ...and mark the new ones live.
       rl_src.reg = new_regs;
       MarkLive(rl_src);
diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc
index c7e9190..4265ae1 100644
--- a/compiler/dex/quick/mips/assemble_mips.cc
+++ b/compiler/dex/quick/mips/assemble_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
@@ -146,12 +147,10 @@
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF_HI | REG_DEF_LO | REG_USE01,
                  "div", "!0r,!1r", 4),
-#if __mips_isa_rev >= 2
     ENCODING_MAP(kMipsExt, 0x7c000000,
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
                  kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
                  "ext", "!0r,!1r,!2d,!3D", 4),
-#endif
     ENCODING_MAP(kMipsJal, 0x0c000000,
                  kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
@@ -240,7 +239,6 @@
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
                  "sb", "!0r,!1d(!2r)", 4),
-#if __mips_isa_rev >= 2
     ENCODING_MAP(kMipsSeb, 0x7c000420,
                  kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
@@ -249,7 +247,6 @@
                  kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "seh", "!0r,!1r", 4),
-#endif
     ENCODING_MAP(kMipsSh, 0xA4000000,
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
@@ -437,7 +434,7 @@
  * anchor:
  *      ori  rAT, rAT, ((target-anchor) & 0xffff)
  *      addu rAT, rAT, rRA
- *      jr   rAT
+ *      jalr rZERO, rAT
  * hop:
  *
  * Orig unconditional branch
@@ -451,7 +448,7 @@
  * anchor:
  *      ori  rAT, rAT, ((target-anchor) & 0xffff)
  *      addu rAT, rAT, rRA
- *      jr   rAT
+ *      jalr rZERO, rAT
  *
  *
  * NOTE: An out-of-range bal isn't supported because it should
@@ -465,6 +462,7 @@
   switch (opcode) {
     case kMipsBal:
       LOG(FATAL) << "long branch and link unsupported";
+      UNREACHABLE();
     case kMipsB:
       unconditional = true;
       break;
@@ -478,12 +476,13 @@
     case kMipsBnez: opcode = kMipsBeqz; break;
     default:
       LOG(FATAL) << "Unexpected branch kind " << opcode;
+      UNREACHABLE();
   }
   LIR* hop_target = NULL;
   if (!unconditional) {
     hop_target = RawLIR(dalvik_offset, kPseudoTargetLabel);
     LIR* hop_branch = RawLIR(dalvik_offset, opcode, lir->operands[0],
-                            lir->operands[1], 0, 0, 0, hop_target);
+                             lir->operands[1], 0, 0, 0, hop_target);
     InsertLIRBefore(lir, hop_branch);
   }
   LIR* curr_pc = RawLIR(dalvik_offset, kMipsCurrPC);
@@ -498,8 +497,8 @@
   InsertLIRBefore(lir, delta_lo);
   LIR* addu = RawLIR(dalvik_offset, kMipsAddu, rAT, rAT, rRA);
   InsertLIRBefore(lir, addu);
-  LIR* jr = RawLIR(dalvik_offset, kMipsJr, rAT);
-  InsertLIRBefore(lir, jr);
+  LIR* jalr = RawLIR(dalvik_offset, kMipsJalr, rZERO, rAT);
+  InsertLIRBefore(lir, jalr);
   if (!unconditional) {
     InsertLIRBefore(lir, hop_target);
   }
@@ -698,12 +697,12 @@
     // TUNING: replace with proper delay slot handling
     if (encoder->size == 8) {
       DCHECK(!IsPseudoLirOp(lir->opcode));
-      const MipsEncodingMap *encoder = &EncodingMap[kMipsNop];
-      uint32_t bits = encoder->skeleton;
-      code_buffer_.push_back(bits & 0xff);
-      code_buffer_.push_back((bits >> 8) & 0xff);
-      code_buffer_.push_back((bits >> 16) & 0xff);
-      code_buffer_.push_back((bits >> 24) & 0xff);
+      const MipsEncodingMap *encoder2 = &EncodingMap[kMipsNop];
+      uint32_t bits2 = encoder2->skeleton;
+      code_buffer_.push_back(bits2 & 0xff);
+      code_buffer_.push_back((bits2 >> 8) & 0xff);
+      code_buffer_.push_back((bits2 >> 16) & 0xff);
+      code_buffer_.push_back((bits2 >> 24) & 0xff);
     }
   }
   return res;
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 6536c41..ed92e82 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -17,16 +17,19 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
 #include "mips_lir.h"
+#include "mirror/art_method.h"
+#include "mirror/object_array-inl.h"
 
 namespace art {
 
-bool MipsMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
-                                 const InlineMethod& special) {
+bool MipsMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special) {
   // TODO
+  UNUSED(bb, mir, special);
   return false;
 }
 
@@ -57,7 +60,7 @@
  *   bne   r_val, r_key, loop
  *   lw    r_disp, -4(r_base)
  *   addu  rRA, r_disp
- *   jr    rRA
+ *   jalr  rZERO, rRA
  * done:
  *
  */
@@ -135,7 +138,7 @@
  *   bound check -> done
  *   lw    r_disp, [rRA, r_val]
  *   addu  rRA, r_disp
- *   jr    rRA
+ *   jalr  rZERO, rRA
  * done:
  */
 void MipsMir2Lir::GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
@@ -210,54 +213,6 @@
   branch_over->target = target;
 }
 
-/*
- * Array data table format:
- *  ushort ident = 0x0300   magic value
- *  ushort width            width of each element in the table
- *  uint   size             number of elements in the table
- *  ubyte  data[size*width] table of data values (may contain a single-byte
- *                          padding at the end)
- *
- * Total size is 4+(width * size + 1)/2 16-bit code units.
- */
-void MipsMir2Lir::GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
-  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
-  // Add the table to the list - we'll process it later
-  FillArrayData* tab_rec =
-      reinterpret_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData),
-                                                     kArenaAllocData));
-  tab_rec->table = table;
-  tab_rec->vaddr = current_dalvik_offset_;
-  uint16_t width = tab_rec->table[1];
-  uint32_t size = tab_rec->table[2] | ((static_cast<uint32_t>(tab_rec->table[3])) << 16);
-  tab_rec->size = (size * width) + 8;
-
-  fill_array_data_.push_back(tab_rec);
-
-  // Making a call - use explicit registers
-  FlushAllRegs();   /* Everything to home location */
-  LockCallTemps();
-  LoadValueDirectFixed(rl_src, rs_rMIPS_ARG0);
-
-  // Must prevent code motion for the curr pc pair
-  GenBarrier();
-  NewLIR0(kMipsCurrPC);  // Really a jal to .+8
-  // Now, fill the branch delay slot with the helper load
-  RegStorage r_tgt = LoadHelper(kQuickHandleFillArrayData);
-  GenBarrier();  // Scheduling barrier
-
-  // Construct BaseLabel and set up table base register
-  LIR* base_label = NewLIR0(kPseudoTargetLabel);
-
-  // Materialize a pointer to the fill data image
-  NewLIR4(kMipsDelta, rMIPS_ARG1, 0, WrapPointer(base_label), WrapPointer(tab_rec));
-
-  // And go...
-  ClobberCallerSave();
-  LIR* call_inst = OpReg(kOpBlx, r_tgt);  // ( array*, fill_data* )
-  MarkSafepointPC(call_inst);
-}
-
 void MipsMir2Lir::GenMoveException(RegLocation rl_dest) {
   int ex_offset = Thread::ExceptionOffset<4>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
@@ -269,19 +224,13 @@
   StoreValue(rl_dest, rl_result);
 }
 
-/*
- * Mark garbage collection card. Skip if the value we're storing is null.
- */
-void MipsMir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void MipsMir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) {
   RegStorage reg_card_base = AllocTemp();
   RegStorage reg_card_no = AllocTemp();
-  LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   // NOTE: native pointer.
   LoadWordDisp(rs_rMIPS_SELF, Thread::CardTableOffset<4>().Int32Value(), reg_card_base);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
-  LIR* target = NewLIR0(kPseudoTargetLabel);
-  branch_over->target = target;
   FreeTemp(reg_card_base);
   FreeTemp(reg_card_no);
 }
@@ -372,4 +321,84 @@
   OpReg(kOpBx, rs_rRA);
 }
 
+/*
+ * Bit of a hack here - in the absence of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
+                          int state, const MethodReference& target_method,
+                          uint32_t,
+                          uintptr_t direct_code, uintptr_t direct_method,
+                          InvokeType type) {
+  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
+  if (direct_code != 0 && direct_method != 0) {
+    switch (state) {
+    case 0:  // Get the current Method* [sets kArg0]
+      if (direct_code != static_cast<uintptr_t>(-1)) {
+        cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
+      } else {
+        cg->LoadCodeAddress(target_method, type, kInvokeTgt);
+      }
+      if (direct_method != static_cast<uintptr_t>(-1)) {
+        cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method);
+      } else {
+        cg->LoadMethodAddress(target_method, type, kArg0);
+      }
+      break;
+    default:
+      return -1;
+    }
+  } else {
+    RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
+    switch (state) {
+    case 0:  // Get the current Method* [sets kArg0]
+      // TUNING: we can save a reg copy if Method* has been promoted.
+      cg->LoadCurrMethodDirect(arg0_ref);
+      break;
+    case 1:  // Get method->dex_cache_resolved_methods_
+      cg->LoadRefDisp(arg0_ref,
+                      mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+                      arg0_ref,
+                      kNotVolatile);
+      // Set up direct code if known.
+      if (direct_code != 0) {
+        if (direct_code != static_cast<uintptr_t>(-1)) {
+          cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
+        } else {
+          CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
+          cg->LoadCodeAddress(target_method, type, kInvokeTgt);
+        }
+      }
+      break;
+    case 2:  // Grab target method*
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
+      cg->LoadRefDisp(arg0_ref,
+                      mirror::ObjectArray<mirror::Object>::
+                          OffsetOfElement(target_method.dex_method_index).Int32Value(),
+                      arg0_ref,
+                      kNotVolatile);
+      break;
+    case 3:  // Grab the code from the method*
+      if (direct_code == 0) {
+        int32_t offset = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+            InstructionSetPointerSize(cu->instruction_set)).Int32Value();
+        // Get the compiled code address [use *alt_from or kArg0, set kInvokeTgt]
+        cg->LoadWordDisp(arg0_ref, offset, cg->TargetPtrReg(kInvokeTgt));
+      }
+      break;
+    default:
+      return -1;
+    }
+  }
+  return state + 1;
+}
+
+NextCallInsn MipsMir2Lir::GetNextSDCallInsn() {
+  return NextSDCallInsn;
+}
+
+LIR* MipsMir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info ATTRIBUTE_UNUSED) {
+  return OpReg(kOpBlx, TargetPtrReg(kInvokeTgt));
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index be94019..ac14704 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -24,6 +24,26 @@
 namespace art {
 
 class MipsMir2Lir FINAL : public Mir2Lir {
+ protected:
+  class InToRegStorageMipsMapper : public InToRegStorageMapper {
+   public:
+    explicit InToRegStorageMipsMapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0) {}
+    virtual RegStorage GetNextReg(ShortyArg arg);
+    virtual void Reset() OVERRIDE {
+      cur_core_reg_ = 0;
+    }
+   protected:
+    Mir2Lir* m2l_;
+   private:
+    size_t cur_core_reg_;
+  };
+
+  InToRegStorageMipsMapper in_to_reg_storage_mips_mapper_;
+  InToRegStorageMapper* GetResetedInToRegStorageMapper() OVERRIDE {
+    in_to_reg_storage_mips_mapper_.Reset();
+    return &in_to_reg_storage_mips_mapper_;
+  }
+
   public:
     MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
@@ -31,6 +51,10 @@
     bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                             RegLocation rl_dest, int lit);
     bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
+    void GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                    int32_t constant) OVERRIDE;
+    void GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                     int64_t constant) OVERRIDE;
     LIR* CheckSuspendUsingLoad() OVERRIDE;
     RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -45,12 +69,13 @@
                           OpSize size) OVERRIDE;
     LIR* GenAtomic64Load(RegStorage r_base, int displacement, RegStorage r_dest);
     LIR* GenAtomic64Store(RegStorage r_base, int displacement, RegStorage r_src);
-    void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+
+    /// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
+    void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
 
     // Required for target - register utilities.
     RegStorage Solo64ToPair64(RegStorage reg);
     RegStorage TargetReg(SpecialTargetRegister reg);
-    RegStorage GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
     RegLocation GetReturnWideAlt();
     RegLocation LocCReturn();
@@ -86,13 +111,13 @@
 
     // Required for target - Dalvik-level generators.
     void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                           RegLocation rl_src1, RegLocation rl_src2);
+                           RegLocation rl_src1, RegLocation rl_src2, int flags);
     void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                      RegLocation rl_index, RegLocation rl_dest, int scale);
     void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                      RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark);
     void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                           RegLocation rl_shift);
+                           RegLocation rl_shift, int flags);
     void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                           RegLocation rl_src2);
     void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
@@ -108,7 +133,7 @@
     bool GenInlinedPeek(CallInfo* info, OpSize size);
     bool GenInlinedPoke(CallInfo* info, OpSize size);
     void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                        RegLocation rl_src2) OVERRIDE;
+                        RegLocation rl_src2, int flags) OVERRIDE;
     RegLocation GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi, bool is_div);
     RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div);
     void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
@@ -116,13 +141,12 @@
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
     void GenSpecialExitSequence();
-    void GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
     void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
     void GenSelect(BasicBlock* bb, MIR* mir);
     void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                           int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                          int dest_reg_class) OVERRIDE;
+                          RegisterClass dest_reg_class) OVERRIDE;
     bool GenMemBarrier(MemBarrierKind barrier_kind);
     void GenMoveException(RegLocation rl_dest);
     void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
@@ -173,15 +197,38 @@
     bool InexpensiveConstantLong(int64_t value);
     bool InexpensiveConstantDouble(int64_t value);
 
-    bool WideGPRsAreAliases() OVERRIDE {
+    bool WideGPRsAreAliases() const OVERRIDE {
       return false;  // Wide GPRs are formed by pairing.
     }
-    bool WideFPRsAreAliases() OVERRIDE {
+    bool WideFPRsAreAliases() const OVERRIDE {
       return false;  // Wide FPRs are formed by pairing.
     }
 
     LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
 
+    RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+                          RegLocation rl_src2, bool is_div, int flags) OVERRIDE;
+    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div)
+        OVERRIDE;
+
+    NextCallInsn GetNextSDCallInsn() OVERRIDE;
+    LIR* GenCallInsn(const MirMethodLoweringInfo& method_info) OVERRIDE;
+
+    // Unimplemented intrinsics.
+    bool GenInlinedCharAt(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
+      return false;
+    }
+    bool GenInlinedAbsInt(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
+      return false;
+    }
+    bool GenInlinedAbsLong(CallInfo* info ATTRIBUTE_UNUSED) OVERRIDE {
+      return false;
+    }
+    bool GenInlinedIndexOf(CallInfo* info ATTRIBUTE_UNUSED, bool zero_based ATTRIBUTE_UNUSED)
+        OVERRIDE {
+      return false;
+    }
+
   private:
     void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
     void GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
@@ -190,9 +237,6 @@
                     RegLocation rl_src2);
 
     void ConvertShortToLongBranch(LIR* lir);
-    RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                          RegLocation rl_src2, bool is_div, bool check_zero);
-    RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index 3a4128a..495d85e 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "mips_lir.h"
@@ -113,6 +114,20 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+void MipsMir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                             int32_t constant) {
+  // TODO: need mips implementation.
+  UNUSED(rl_dest, rl_src1, constant);
+  LOG(FATAL) << "Unimplemented GenMultiplyByConstantFloat in mips";
+}
+
+void MipsMir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                              int64_t constant) {
+  // TODO: need mips implementation.
+  UNUSED(rl_dest, rl_src1, constant);
+  LOG(FATAL) << "Unimplemented GenMultiplyByConstantDouble in mips";
+}
+
 void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
                                 RegLocation rl_src) {
   int op = kMipsNop;
@@ -207,8 +222,8 @@
   StoreValue(rl_dest, rl_result);
 }
 
-void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir,
-                                bool gt_bias, bool is_double) {
+void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) {
+  UNUSED(bb, mir, gt_bias, is_double);
   UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
 }
 
@@ -230,7 +245,8 @@
 }
 
 bool MipsMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
-  // TODO: need Mips implementation
+  // TODO: need Mips implementation.
+  UNUSED(info, is_min, is_long);
   return false;
 }
 
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 95c1262..aabef60 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -17,11 +17,12 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "mips_lir.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
 
 namespace art {
 
@@ -171,7 +172,7 @@
   if (r_dest.IsFloat() || r_src.IsFloat())
     return OpFpRegCopy(r_dest, r_src);
   LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
-            r_dest.GetReg(), r_src.GetReg());
+                    r_dest.GetReg(), r_src.GetReg());
   if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
     res->flags.is_nop = true;
   }
@@ -193,7 +194,7 @@
       if (src_fp) {
         OpRegCopy(r_dest, r_src);
       } else {
-         /* note the operands are swapped for the mtc1 instr */
+        /* note the operands are swapped for the mtc1 instr */
         NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
         NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
       }
@@ -217,7 +218,8 @@
 
 void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                                    int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                                   int dest_reg_class) {
+                                   RegisterClass dest_reg_class) {
+  UNUSED(dest_reg_class);
   // Implement as a branch-over.
   // TODO: Conditional move?
   LoadConstant(rs_dest, true_val);
@@ -228,15 +230,17 @@
 }
 
 void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb, mir);
   UNIMPLEMENTED(FATAL) << "Need codegen for select";
 }
 
 void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb, mir);
   UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
 }
 
 RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
-                                    bool is_div) {
+                                   bool is_div) {
   NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (is_div) {
@@ -248,7 +252,7 @@
 }
 
 RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
-                                       bool is_div) {
+                                      bool is_div) {
   RegStorage t_reg = AllocTemp();
   NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
   NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
@@ -262,34 +266,39 @@
   return rl_result;
 }
 
-RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                      RegLocation rl_src2, bool is_div, bool check_zero) {
+RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                   bool is_div, int flags) {
+  UNUSED(rl_dest, rl_src1, rl_src2, is_div, flags);
   LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
-  return rl_dest;
+  UNREACHABLE();
 }
 
-RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
+RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit,
+                                      bool is_div) {
+  UNUSED(rl_dest, rl_src1, lit, is_div);
   LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
-  return rl_dest;
+  UNREACHABLE();
 }
 
 bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
-  DCHECK_NE(cu_->instruction_set, kThumb2);
+  UNUSED(info, is_long, is_object);
   return false;
 }
 
 bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
-  // TODO - add Mips implementation
+  UNUSED(info);
+  // TODO: add Mips implementation.
   return false;
 }
 
 bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
-  // TODO - add Mips implementation
+  UNUSED(info);
+  // TODO: add Mips implementation.
   return false;
 }
 
 bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
-  DCHECK_NE(cu_->instruction_set, kThumb2);
+  UNUSED(info);
   return false;
 }
 
@@ -325,23 +334,27 @@
 }
 
 LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
+  UNUSED(reg, target);
   LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
+  UNUSED(r_base, count);
   LOG(FATAL) << "Unexpected use of OpVldm for Mips";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
+  UNUSED(r_base, count);
   LOG(FATAL) << "Unexpected use of OpVstm for Mips";
-  return NULL;
+  UNREACHABLE();
 }
 
 void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
                                                 RegLocation rl_result, int lit,
                                                 int first_bit, int second_bit) {
+  UNUSED(lit);
   RegStorage t_reg = AllocTemp();
   OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
   OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
@@ -373,27 +386,31 @@
 
 bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                      RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(dalvik_opcode, is_div, rl_src, rl_dest, lit);
   LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
-  return false;
+  UNREACHABLE();
 }
 
 bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(rl_src, rl_dest, lit);
   LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
-  return false;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
+  UNUSED(cond, guide);
   LOG(FATAL) << "Unexpected use of OpIT in Mips";
-  return NULL;
+  UNREACHABLE();
 }
 
 void MipsMir2Lir::OpEndIT(LIR* it) {
+  UNUSED(it);
   LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
 }
 
-
 void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
                              RegLocation rl_src1, RegLocation rl_src2) {
+  UNUSED(opcode);
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -416,6 +433,7 @@
 
 void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
                              RegLocation rl_src1, RegLocation rl_src2) {
+  UNUSED(opcode);
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -437,7 +455,7 @@
 }
 
 void MipsMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                                 RegLocation rl_src2) {
+                                 RegLocation rl_src2, int flags) {
   switch (opcode) {
     case Instruction::ADD_LONG:
     case Instruction::ADD_LONG_2ADDR:
@@ -456,7 +474,7 @@
   }
 
   // Fallback for all other ops.
-  Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+  Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
 }
 
 void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
@@ -483,7 +501,7 @@
  * Generate array load
  */
 void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
-                          RegLocation rl_index, RegLocation rl_dest, int scale) {
+                              RegLocation rl_index, RegLocation rl_dest, int scale) {
   RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
@@ -552,7 +570,7 @@
  *
  */
 void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
-                          RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
+                              RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
   RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
@@ -614,7 +632,7 @@
   } else {
     rl_src = LoadValue(rl_src, reg_class);
     if (needs_range_check) {
-       GenArrayBoundsCheck(rl_index.reg, reg_len);
+      GenArrayBoundsCheck(rl_index.reg, reg_len);
       FreeTemp(reg_len);
     }
     StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
@@ -623,20 +641,22 @@
     FreeTemp(reg_ptr);
   }
   if (card_mark) {
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
 void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                    RegLocation rl_src1, RegLocation rl_shift) {
+                                    RegLocation rl_src1, RegLocation rl_shift, int flags) {
+  UNUSED(flags);
   // Default implementation is just to ignore the constant case.
   GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
 }
 
 void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
-                                    RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
+                                    RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                    int flags) {
   // Default - bail to non-const handler.
-  GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+  GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index 495eb16..3df8f2e 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -142,7 +142,7 @@
 // This bit determines how the CPU access FP registers.
 #define FR_BIT   0
 
-enum MipsNativeRegisterPool {
+enum MipsNativeRegisterPool {  // private marker to avoid generate-operator-out.py from processing.
   rZERO = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  0,
   rAT   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  1,
   rV0   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  2,
@@ -214,44 +214,43 @@
   rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
   rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
 #endif
-#if (FR_BIT == 0)
-  rD0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
-  rD1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
-  rD2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
-  rD3  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
-  rD4  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
-  rD5  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
-  rD6  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
-  rD7  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+  // Double precision registers where the FPU is in 32-bit mode.
+  rD0_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  rD1_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD2_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD3_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD4_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD5_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD6_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD7_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
 #if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
-  rD8  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
-  rD9  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
-  rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
-  rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
-  rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
-  rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
-  rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
-  rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
+  rD8_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+  rD9_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+  rD10_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+  rD11_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+  rD12_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+  rD13_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+  rD14_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+  rD15_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
 #endif
-#else
-  rD0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
-  rD1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
-  rD2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
-  rD3  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  3,
-  rD4  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
-  rD5  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  5,
-  rD6  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
-  rD7  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  7,
+  // Double precision registers where the FPU is in 64-bit mode.
+  rD0_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  rD1_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
+  rD2_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD3_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  3,
+  rD4_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD5_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  5,
+  rD6_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD7_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  7,
 #if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
-  rD8  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
-  rD9  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  9,
-  rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
-  rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
-  rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
-  rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
-  rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
-  rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
-#endif
+  rD8_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD9_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  9,
+  rD10_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD11_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+  rD12_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD13_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+  rD14_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+  rD15_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
 #endif
 };
 
@@ -309,14 +308,23 @@
 constexpr RegStorage rs_rF14(RegStorage::kValid | rF14);
 constexpr RegStorage rs_rF15(RegStorage::kValid | rF15);
 
-constexpr RegStorage rs_rD0(RegStorage::kValid | rD0);
-constexpr RegStorage rs_rD1(RegStorage::kValid | rD1);
-constexpr RegStorage rs_rD2(RegStorage::kValid | rD2);
-constexpr RegStorage rs_rD3(RegStorage::kValid | rD3);
-constexpr RegStorage rs_rD4(RegStorage::kValid | rD4);
-constexpr RegStorage rs_rD5(RegStorage::kValid | rD5);
-constexpr RegStorage rs_rD6(RegStorage::kValid | rD6);
-constexpr RegStorage rs_rD7(RegStorage::kValid | rD7);
+constexpr RegStorage rs_rD0_fr0(RegStorage::kValid | rD0_fr0);
+constexpr RegStorage rs_rD1_fr0(RegStorage::kValid | rD1_fr0);
+constexpr RegStorage rs_rD2_fr0(RegStorage::kValid | rD2_fr0);
+constexpr RegStorage rs_rD3_fr0(RegStorage::kValid | rD3_fr0);
+constexpr RegStorage rs_rD4_fr0(RegStorage::kValid | rD4_fr0);
+constexpr RegStorage rs_rD5_fr0(RegStorage::kValid | rD5_fr0);
+constexpr RegStorage rs_rD6_fr0(RegStorage::kValid | rD6_fr0);
+constexpr RegStorage rs_rD7_fr0(RegStorage::kValid | rD7_fr0);
+
+constexpr RegStorage rs_rD0_fr1(RegStorage::kValid | rD0_fr1);
+constexpr RegStorage rs_rD1_fr1(RegStorage::kValid | rD1_fr1);
+constexpr RegStorage rs_rD2_fr1(RegStorage::kValid | rD2_fr1);
+constexpr RegStorage rs_rD3_fr1(RegStorage::kValid | rD3_fr1);
+constexpr RegStorage rs_rD4_fr1(RegStorage::kValid | rD4_fr1);
+constexpr RegStorage rs_rD5_fr1(RegStorage::kValid | rD5_fr1);
+constexpr RegStorage rs_rD6_fr1(RegStorage::kValid | rD6_fr1);
+constexpr RegStorage rs_rD7_fr1(RegStorage::kValid | rD7_fr1);
 
 // TODO: reduce/eliminate use of these.
 #define rMIPS_SUSPEND rS0
@@ -408,9 +416,7 @@
   kMipsBnez,  // bnez s,o [000101] s[25..21] [00000] o[15..0].
   kMipsBne,   // bne s,t,o [000101] s[25..21] t[20..16] o[15..0].
   kMipsDiv,   // div s,t [000000] s[25..21] t[20..16] [0000000000011010].
-#if __mips_isa_rev >= 2
   kMipsExt,   // ext t,s,p,z [011111] s[25..21] t[20..16] z[15..11] p[10..6] [000000].
-#endif
   kMipsJal,   // jal t [000011] t[25..0].
   kMipsJalr,  // jalr d,s [000000] s[25..21] [00000] d[15..11] hint[10..6] [001001].
   kMipsJr,    // jr s [000000] s[25..21] [0000000000] hint[10..6] [001000].
@@ -433,10 +439,8 @@
   kMipsOri,   // ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0].
   kMipsPref,  // pref h,o(b) [101011] b[25..21] h[20..16] o[15..0].
   kMipsSb,    // sb t,o(b) [101000] b[25..21] t[20..16] o[15..0].
-#if __mips_isa_rev >= 2
   kMipsSeb,   // seb d,t [01111100000] t[20..16] d[15..11] [10000100000].
   kMipsSeh,   // seh d,t [01111100000] t[20..16] d[15..11] [11000100000].
-#endif
   kMipsSh,    // sh t,o(b) [101001] b[25..21] t[20..16] o[15..0].
   kMipsSll,   // sll d,t,a [00000000000] t[20..16] d[15..11] a[10..6] [000000].
   kMipsSllv,  // sllv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000100].
@@ -481,15 +485,17 @@
   kMipsUndefined,  // undefined [011001xxxxxxxxxxxxxxxx].
   kMipsLast
 };
+std::ostream& operator<<(std::ostream& os, const MipsOpCode& rhs);
 
 // Instruction assembly field_loc kind.
 enum MipsEncodingKind {
   kFmtUnused,
-  kFmtBitBlt,    /* Bit string using end/start */
-  kFmtDfp,       /* Double FP reg */
-  kFmtSfp,       /* Single FP reg */
-  kFmtBlt5_2,    /* Same 5-bit field to 2 locations */
+  kFmtBitBlt,    // Bit string using end/start.
+  kFmtDfp,       // Double FP reg.
+  kFmtSfp,       // Single FP reg
+  kFmtBlt5_2,    // Same 5-bit field to 2 locations.
 };
+std::ostream& operator<<(std::ostream& os, const MipsEncodingKind& rhs);
 
 // Struct used to define the snippet positions for each MIPS opcode.
 struct MipsEncodingMap {
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index d3719ab..c819903 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -20,6 +20,7 @@
 
 #include <string>
 
+#include "arch/mips/instruction_set_features_mips.h"
 #include "backend_mips.h"
 #include "dex/compiler_internals.h"
 #include "dex/quick/mir_to_lir-inl.h"
@@ -34,8 +35,12 @@
 static constexpr RegStorage sp_regs_arr[] =
     {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
      rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
-static constexpr RegStorage dp_regs_arr[] =
-    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static constexpr RegStorage dp_fr0_regs_arr[] =
+    {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
+     rs_rD7_fr0};
+static constexpr RegStorage dp_fr1_regs_arr[] =
+    {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
+     rs_rD7_fr1};
 static constexpr RegStorage reserved_regs_arr[] =
     {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
 static constexpr RegStorage core_temps_arr[] =
@@ -44,17 +49,23 @@
 static constexpr RegStorage sp_temps_arr[] =
     {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
      rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
-static constexpr RegStorage dp_temps_arr[] =
-    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static constexpr RegStorage dp_fr0_temps_arr[] =
+    {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
+     rs_rD7_fr0};
+static constexpr RegStorage dp_fr1_temps_arr[] =
+    {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
+     rs_rD7_fr1};
 
 static constexpr ArrayRef<const RegStorage> empty_pool;
 static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
 static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
-static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr0_regs(dp_fr0_regs_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr1_regs(dp_fr1_regs_arr);
 static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
 static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
 static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
-static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr0_temps(dp_fr0_temps_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr1_temps(dp_fr1_temps_arr);
 
 RegLocation MipsMir2Lir::LocCReturn() {
   return mips_loc_c_return;
@@ -78,9 +89,9 @@
 
 // Convert k64BitSolo into k64BitPair
 RegStorage MipsMir2Lir::Solo64ToPair64(RegStorage reg) {
-    DCHECK(reg.IsDouble());
-    int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
-    return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
+  DCHECK(reg.IsDouble());
+  int reg_num = (reg.GetRegNum() & ~1) | RegStorage::kFloatingPoint;
+  return RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
 }
 
 // Return a target-dependent special register.
@@ -111,32 +122,37 @@
   return res_reg;
 }
 
-RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
-  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
-  switch (arg_num) {
-    case 0:
-      return rs_rMIPS_ARG1;
-    case 1:
-      return rs_rMIPS_ARG2;
-    case 2:
-      return rs_rMIPS_ARG3;
-    default:
-      return RegStorage::InvalidReg();
+RegStorage MipsMir2Lir::InToRegStorageMipsMapper::GetNextReg(ShortyArg arg) {
+  const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
+  const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
+
+  RegStorage result = RegStorage::InvalidReg();
+  if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+    result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
+                             arg.IsRef() ? kRef : kNotWide);
+    if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+      result = RegStorage::MakeRegPair(
+          result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
+    }
   }
+  return result;
 }
 
 /*
  * Decode the register id.
  */
 ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
-  return reg.IsDouble()
-      /* Each double register is equal to a pair of single-precision FP registers */
-#if (FR_BIT == 0)
-      ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0)
-#else
-      ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0)
-#endif
-      : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum());
+  if (reg.IsDouble()) {
+    if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
+      return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
+    } else {
+      return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
+    }
+  } else if (reg.IsSingle()) {
+    return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
+  } else {
+    return ResourceMask::Bit(reg.GetRegNum());
+  }
 }
 
 ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
@@ -207,78 +223,78 @@
       if (nc == '!') {
         strcpy(tbuf, "!");
       } else {
-         DCHECK_LT(fmt, fmt_end);
-         DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
-         operand = lir->operands[nc-'0'];
-         switch (*fmt++) {
-           case 'b':
-             strcpy(tbuf, "0000");
-             for (i = 3; i >= 0; i--) {
-               tbuf[i] += operand & 1;
-               operand >>= 1;
-             }
-             break;
-           case 's':
-             snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
-             break;
-           case 'S':
-             DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
-             snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
-             break;
-           case 'h':
-             snprintf(tbuf, arraysize(tbuf), "%04x", operand);
-             break;
-           case 'M':
-           case 'd':
-             snprintf(tbuf, arraysize(tbuf), "%d", operand);
-             break;
-           case 'D':
-             snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
-             break;
-           case 'E':
-             snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
-             break;
-           case 'F':
-             snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
-             break;
-           case 't':
-             snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
-                 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
-                 lir->target);
-             break;
-           case 'T':
-             snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
-             break;
-           case 'u': {
-             int offset_1 = lir->operands[0];
-             int offset_2 = NEXT_LIR(lir)->operands[0];
-             uintptr_t target =
-                 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
-                 (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
-             snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
-             break;
+        DCHECK_LT(fmt, fmt_end);
+        DCHECK_LT(static_cast<unsigned>(nc-'0'), 4u);
+        operand = lir->operands[nc-'0'];
+        switch (*fmt++) {
+          case 'b':
+            strcpy(tbuf, "0000");
+            for (i = 3; i >= 0; i--) {
+              tbuf[i] += operand & 1;
+              operand >>= 1;
+            }
+            break;
+          case 's':
+            snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
+            break;
+          case 'S':
+            DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
+            snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
+            break;
+          case 'h':
+            snprintf(tbuf, arraysize(tbuf), "%04x", operand);
+            break;
+          case 'M':
+          case 'd':
+            snprintf(tbuf, arraysize(tbuf), "%d", operand);
+            break;
+          case 'D':
+            snprintf(tbuf, arraysize(tbuf), "%d", operand+1);
+            break;
+          case 'E':
+            snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
+            break;
+          case 'F':
+            snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
+            break;
+          case 't':
+            snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
+                     reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
+                     lir->target);
+            break;
+          case 'T':
+            snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
+            break;
+          case 'u': {
+            int offset_1 = lir->operands[0];
+            int offset_2 = NEXT_LIR(lir)->operands[0];
+            uintptr_t target =
+                (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) & ~3) +
+                    (offset_1 << 21 >> 9) + (offset_2 << 1)) & 0xfffffffc;
+            snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void*>(target));
+            break;
           }
 
-           /* Nothing to print for BLX_2 */
-           case 'v':
-             strcpy(tbuf, "see above");
-             break;
-           case 'r':
-             DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
-             strcpy(tbuf, mips_reg_name[operand]);
-             break;
-           case 'N':
-             // Placeholder for delay slot handling
-             strcpy(tbuf, ";  nop");
-             break;
-           default:
-             strcpy(tbuf, "DecodeError");
-             break;
-         }
-         buf += tbuf;
+          /* Nothing to print for BLX_2 */
+          case 'v':
+            strcpy(tbuf, "see above");
+            break;
+          case 'r':
+            DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
+            strcpy(tbuf, mips_reg_name[operand]);
+            break;
+          case 'N':
+            // Placeholder for delay slot handling
+            strcpy(tbuf, ";  nop");
+            break;
+          default:
+            strcpy(tbuf, "DecodeError");
+            break;
+        }
+        buf += tbuf;
       }
     } else {
-       buf += *fmt++;
+      buf += *fmt++;
     }
   }
   return buf;
@@ -382,14 +398,25 @@
   Clobber(rs_rF13);
   Clobber(rs_rF14);
   Clobber(rs_rF15);
-  Clobber(rs_rD0);
-  Clobber(rs_rD1);
-  Clobber(rs_rD2);
-  Clobber(rs_rD3);
-  Clobber(rs_rD4);
-  Clobber(rs_rD5);
-  Clobber(rs_rD6);
-  Clobber(rs_rD7);
+  if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
+    Clobber(rs_rD0_fr0);
+    Clobber(rs_rD1_fr0);
+    Clobber(rs_rD2_fr0);
+    Clobber(rs_rD3_fr0);
+    Clobber(rs_rD4_fr0);
+    Clobber(rs_rD5_fr0);
+    Clobber(rs_rD6_fr0);
+    Clobber(rs_rD7_fr0);
+  } else {
+    Clobber(rs_rD0_fr1);
+    Clobber(rs_rD1_fr1);
+    Clobber(rs_rD2_fr1);
+    Clobber(rs_rD3_fr1);
+    Clobber(rs_rD4_fr1);
+    Clobber(rs_rD5_fr1);
+    Clobber(rs_rD6_fr1);
+    Clobber(rs_rD7_fr1);
+  }
 }
 
 RegLocation MipsMir2Lir::GetReturnWideAlt() {
@@ -418,34 +445,40 @@
   FreeTemp(rs_rMIPS_ARG1);
   FreeTemp(rs_rMIPS_ARG2);
   FreeTemp(rs_rMIPS_ARG3);
+  FreeTemp(TargetReg(kHiddenArg));
 }
 
-bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
-#if ANDROID_SMP != 0
-  NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
-  return true;
-#else
-  return false;
-#endif
+bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
+  if (cu_->GetInstructionSetFeatures()->IsSmp()) {
+    NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
+    return true;
+  } else {
+    return false;
+  }
 }
 
 void MipsMir2Lir::CompilerInitializeRegAlloc() {
+  const bool fpu_is_32bit =
+      cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
   reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
-                                            sp_regs, dp_regs,
+                                            sp_regs,
+                                            fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
                                             reserved_regs, empty_pool /* reserved64 */,
                                             core_temps, empty_pool /* core64_temps */,
-                                            sp_temps, dp_temps));
+                                            sp_temps,
+                                            fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
 
   // Target-specific adjustments.
 
   // Alias single precision floats to appropriate half of overlapping double.
   for (RegisterInfo* info : reg_pool_->sp_regs_) {
     int sp_reg_num = info->GetReg().GetRegNum();
-#if (FR_BIT == 0)
-    int dp_reg_num = sp_reg_num & ~1;
-#else
-    int dp_reg_num = sp_reg_num >> 1;
-#endif
+    int dp_reg_num;
+    if (fpu_is_32bit) {
+      dp_reg_num = sp_reg_num & ~1;
+    } else {
+      dp_reg_num = sp_reg_num >> 1;
+    }
     RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
     RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
     // Double precision register's master storage should refer to itself.
@@ -464,11 +497,11 @@
   // TODO: adjust when we roll to hard float calling convention.
   reg_pool_->next_core_reg_ = 2;
   reg_pool_->next_sp_reg_ = 2;
-#if (FR_BIT == 0)
-  reg_pool_->next_dp_reg_ = 2;
-#else
-  reg_pool_->next_dp_reg_ = 1;
-#endif
+  if (fpu_is_32bit) {
+    reg_pool_->next_dp_reg_ = 2;
+  } else {
+    reg_pool_->next_dp_reg_ = 1;
+  }
 }
 
 /*
@@ -572,13 +605,12 @@
 }
 
 MipsMir2Lir::MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
-    : Mir2Lir(cu, mir_graph, arena) {
+    : Mir2Lir(cu, mir_graph, arena), in_to_reg_storage_mips_mapper_(this) {
   for (int i = 0; i < kMipsLast; i++) {
-    if (MipsMir2Lir::EncodingMap[i].opcode != i) {
-      LOG(FATAL) << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
-                 << " is wrong: expecting " << i << ", seeing "
-                 << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
-    }
+    DCHECK_EQ(MipsMir2Lir::EncodingMap[i].opcode, i)
+        << "Encoding order for " << MipsMir2Lir::EncodingMap[i].name
+        << " is wrong: expecting " << i << ", seeing "
+        << static_cast<int>(MipsMir2Lir::EncodingMap[i].opcode);
   }
 }
 
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 7178ede..15fc69d 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -15,6 +15,8 @@
  */
 
 #include "codegen_mips.h"
+
+#include "arch/mips/instruction_set_features_mips.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "mips_lir.h"
@@ -56,14 +58,17 @@
 }
 
 bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
+  UNUSED(value);
   return false;  // TUNING
 }
 
 bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) {
+  UNUSED(value);
   return false;  // TUNING
 }
 
 bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) {
+  UNUSED(value);
   return false;  // TUNING
 }
 
@@ -120,7 +125,7 @@
       opcode = kMipsJalr;
       break;
     case kOpBx:
-      return NewLIR1(kMipsJr, r_dest_src.GetReg());
+      return NewLIR2(kMipsJalr, rZERO, r_dest_src.GetReg());
       break;
     default:
       LOG(FATAL) << "Bad case in OpReg";
@@ -223,17 +228,17 @@
       }
       break;
     case kOpLsl:
-        DCHECK(value >= 0 && value <= 31);
-        opcode = kMipsSll;
-        break;
+      DCHECK(value >= 0 && value <= 31);
+      opcode = kMipsSll;
+      break;
     case kOpLsr:
-        DCHECK(value >= 0 && value <= 31);
-        opcode = kMipsSrl;
-        break;
+      DCHECK(value >= 0 && value <= 31);
+      opcode = kMipsSrl;
+      break;
     case kOpAsr:
-        DCHECK(value >= 0 && value <= 31);
-        opcode = kMipsSra;
-        break;
+      DCHECK(value >= 0 && value <= 31);
+      opcode = kMipsSra;
+      break;
     case kOpAnd:
       if (IS_UIMM16((value))) {
         opcode = kMipsAndi;
@@ -301,44 +306,49 @@
     case kOpXor:
       return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
     case kOp2Byte:
-#if __mips_isa_rev >= 2
-      res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
-#else
-      res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
-      OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
-#endif
+      if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
+          ->IsMipsIsaRevGreaterThanEqual2()) {
+        res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
+      } else {
+        res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
+        OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
+      }
       return res;
     case kOp2Short:
-#if __mips_isa_rev >= 2
-      res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
-#else
-      res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
-      OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
-#endif
+      if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
+          ->IsMipsIsaRevGreaterThanEqual2()) {
+        res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
+      } else {
+        res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
+        OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
+      }
       return res;
     case kOp2Char:
-       return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
+      return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
     default:
       LOG(FATAL) << "Bad case in OpRegReg";
-      break;
+      UNREACHABLE();
   }
   return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
 }
 
 LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
                               MoveType move_type) {
+  UNUSED(r_dest, r_base, offset, move_type);
   UNIMPLEMENTED(FATAL);
-  return nullptr;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
+  UNUSED(r_base, offset, r_src, move_type);
   UNIMPLEMENTED(FATAL);
-  return nullptr;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
+  UNUSED(op, cc, r_dest, r_src);
   LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
@@ -538,7 +548,7 @@
   }
 
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rMIPS_SP);
+    DCHECK_EQ(r_base, rs_rMIPS_SP);
     AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
                             true /* is_load */, pair /* is64bit */);
     if (pair) {
@@ -640,7 +650,7 @@
   }
 
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rMIPS_SP);
+    DCHECK_EQ(r_base, rs_rMIPS_SP);
     AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
                             false /* is_load */, pair /* is64bit */);
     if (pair) {
@@ -681,16 +691,19 @@
 }
 
 LIR* MipsMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
+  UNUSED(op, r_base, disp);
   LOG(FATAL) << "Unexpected use of OpMem for MIPS";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
+  UNUSED(cc, target);
   LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
+  UNUSED(trampoline);  // The address of the trampoline is already loaded into r_tgt.
   return OpReg(op, r_tgt);
 }
 
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index 0aefc2d..144790e 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -276,6 +276,24 @@
   }
 }
 
+inline Mir2Lir::ShortyIterator::ShortyIterator(const char* shorty, bool is_static)
+    : cur_(shorty + 1), pending_this_(!is_static), initialized_(false) {
+  DCHECK(shorty != nullptr);
+  DCHECK_NE(*shorty, 0);
+}
+
+inline bool Mir2Lir::ShortyIterator::Next() {
+  if (!initialized_) {
+    initialized_ = true;
+  } else if (pending_this_) {
+    pending_this_ = false;
+  } else if (*cur_ != 0) {
+    cur_++;
+  }
+
+  return *cur_ != 0 || pending_this_;
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index e7160ad..1ff64c9 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -53,20 +53,14 @@
   return res;
 }
 
-void Mir2Lir::LockArg(int in_position, bool wide) {
-  RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
-  RegStorage reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) :
-      RegStorage::InvalidReg();
+void Mir2Lir::LockArg(int in_position, bool) {
+  RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
 
-  if (reg_arg_low.Valid()) {
-    LockTemp(reg_arg_low);
-  }
-  if (reg_arg_high.Valid() && reg_arg_low.NotExactlyEquals(reg_arg_high)) {
-    LockTemp(reg_arg_high);
+  if (reg_arg.Valid()) {
+    LockTemp(reg_arg);
   }
 }
 
-// TODO: simplify when 32-bit targets go hard-float.
 RegStorage Mir2Lir::LoadArg(int in_position, RegisterClass reg_class, bool wide) {
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
   int offset = StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
@@ -87,81 +81,38 @@
     offset += sizeof(uint64_t);
   }
 
-  if (cu_->target64) {
-    RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
-    if (!reg_arg.Valid()) {
-      RegStorage new_reg =
-          wide ?  AllocTypedTempWide(false, reg_class) : AllocTypedTemp(false, reg_class);
-      LoadBaseDisp(TargetPtrReg(kSp), offset, new_reg, wide ? k64 : k32, kNotVolatile);
-      return new_reg;
-    } else {
-      // Check if we need to copy the arg to a different reg_class.
-      if (!RegClassMatches(reg_class, reg_arg)) {
-        if (wide) {
-          RegStorage new_reg = AllocTypedTempWide(false, reg_class);
-          OpRegCopyWide(new_reg, reg_arg);
-          reg_arg = new_reg;
-        } else {
-          RegStorage new_reg = AllocTypedTemp(false, reg_class);
-          OpRegCopy(new_reg, reg_arg);
-          reg_arg = new_reg;
-        }
+  RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+
+  // TODO: REVISIT: This adds a spill of low part while we could just copy it.
+  if (reg_arg.Valid() && wide && (reg_arg.GetWideKind() == kNotWide)) {
+    // For wide register we've got only half of it.
+    // Flush it to memory then.
+    StoreBaseDisp(TargetPtrReg(kSp), offset, reg_arg, k32, kNotVolatile);
+    reg_arg = RegStorage::InvalidReg();
+  }
+
+  if (!reg_arg.Valid()) {
+    reg_arg = wide ?  AllocTypedTempWide(false, reg_class) : AllocTypedTemp(false, reg_class);
+    LoadBaseDisp(TargetPtrReg(kSp), offset, reg_arg, wide ? k64 : k32, kNotVolatile);
+  } else {
+    // Check if we need to copy the arg to a different reg_class.
+    if (!RegClassMatches(reg_class, reg_arg)) {
+      if (wide) {
+        RegStorage new_reg = AllocTypedTempWide(false, reg_class);
+        OpRegCopyWide(new_reg, reg_arg);
+        reg_arg = new_reg;
+      } else {
+        RegStorage new_reg = AllocTypedTemp(false, reg_class);
+        OpRegCopy(new_reg, reg_arg);
+        reg_arg = new_reg;
       }
     }
-    return reg_arg;
-  }
-
-  RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
-  RegStorage reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) :
-      RegStorage::InvalidReg();
-
-  // If the VR is wide and there is no register for high part, we need to load it.
-  if (wide && !reg_arg_high.Valid()) {
-    // If the low part is not in a reg, we allocate a pair. Otherwise, we just load to high reg.
-    if (!reg_arg_low.Valid()) {
-      RegStorage new_regs = AllocTypedTempWide(false, reg_class);
-      LoadBaseDisp(TargetPtrReg(kSp), offset, new_regs, k64, kNotVolatile);
-      return new_regs;  // The reg_class is OK, we can return.
-    } else {
-      // Assume that no ABI allows splitting a wide fp reg between a narrow fp reg and memory,
-      // i.e. the low part is in a core reg. Load the second part in a core reg as well for now.
-      DCHECK(!reg_arg_low.IsFloat());
-      reg_arg_high = AllocTemp();
-      int offset_high = offset + sizeof(uint32_t);
-      Load32Disp(TargetPtrReg(kSp), offset_high, reg_arg_high);
-      // Continue below to check the reg_class.
-    }
-  }
-
-  // If the low part is not in a register yet, we need to load it.
-  if (!reg_arg_low.Valid()) {
-    // Assume that if the low part of a wide arg is passed in memory, so is the high part,
-    // thus we don't get here for wide args as it's handled above. Big-endian ABIs could
-    // conceivably break this assumption but Android supports only little-endian architectures.
-    DCHECK(!wide);
-    reg_arg_low = AllocTypedTemp(false, reg_class);
-    Load32Disp(TargetPtrReg(kSp), offset, reg_arg_low);
-    return reg_arg_low;  // The reg_class is OK, we can return.
-  }
-
-  RegStorage reg_arg = wide ? RegStorage::MakeRegPair(reg_arg_low, reg_arg_high) : reg_arg_low;
-  // Check if we need to copy the arg to a different reg_class.
-  if (!RegClassMatches(reg_class, reg_arg)) {
-    if (wide) {
-      RegStorage new_regs = AllocTypedTempWide(false, reg_class);
-      OpRegCopyWide(new_regs, reg_arg);
-      reg_arg = new_regs;
-    } else {
-      RegStorage new_reg = AllocTypedTemp(false, reg_class);
-      OpRegCopy(new_reg, reg_arg);
-      reg_arg = new_reg;
-    }
   }
   return reg_arg;
 }
 
-// TODO: simpilfy when 32-bit targets go hard float.
 void Mir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
+  DCHECK_EQ(rl_dest.location, kLocPhysReg);
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
   int offset = StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
   if (cu_->instruction_set == kX86) {
@@ -180,38 +131,23 @@
     offset += sizeof(uint64_t);
   }
 
-  if (!rl_dest.wide) {
-    RegStorage reg = GetArgMappingToPhysicalReg(in_position);
-    if (reg.Valid()) {
-      OpRegCopy(rl_dest.reg, reg);
-    } else {
-      Load32Disp(TargetPtrReg(kSp), offset, rl_dest.reg);
-    }
+  RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+
+  // TODO: REVISIT: This adds a spill of low part while we could just copy it.
+  if (reg_arg.Valid() && rl_dest.wide && (reg_arg.GetWideKind() == kNotWide)) {
+    // For wide register we've got only half of it.
+    // Flush it to memory then.
+    StoreBaseDisp(TargetPtrReg(kSp), offset, reg_arg, k32, kNotVolatile);
+    reg_arg = RegStorage::InvalidReg();
+  }
+
+  if (!reg_arg.Valid()) {
+    LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, rl_dest.wide ? k64 : k32, kNotVolatile);
   } else {
-    if (cu_->target64) {
-      RegStorage reg = GetArgMappingToPhysicalReg(in_position);
-      if (reg.Valid()) {
-        OpRegCopy(rl_dest.reg, reg);
-      } else {
-        LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, k64, kNotVolatile);
-      }
-      return;
-    }
-
-    RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
-    RegStorage reg_arg_high = GetArgMappingToPhysicalReg(in_position + 1);
-
-    if (reg_arg_low.Valid() && reg_arg_high.Valid()) {
-      OpRegCopyWide(rl_dest.reg, RegStorage::MakeRegPair(reg_arg_low, reg_arg_high));
-    } else if (reg_arg_low.Valid() && !reg_arg_high.Valid()) {
-      OpRegCopy(rl_dest.reg, reg_arg_low);
-      int offset_high = offset + sizeof(uint32_t);
-      Load32Disp(TargetPtrReg(kSp), offset_high, rl_dest.reg.GetHigh());
-    } else if (!reg_arg_low.Valid() && reg_arg_high.Valid()) {
-      OpRegCopy(rl_dest.reg.GetHigh(), reg_arg_high);
-      Load32Disp(TargetPtrReg(kSp), offset, rl_dest.reg.GetLow());
+    if (rl_dest.wide) {
+      OpRegCopyWide(rl_dest.reg, reg_arg);
     } else {
-      LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, k64, kNotVolatile);
+      OpRegCopy(rl_dest.reg, reg_arg);
     }
   }
 }
@@ -322,7 +258,7 @@
         kNotVolatile);
   }
   if (IsRef(size)) {
-    MarkGCCard(reg_src, reg_obj);
+    MarkGCCard(0, reg_src, reg_obj);
   }
   return true;
 }
@@ -417,10 +353,10 @@
   RegLocation rl_src[3];
   RegLocation rl_dest = mir_graph_->GetBadLoc();
   RegLocation rl_result = mir_graph_->GetBadLoc();
-  Instruction::Code opcode = mir->dalvikInsn.opcode;
-  int opt_flags = mir->optimization_flags;
-  uint32_t vB = mir->dalvikInsn.vB;
-  uint32_t vC = mir->dalvikInsn.vC;
+  const Instruction::Code opcode = mir->dalvikInsn.opcode;
+  const int opt_flags = mir->optimization_flags;
+  const uint32_t vB = mir->dalvikInsn.vB;
+  const uint32_t vC = mir->dalvikInsn.vC;
   DCHECK(CheckCorePoolSanity()) << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " @ 0x:"
                                 << std::hex << current_dalvik_offset_;
 
@@ -482,7 +418,7 @@
 
     case Instruction::RETURN_OBJECT:
       DCHECK(rl_src[0].ref);
-      // Intentional fallthrough.
+      FALLTHROUGH_INTENDED;
     case Instruction::RETURN:
       if (!kLeafOptimization || !mir_graph_->MethodIsLeaf()) {
         GenSuspendTest(opt_flags);
@@ -572,7 +508,7 @@
       GenThrow(rl_src[0]);
       break;
 
-    case Instruction::ARRAY_LENGTH:
+    case Instruction::ARRAY_LENGTH: {
       int len_offset;
       len_offset = mirror::Array::LengthOffset().Int32Value();
       rl_src[0] = LoadValue(rl_src[0], kRefReg);
@@ -582,7 +518,7 @@
       MarkPossibleNullPointerException(opt_flags);
       StoreValue(rl_dest, rl_result);
       break;
-
+    }
     case Instruction::CONST_STRING:
     case Instruction::CONST_STRING_JUMBO:
       GenConstString(vB, rl_dest);
@@ -613,8 +549,7 @@
     case Instruction::GOTO:
     case Instruction::GOTO_16:
     case Instruction::GOTO_32:
-      if (mir_graph_->IsBackedge(bb, bb->taken) &&
-          (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken))) {
+      if (mir_graph_->IsBackEdge(bb, bb->taken)) {
         GenSuspendTestAndBranch(opt_flags, &label_list[bb->taken]);
       } else {
         OpUnconditionalBranch(&label_list[bb->taken]);
@@ -646,65 +581,35 @@
     case Instruction::IF_GE:
     case Instruction::IF_GT:
     case Instruction::IF_LE: {
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(opt_flags);
+      }
       LIR* taken = &label_list[bb->taken];
-      LIR* fall_through = &label_list[bb->fall_through];
-      // Result known at compile time?
-      if (rl_src[0].is_const && rl_src[1].is_const) {
-        bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg),
-                                       mir_graph_->ConstantValue(rl_src[1].orig_sreg));
-        BasicBlockId target_id = is_taken ? bb->taken : bb->fall_through;
-        if (mir_graph_->IsBackedge(bb, target_id) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, target_id))) {
-          GenSuspendTest(opt_flags);
-        }
-        OpUnconditionalBranch(&label_list[target_id]);
-      } else {
-        if (mir_graph_->IsBackwardsBranch(bb) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
-             !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
-          GenSuspendTest(opt_flags);
-        }
-        GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken, fall_through);
-      }
+      GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken);
       break;
-      }
-
+    }
     case Instruction::IF_EQZ:
     case Instruction::IF_NEZ:
     case Instruction::IF_LTZ:
     case Instruction::IF_GEZ:
     case Instruction::IF_GTZ:
     case Instruction::IF_LEZ: {
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(opt_flags);
+      }
       LIR* taken = &label_list[bb->taken];
-      LIR* fall_through = &label_list[bb->fall_through];
-      // Result known at compile time?
-      if (rl_src[0].is_const) {
-        bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg), 0);
-        BasicBlockId target_id = is_taken ? bb->taken : bb->fall_through;
-        if (mir_graph_->IsBackedge(bb, target_id) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, target_id))) {
-          GenSuspendTest(opt_flags);
-        }
-        OpUnconditionalBranch(&label_list[target_id]);
-      } else {
-        if (mir_graph_->IsBackwardsBranch(bb) &&
-            (kLeafOptimization || !mir_graph_->HasSuspendTestBetween(bb, bb->taken) ||
-             !mir_graph_->HasSuspendTestBetween(bb, bb->fall_through))) {
-          GenSuspendTest(opt_flags);
-        }
-        GenCompareZeroAndBranch(opcode, rl_src[0], taken, fall_through);
-      }
+      GenCompareZeroAndBranch(opcode, rl_src[0], taken);
       break;
-      }
+    }
 
     case Instruction::AGET_WIDE:
-      GenArrayGet(opt_flags, k64, rl_src[0], rl_src[1], rl_dest, 3);
+      GenArrayGet(opt_flags, rl_dest.fp ? kDouble : k64, rl_src[0], rl_src[1], rl_dest, 3);
       break;
     case Instruction::AGET_OBJECT:
       GenArrayGet(opt_flags, kReference, rl_src[0], rl_src[1], rl_dest, 2);
       break;
     case Instruction::AGET:
-      GenArrayGet(opt_flags, k32, rl_src[0], rl_src[1], rl_dest, 2);
+      GenArrayGet(opt_flags, rl_dest.fp ? kSingle : k32, rl_src[0], rl_src[1], rl_dest, 2);
       break;
     case Instruction::AGET_BOOLEAN:
       GenArrayGet(opt_flags, kUnsignedByte, rl_src[0], rl_src[1], rl_dest, 0);
@@ -719,10 +624,10 @@
       GenArrayGet(opt_flags, kSignedHalf, rl_src[0], rl_src[1], rl_dest, 1);
       break;
     case Instruction::APUT_WIDE:
-      GenArrayPut(opt_flags, k64, rl_src[1], rl_src[2], rl_src[0], 3, false);
+      GenArrayPut(opt_flags, rl_src[0].fp ? kDouble : k64, rl_src[1], rl_src[2], rl_src[0], 3, false);
       break;
     case Instruction::APUT:
-      GenArrayPut(opt_flags, k32, rl_src[1], rl_src[2], rl_src[0], 2, false);
+      GenArrayPut(opt_flags, rl_src[0].fp ? kSingle : k32, rl_src[1], rl_src[2], rl_src[0], 2, false);
       break;
     case Instruction::APUT_OBJECT: {
       bool is_null = mir_graph_->IsConstantNullRef(rl_src[0]);
@@ -756,11 +661,19 @@
 
     case Instruction::IGET_WIDE:
       // kPrimLong and kPrimDouble share the same entrypoints.
-      GenIGet(mir, opt_flags, k64, Primitive::kPrimLong, rl_dest, rl_src[0]);
+      if (rl_dest.fp) {
+        GenIGet(mir, opt_flags, kDouble, Primitive::kPrimDouble, rl_dest, rl_src[0]);
+      } else {
+        GenIGet(mir, opt_flags, k64, Primitive::kPrimLong, rl_dest, rl_src[0]);
+      }
       break;
 
     case Instruction::IGET:
-      GenIGet(mir, opt_flags, k32, Primitive::kPrimInt, rl_dest, rl_src[0]);
+      if (rl_dest.fp) {
+        GenIGet(mir, opt_flags, kSingle, Primitive::kPrimFloat, rl_dest, rl_src[0]);
+      } else {
+        GenIGet(mir, opt_flags, k32, Primitive::kPrimInt, rl_dest, rl_src[0]);
+      }
       break;
 
     case Instruction::IGET_CHAR:
@@ -780,7 +693,7 @@
       break;
 
     case Instruction::IPUT_WIDE:
-      GenIPut(mir, opt_flags, k64, rl_src[0], rl_src[1]);
+      GenIPut(mir, opt_flags, rl_src[0].fp ? kDouble : k64, rl_src[0], rl_src[1]);
       break;
 
     case Instruction::IPUT_OBJECT:
@@ -788,7 +701,7 @@
       break;
 
     case Instruction::IPUT:
-      GenIPut(mir, opt_flags, k32, rl_src[0], rl_src[1]);
+      GenIPut(mir, opt_flags, rl_src[0].fp ? kSingle : k32, rl_src[0], rl_src[1]);
       break;
 
     case Instruction::IPUT_BYTE:
@@ -809,7 +722,7 @@
       break;
 
     case Instruction::SGET:
-      GenSget(mir, rl_dest, k32, Primitive::kPrimInt);
+      GenSget(mir, rl_dest, rl_dest.fp ? kSingle : k32, Primitive::kPrimInt);
       break;
 
     case Instruction::SGET_CHAR:
@@ -830,7 +743,7 @@
 
     case Instruction::SGET_WIDE:
       // kPrimLong and kPrimDouble share the same entrypoints.
-      GenSget(mir, rl_dest, k64, Primitive::kPrimLong);
+      GenSget(mir, rl_dest, rl_dest.fp ? kDouble : k64, Primitive::kPrimDouble);
       break;
 
     case Instruction::SPUT_OBJECT:
@@ -838,7 +751,7 @@
       break;
 
     case Instruction::SPUT:
-      GenSput(mir, rl_src[0], k32);
+      GenSput(mir, rl_src[0], rl_src[0].fp ? kSingle : k32);
       break;
 
     case Instruction::SPUT_BYTE:
@@ -856,84 +769,52 @@
 
 
     case Instruction::SPUT_WIDE:
-      GenSput(mir, rl_src[0], k64);
+      GenSput(mir, rl_src[0], rl_src[0].fp ? kDouble : k64);
       break;
 
     case Instruction::INVOKE_STATIC_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, true));
-      if (!kLeafOptimization) {
-        // If the invocation is not inlined, we can assume there is already a
-        // suspend check at the return site
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
     case Instruction::INVOKE_STATIC:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, false));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
 
     case Instruction::INVOKE_DIRECT:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, false));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
     case Instruction::INVOKE_DIRECT_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, true));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
 
     case Instruction::INVOKE_VIRTUAL:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, false));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
     case Instruction::INVOKE_VIRTUAL_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, true));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
 
     case Instruction::INVOKE_SUPER:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, false));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
     case Instruction::INVOKE_SUPER_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, true));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
 
     case Instruction::INVOKE_INTERFACE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, false));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
     case Instruction::INVOKE_INTERFACE_RANGE:
       GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, true));
-      if (!kLeafOptimization) {
-        mir_graph_->AppendGenSuspendTestList(bb);
-      }
       break;
 
     case Instruction::NEG_INT:
     case Instruction::NOT_INT:
-      GenArithOpInt(opcode, rl_dest, rl_src[0], rl_src[0]);
+      GenArithOpInt(opcode, rl_dest, rl_src[0], rl_src[0], opt_flags);
       break;
 
     case Instruction::NEG_LONG:
     case Instruction::NOT_LONG:
-      GenArithOpLong(opcode, rl_dest, rl_src[0], rl_src[0]);
+      GenArithOpLong(opcode, rl_dest, rl_src[0], rl_src[0], opt_flags);
       break;
 
     case Instruction::NEG_FLOAT:
@@ -949,9 +830,7 @@
       break;
 
     case Instruction::LONG_TO_INT:
-      rl_src[0] = UpdateLocWide(rl_src[0]);
-      rl_src[0] = NarrowRegLoc(rl_src[0]);
-      StoreValue(rl_dest, rl_src[0]);
+      GenLongToInt(rl_dest, rl_src[0]);
       break;
 
     case Instruction::INT_TO_BYTE:
@@ -993,7 +872,7 @@
         GenArithOpIntLit(opcode, rl_dest, rl_src[0],
                              mir_graph_->ConstantValue(rl_src[1].orig_sreg));
       } else {
-        GenArithOpInt(opcode, rl_dest, rl_src[0], rl_src[1]);
+        GenArithOpInt(opcode, rl_dest, rl_src[0], rl_src[1], opt_flags);
       }
       break;
 
@@ -1013,7 +892,7 @@
           InexpensiveConstantInt(mir_graph_->ConstantValue(rl_src[1]), opcode)) {
         GenArithOpIntLit(opcode, rl_dest, rl_src[0], mir_graph_->ConstantValue(rl_src[1]));
       } else {
-        GenArithOpInt(opcode, rl_dest, rl_src[0], rl_src[1]);
+        GenArithOpInt(opcode, rl_dest, rl_src[0], rl_src[1], opt_flags);
       }
       break;
 
@@ -1028,18 +907,17 @@
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
       if (rl_src[0].is_const || rl_src[1].is_const) {
-        GenArithImmOpLong(opcode, rl_dest, rl_src[0], rl_src[1]);
+        GenArithImmOpLong(opcode, rl_dest, rl_src[0], rl_src[1], opt_flags);
         break;
       }
-      // Note: intentional fallthrough.
-
+      FALLTHROUGH_INTENDED;
     case Instruction::MUL_LONG:
     case Instruction::DIV_LONG:
     case Instruction::REM_LONG:
     case Instruction::MUL_LONG_2ADDR:
     case Instruction::DIV_LONG_2ADDR:
     case Instruction::REM_LONG_2ADDR:
-      GenArithOpLong(opcode, rl_dest, rl_src[0], rl_src[1]);
+      GenArithOpLong(opcode, rl_dest, rl_src[0], rl_src[1], opt_flags);
       break;
 
     case Instruction::SHL_LONG:
@@ -1049,34 +927,42 @@
     case Instruction::SHR_LONG_2ADDR:
     case Instruction::USHR_LONG_2ADDR:
       if (rl_src[1].is_const) {
-        GenShiftImmOpLong(opcode, rl_dest, rl_src[0], rl_src[1]);
+        GenShiftImmOpLong(opcode, rl_dest, rl_src[0], rl_src[1], opt_flags);
       } else {
         GenShiftOpLong(opcode, rl_dest, rl_src[0], rl_src[1]);
       }
       break;
 
+    case Instruction::DIV_FLOAT:
+    case Instruction::DIV_FLOAT_2ADDR:
+      if (HandleEasyFloatingPointDiv(rl_dest, rl_src[0], rl_src[1])) {
+        break;
+      }
+      FALLTHROUGH_INTENDED;
     case Instruction::ADD_FLOAT:
     case Instruction::SUB_FLOAT:
     case Instruction::MUL_FLOAT:
-    case Instruction::DIV_FLOAT:
     case Instruction::REM_FLOAT:
     case Instruction::ADD_FLOAT_2ADDR:
     case Instruction::SUB_FLOAT_2ADDR:
     case Instruction::MUL_FLOAT_2ADDR:
-    case Instruction::DIV_FLOAT_2ADDR:
     case Instruction::REM_FLOAT_2ADDR:
       GenArithOpFloat(opcode, rl_dest, rl_src[0], rl_src[1]);
       break;
 
+    case Instruction::DIV_DOUBLE:
+    case Instruction::DIV_DOUBLE_2ADDR:
+      if (HandleEasyFloatingPointDiv(rl_dest, rl_src[0], rl_src[1])) {
+        break;
+      }
+      FALLTHROUGH_INTENDED;
     case Instruction::ADD_DOUBLE:
     case Instruction::SUB_DOUBLE:
     case Instruction::MUL_DOUBLE:
-    case Instruction::DIV_DOUBLE:
     case Instruction::REM_DOUBLE:
     case Instruction::ADD_DOUBLE_2ADDR:
     case Instruction::SUB_DOUBLE_2ADDR:
     case Instruction::MUL_DOUBLE_2ADDR:
-    case Instruction::DIV_DOUBLE_2ADDR:
     case Instruction::REM_DOUBLE_2ADDR:
       GenArithOpDouble(opcode, rl_dest, rl_src[0], rl_src[1]);
       break;
@@ -1119,18 +1005,33 @@
       break;
     }
     case kMirOpFusedCmplFloat:
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(mir->optimization_flags);
+      }
       GenFusedFPCmpBranch(bb, mir, false /*gt bias*/, false /*double*/);
       break;
     case kMirOpFusedCmpgFloat:
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(mir->optimization_flags);
+      }
       GenFusedFPCmpBranch(bb, mir, true /*gt bias*/, false /*double*/);
       break;
     case kMirOpFusedCmplDouble:
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(mir->optimization_flags);
+      }
       GenFusedFPCmpBranch(bb, mir, false /*gt bias*/, true /*double*/);
       break;
     case kMirOpFusedCmpgDouble:
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(mir->optimization_flags);
+      }
       GenFusedFPCmpBranch(bb, mir, true /*gt bias*/, true /*double*/);
       break;
     case kMirOpFusedCmpLong:
+      if (mir_graph_->IsBackEdge(bb, bb->taken) || mir_graph_->IsBackEdge(bb, bb->fall_through)) {
+        GenSuspendTest(mir->optimization_flags);
+      }
       GenFusedLongCmpBranch(bb, mir);
       break;
     case kMirOpSelect:
@@ -1234,7 +1135,8 @@
     if (opcode == kMirOpCheck) {
       // Combine check and work halves of throwing instruction.
       MIR* work_half = mir->meta.throw_insn;
-      mir->dalvikInsn.opcode = work_half->dalvikInsn.opcode;
+      mir->dalvikInsn = work_half->dalvikInsn;
+      mir->optimization_flags = work_half->optimization_flags;
       mir->meta = work_half->meta;  // Whatever the work_half had, we need to copy it.
       opcode = work_half->dalvikInsn.opcode;
       SSARepresentation* ssa_rep = work_half->ssa_rep;
@@ -1377,8 +1279,40 @@
 }
 
 size_t Mir2Lir::GetInstructionOffset(LIR* lir) {
-  UNIMPLEMENTED(FATAL) << "Unsuppored GetInstructionOffset()";
-  return 0;
+  UNUSED(lir);
+  UNIMPLEMENTED(FATAL) << "Unsupported GetInstructionOffset()";
+  UNREACHABLE();
+}
+
+void Mir2Lir::InToRegStorageMapping::Initialize(ShortyIterator* shorty,
+                                                InToRegStorageMapper* mapper) {
+  DCHECK(mapper != nullptr);
+  DCHECK(shorty != nullptr);
+  max_mapped_in_ = -1;
+  has_arguments_on_stack_ = false;
+  while (shorty->Next()) {
+     ShortyArg arg = shorty->GetArg();
+     RegStorage reg = mapper->GetNextReg(arg);
+     if (reg.Valid()) {
+       mapping_.Put(count_, reg);
+       max_mapped_in_ = count_;
+       // If the VR is wide and was mapped as wide then account for it.
+       if (arg.IsWide() && reg.Is64Bit()) {
+         max_mapped_in_++;
+       }
+     } else {
+       has_arguments_on_stack_ = true;
+     }
+     count_ += arg.IsWide() ? 2 : 1;
+  }
+  initialized_ = true;
+}
+
+RegStorage Mir2Lir::InToRegStorageMapping::Get(int in_position) {
+  DCHECK(IsInitialized());
+  DCHECK_LT(in_position, count_);
+  auto res = mapping_.find(in_position);
+  return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 67a8c0f..fabf941 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -17,7 +17,7 @@
 #ifndef ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
 #define ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
 
-#include "invoke_type.h"
+#include "arch/instruction_set.h"
 #include "compiled_method.h"
 #include "dex/compiler_enums.h"
 #include "dex/compiler_ir.h"
@@ -26,13 +26,14 @@
 #include "dex/backend.h"
 #include "dex/quick/resource_mask.h"
 #include "driver/compiler_driver.h"
-#include "instruction_set.h"
-#include "leb128.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "invoke_type.h"
+#include "leb128.h"
 #include "safe_map.h"
 #include "utils/array_ref.h"
 #include "utils/arena_allocator.h"
 #include "utils/arena_containers.h"
+#include "utils/arena_object.h"
 #include "utils/stack_checks.h"
 
 namespace art {
@@ -129,11 +130,11 @@
 #define INVALID_SREG (-1)
 #endif
 
-struct BasicBlock;
+class BasicBlock;
 struct CallInfo;
 struct CompilationUnit;
 struct InlineMethod;
-struct MIR;
+class MIR;
 struct LIR;
 struct RegisterInfo;
 class DexFileMethodInliner;
@@ -318,13 +319,10 @@
      * Working plan is, for all targets, to follow mechanism 1 for 64-bit core registers, and
      * mechanism 2 for aliased float registers and x86 vector registers.
      */
-    class RegisterInfo {
+    class RegisterInfo : public ArenaObject<kArenaAllocRegAlloc> {
      public:
       RegisterInfo(RegStorage r, const ResourceMask& mask = kEncodeAll);
       ~RegisterInfo() {}
-      static void* operator new(size_t size, ArenaAllocator* arena) {
-        return arena->Alloc(size, kArenaAllocRegAlloc);
-      }
 
       static const uint32_t k32SoloStorageMask     = 0x00000001;
       static const uint32_t kLowSingleStorageMask  = 0x00000001;
@@ -420,7 +418,7 @@
       RegisterInfo* alias_chain_;  // Chain of aliased registers.
     };
 
-    class RegisterPool {
+    class RegisterPool : public DeletableArenaObject<kArenaAllocRegAlloc> {
      public:
       RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena,
                    const ArrayRef<const RegStorage>& core_regs,
@@ -434,10 +432,6 @@
                    const ArrayRef<const RegStorage>& sp_temps,
                    const ArrayRef<const RegStorage>& dp_temps);
       ~RegisterPool() {}
-      static void* operator new(size_t size, ArenaAllocator* arena) {
-        return arena->Alloc(size, kArenaAllocRegAlloc);
-      }
-      static void operator delete(void* ptr) { UNUSED(ptr); }
       void ResetNextTemp() {
         next_core_reg_ = 0;
         next_sp_reg_ = 0;
@@ -501,20 +495,15 @@
     // has completed.
     //
 
-    class LIRSlowPath {
+    class LIRSlowPath : public ArenaObject<kArenaAllocSlowPaths> {
      public:
       LIRSlowPath(Mir2Lir* m2l, const DexOffset dexpc, LIR* fromfast,
                   LIR* cont = nullptr) :
         m2l_(m2l), cu_(m2l->cu_), current_dex_pc_(dexpc), fromfast_(fromfast), cont_(cont) {
-          m2l->StartSlowPath(this);
       }
       virtual ~LIRSlowPath() {}
       virtual void Compile() = 0;
 
-      static void* operator new(size_t size, ArenaAllocator* arena) {
-        return arena->Alloc(size, kArenaAllocData);
-      }
-
       LIR *GetContinuationLabel() {
         return cont_;
       }
@@ -677,7 +666,6 @@
     void MarkBoundary(DexOffset offset, const char* inst_str);
     void NopLIR(LIR* lir);
     void UnlinkLIR(LIR* lir);
-    bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
     bool IsInexpensiveConstant(RegLocation rl_src);
     ConditionCode FlipComparisonOrder(ConditionCode before);
     ConditionCode NegateComparison(ConditionCode before);
@@ -691,14 +679,9 @@
     int AssignSwitchTablesOffset(CodeOffset offset);
     int AssignFillArrayDataOffset(CodeOffset offset);
     virtual LIR* InsertCaseLabel(DexOffset vaddr, int keyVal);
-    void MarkPackedCaseLabels(Mir2Lir::SwitchTable* tab_rec);
+    virtual void MarkPackedCaseLabels(Mir2Lir::SwitchTable* tab_rec);
     void MarkSparseCaseLabels(Mir2Lir::SwitchTable* tab_rec);
 
-    virtual void StartSlowPath(LIRSlowPath* slowpath) {}
-    virtual void BeginInvoke(CallInfo* info) {}
-    virtual void EndInvoke(CallInfo* info) {}
-
-
     // Handle bookkeeping to convert a wide RegLocation to a narrow RegLocation.  No code generated.
     virtual RegLocation NarrowRegLoc(RegLocation loc);
 
@@ -805,6 +788,7 @@
     virtual bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                   RegLocation rl_src, RegLocation rl_dest, int lit);
     bool HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit);
+    bool HandleEasyFloatingPointDiv(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
     virtual void HandleSlowPaths();
     void GenBarrier();
     void GenDivZeroException();
@@ -822,16 +806,17 @@
     LIR* GenNullCheck(RegStorage m_reg, int opt_flags);
     LIR* GenExplicitNullCheck(RegStorage m_reg, int opt_flags);
     virtual void GenImplicitNullCheck(RegStorage reg, int opt_flags);
-    void GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
-                             RegLocation rl_src2, LIR* taken, LIR* fall_through);
-    void GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src,
-                                 LIR* taken, LIR* fall_through);
+    void GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1, RegLocation rl_src2,
+                             LIR* taken);
+    void GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken);
     virtual void GenIntToLong(RegLocation rl_dest, RegLocation rl_src);
+    virtual void GenLongToInt(RegLocation rl_dest, RegLocation rl_src);
     void GenIntNarrowing(Instruction::Code opcode, RegLocation rl_dest,
                          RegLocation rl_src);
     void GenNewArray(uint32_t type_idx, RegLocation rl_dest,
                      RegLocation rl_src);
     void GenFilledNewArray(CallInfo* info);
+    void GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenSput(MIR* mir, RegLocation rl_src, OpSize size);
     // Get entrypoints are specific for types, size alone is not sufficient to safely infer
     // entrypoint.
@@ -856,15 +841,15 @@
     void GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest,
                           RegLocation rl_src, int lit);
     virtual void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                RegLocation rl_src1, RegLocation rl_src2);
+                                RegLocation rl_src1, RegLocation rl_src2, int flags);
     void GenConversionCall(QuickEntrypointEnum trampoline, RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenSuspendTest(int opt_flags);
-    virtual void GenSuspendTestAndBranch(int opt_flags, LIR* target);
+    void GenSuspendTest(int opt_flags);
+    void GenSuspendTestAndBranch(int opt_flags, LIR* target);
 
     // This will be overridden by x86 implementation.
     virtual void GenConstWide(RegLocation rl_dest, int64_t value);
     virtual void GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
-                       RegLocation rl_src1, RegLocation rl_src2);
+                       RegLocation rl_src1, RegLocation rl_src2, int flags);
 
     // Shared by all targets - implemented in gen_invoke.cc.
     LIR* CallHelper(RegStorage r_tgt, QuickEntrypointEnum trampoline, bool safepoint_pc,
@@ -889,17 +874,17 @@
     void CallRuntimeHelperImmMethod(QuickEntrypointEnum trampoline, int arg0, bool safepoint_pc);
     void CallRuntimeHelperRegMethod(QuickEntrypointEnum trampoline, RegStorage arg0,
                                     bool safepoint_pc);
-    void CallRuntimeHelperRegMethodRegLocation(QuickEntrypointEnum trampoline, RegStorage arg0,
-                                               RegLocation arg2, bool safepoint_pc);
+    void CallRuntimeHelperRegRegLocationMethod(QuickEntrypointEnum trampoline, RegStorage arg0,
+                                               RegLocation arg1, bool safepoint_pc);
     void CallRuntimeHelperRegLocationRegLocation(QuickEntrypointEnum trampoline, RegLocation arg0,
                                                  RegLocation arg1, bool safepoint_pc);
     void CallRuntimeHelperRegReg(QuickEntrypointEnum trampoline, RegStorage arg0, RegStorage arg1,
                                  bool safepoint_pc);
     void CallRuntimeHelperRegRegImm(QuickEntrypointEnum trampoline, RegStorage arg0,
                                     RegStorage arg1, int arg2, bool safepoint_pc);
-    void CallRuntimeHelperImmMethodRegLocation(QuickEntrypointEnum trampoline, int arg0,
-                                               RegLocation arg2, bool safepoint_pc);
-    void CallRuntimeHelperImmMethodImm(QuickEntrypointEnum trampoline, int arg0, int arg2,
+    void CallRuntimeHelperImmRegLocationMethod(QuickEntrypointEnum trampoline, int arg0,
+                                               RegLocation arg1, bool safepoint_pc);
+    void CallRuntimeHelperImmImmMethod(QuickEntrypointEnum trampoline, int arg0, int arg1,
                                        bool safepoint_pc);
     void CallRuntimeHelperImmRegLocationRegLocation(QuickEntrypointEnum trampoline, int arg0,
                                                     RegLocation arg1, RegLocation arg2,
@@ -910,29 +895,24 @@
                                                             bool safepoint_pc);
     void GenInvoke(CallInfo* info);
     void GenInvokeNoInline(CallInfo* info);
-    virtual NextCallInsn GetNextSDCallInsn();
+    virtual NextCallInsn GetNextSDCallInsn() = 0;
 
     /*
      * @brief Generate the actual call insn based on the method info.
      * @param method_info the lowering info for the method call.
      * @returns Call instruction
      */
-    virtual LIR* GenCallInsn(const MirMethodLoweringInfo& method_info);
+    virtual LIR* GenCallInsn(const MirMethodLoweringInfo& method_info) = 0;
 
     virtual void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                             NextCallInsn next_call_insn,
-                             const MethodReference& target_method,
-                             uint32_t vtable_idx,
-                             uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                             bool skip_this);
-    virtual int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                           NextCallInsn next_call_insn,
-                           const MethodReference& target_method,
-                           uint32_t vtable_idx,
-                           uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                           bool skip_this);
-
+    virtual int GenDalvikArgs(CallInfo* info, int call_state, LIR** pcrLabel,
+                      NextCallInsn next_call_insn,
+                      const MethodReference& target_method,
+                      uint32_t vtable_idx,
+                      uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
+                      bool skip_this);
+    virtual int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count);
+    virtual void GenDalvikArgsFlushPromoted(CallInfo* info, int start);
     /**
      * @brief Used to determine the register location of destination.
      * @details This is needed during generation of inline intrinsics because it finds destination
@@ -973,43 +953,31 @@
     bool GenInlinedUnsafeGet(CallInfo* info, bool is_long, bool is_volatile);
     bool GenInlinedUnsafePut(CallInfo* info, bool is_long, bool is_object,
                              bool is_volatile, bool is_ordered);
-    virtual int LoadArgRegs(CallInfo* info, int call_state,
-                    NextCallInsn next_call_insn,
-                    const MethodReference& target_method,
-                    uint32_t vtable_idx,
-                    uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                    bool skip_this);
 
     // Shared by all targets - implemented in gen_loadstore.cc.
     RegLocation LoadCurrMethod();
     void LoadCurrMethodDirect(RegStorage r_tgt);
     virtual LIR* LoadConstant(RegStorage r_dest, int value);
     // Natural word size.
-    virtual LIR* LoadWordDisp(RegStorage r_base, int displacement, RegStorage r_dest) {
+    LIR* LoadWordDisp(RegStorage r_base, int displacement, RegStorage r_dest) {
       return LoadBaseDisp(r_base, displacement, r_dest, kWord, kNotVolatile);
     }
-    // Load 8 bits, regardless of target.
-    virtual LIR* Load8Disp(RegStorage r_base, int displacement, RegStorage r_dest) {
-      return LoadBaseDisp(r_base, displacement, r_dest, kSignedByte, kNotVolatile);
-    }
     // Load 32 bits, regardless of target.
-    virtual LIR* Load32Disp(RegStorage r_base, int displacement, RegStorage r_dest)  {
+    LIR* Load32Disp(RegStorage r_base, int displacement, RegStorage r_dest)  {
       return LoadBaseDisp(r_base, displacement, r_dest, k32, kNotVolatile);
     }
     // Load a reference at base + displacement and decompress into register.
-    virtual LIR* LoadRefDisp(RegStorage r_base, int displacement, RegStorage r_dest,
+    LIR* LoadRefDisp(RegStorage r_base, int displacement, RegStorage r_dest,
                              VolatileKind is_volatile) {
       return LoadBaseDisp(r_base, displacement, r_dest, kReference, is_volatile);
     }
     // Load a reference at base + index and decompress into register.
-    virtual LIR* LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
+    LIR* LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
                                 int scale) {
       return LoadBaseIndexed(r_base, r_index, r_dest, scale, kReference);
     }
     // Load Dalvik value with 32-bit memory storage.  If compressed object reference, decompress.
     virtual RegLocation LoadValue(RegLocation rl_src, RegisterClass op_kind);
-    // Same as above, but derive the target register class from the location record.
-    virtual RegLocation LoadValue(RegLocation rl_src);
     // Load Dalvik value with 64-bit memory storage.
     virtual RegLocation LoadValueWide(RegLocation rl_src, RegisterClass op_kind);
     // Load Dalvik value with 32-bit memory storage.  If compressed object reference, decompress.
@@ -1021,21 +989,21 @@
     // Load Dalvik value with 64-bit memory storage.
     virtual void LoadValueDirectWideFixed(RegLocation rl_src, RegStorage r_dest);
     // Store an item of natural word size.
-    virtual LIR* StoreWordDisp(RegStorage r_base, int displacement, RegStorage r_src) {
+    LIR* StoreWordDisp(RegStorage r_base, int displacement, RegStorage r_src) {
       return StoreBaseDisp(r_base, displacement, r_src, kWord, kNotVolatile);
     }
     // Store an uncompressed reference into a compressed 32-bit container.
-    virtual LIR* StoreRefDisp(RegStorage r_base, int displacement, RegStorage r_src,
+    LIR* StoreRefDisp(RegStorage r_base, int displacement, RegStorage r_src,
                               VolatileKind is_volatile) {
       return StoreBaseDisp(r_base, displacement, r_src, kReference, is_volatile);
     }
     // Store an uncompressed reference into a compressed 32-bit container by index.
-    virtual LIR* StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
+    LIR* StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                  int scale) {
       return StoreBaseIndexed(r_base, r_index, r_src, scale, kReference);
     }
     // Store 32 bits, regardless of target.
-    virtual LIR* Store32Disp(RegStorage r_base, int displacement, RegStorage r_src) {
+    LIR* Store32Disp(RegStorage r_base, int displacement, RegStorage r_src) {
       return StoreBaseDisp(r_base, displacement, r_src, k32, kNotVolatile);
     }
 
@@ -1088,6 +1056,14 @@
     // Update LIR for verbose listings.
     void UpdateLIROffsets();
 
+    /**
+     * @brief Mark a garbage collection card. Skip if the stored value is null.
+     * @param val_reg the register holding the stored value to check against null.
+     * @param tgt_addr_reg the address of the object or array where the value was stored.
+     * @param opt_flags the optimization flags which may indicate that the value is non-null.
+     */
+    void MarkGCCard(int opt_flags, RegStorage val_reg, RegStorage tgt_addr_reg);
+
     /*
      * @brief Load the address of the dex method into the register.
      * @param target_method The MethodReference of the method to be invoked.
@@ -1138,6 +1114,10 @@
     virtual bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
     virtual bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
+    virtual void GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                            int32_t constant) = 0;
+    virtual void GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                             int64_t constant) = 0;
     virtual LIR* CheckSuspendUsingLoad() = 0;
 
     virtual RegStorage LoadHelper(QuickEntrypointEnum trampoline) = 0;
@@ -1152,7 +1132,12 @@
                                OpSize size, VolatileKind is_volatile) = 0;
     virtual LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                   int scale, OpSize size) = 0;
-    virtual void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) = 0;
+
+    /**
+     * @brief Unconditionally mark a garbage collection card.
+     * @param tgt_addr_reg the address of the object or array where the value was stored.
+     */
+    virtual void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) = 0;
 
     // Required for target - register utilities.
 
@@ -1192,14 +1177,18 @@
      */
     virtual RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) {
       if (wide_kind == kWide) {
-        DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg7) || (kRet0 == reg));
-        COMPILE_ASSERT((kArg1 == kArg0 + 1) && (kArg2 == kArg1 + 1) && (kArg3 == kArg2 + 1) &&
-                       (kArg4 == kArg3 + 1) && (kArg5 == kArg4 + 1) && (kArg6 == kArg5 + 1) &&
-                       (kArg7 == kArg6 + 1), kargs_range_unexpected);
-        COMPILE_ASSERT((kFArg1 == kFArg0 + 1) && (kFArg2 == kFArg1 + 1) && (kFArg3 == kFArg2 + 1) &&
-                       (kFArg4 == kFArg3 + 1) && (kFArg5 == kFArg4 + 1) && (kFArg6 == kFArg5 + 1) &&
-                       (kFArg7 == kFArg6 + 1), kfargs_range_unexpected);
-        COMPILE_ASSERT(kRet1 == kRet0 + 1, kret_range_unexpected);
+        DCHECK((kArg0 <= reg && reg < kArg7) || (kFArg0 <= reg && reg < kFArg15) || (kRet0 == reg));
+        static_assert((kArg1 == kArg0 + 1) && (kArg2 == kArg1 + 1) && (kArg3 == kArg2 + 1) &&
+                      (kArg4 == kArg3 + 1) && (kArg5 == kArg4 + 1) && (kArg6 == kArg5 + 1) &&
+                      (kArg7 == kArg6 + 1), "kargs range unexpected");
+        static_assert((kFArg1 == kFArg0 + 1) && (kFArg2 == kFArg1 + 1) && (kFArg3 == kFArg2 + 1) &&
+                      (kFArg4 == kFArg3 + 1) && (kFArg5 == kFArg4 + 1) && (kFArg6 == kFArg5 + 1) &&
+                      (kFArg7 == kFArg6 + 1) && (kFArg8 == kFArg7 + 1) && (kFArg9 == kFArg8 + 1) &&
+                      (kFArg10 == kFArg9 + 1) && (kFArg11 == kFArg10 + 1) &&
+                      (kFArg12 == kFArg11 + 1) && (kFArg13 == kFArg12 + 1) &&
+                      (kFArg14 == kFArg13 + 1) && (kFArg15 == kFArg14 + 1),
+                      "kfargs range unexpected");
+        static_assert(kRet1 == kRet0 + 1, "kret range unexpected");
         return RegStorage::MakeRegPair(TargetReg(reg),
                                        TargetReg(static_cast<SpecialTargetRegister>(reg + 1)));
       } else {
@@ -1224,7 +1213,7 @@
       }
     }
 
-    virtual RegStorage GetArgMappingToPhysicalReg(int arg_num) = 0;
+    RegStorage GetArgMappingToPhysicalReg(int arg_num);
     virtual RegLocation GetReturnAlt() = 0;
     virtual RegLocation GetReturnWideAlt() = 0;
     virtual RegLocation LocCReturn() = 0;
@@ -1260,7 +1249,7 @@
 
     // Required for target - Dalvik-level generators.
     virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src1, RegLocation rl_src2) = 0;
+                                   RegLocation rl_src1, RegLocation rl_src2, int flags) = 0;
     virtual void GenArithOpDouble(Instruction::Code opcode,
                                   RegLocation rl_dest, RegLocation rl_src1,
                                   RegLocation rl_src2) = 0;
@@ -1298,10 +1287,11 @@
      * @param rl_src1 Numerator Location.
      * @param rl_src2 Divisor Location.
      * @param is_div 'true' if this is a division, 'false' for a remainder.
-     * @param check_zero 'true' if an exception should be generated if the divisor is 0.
+     * @param flags The instruction optimization flags. It can include information
+     * if exception check can be elided.
      */
     virtual RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                                  RegLocation rl_src2, bool is_div, bool check_zero) = 0;
+                                  RegLocation rl_src2, bool is_div, int flags) = 0;
     /*
      * @brief Generate an integer div or rem operation by a literal.
      * @param rl_dest Destination Location.
@@ -1323,7 +1313,6 @@
 
     virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) = 0;
     virtual void GenExitSequence() = 0;
-    virtual void GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) = 0;
     virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) = 0;
     virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) = 0;
 
@@ -1347,7 +1336,7 @@
      */
     virtual void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                                   int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                                  int dest_reg_class) = 0;
+                                  RegisterClass dest_reg_class) = 0;
 
     /**
      * @brief Used to generate a memory barrier in an architecture specific way.
@@ -1384,7 +1373,7 @@
                              RegLocation rl_index, RegLocation rl_src, int scale,
                              bool card_mark) = 0;
     virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src1, RegLocation rl_shift) = 0;
+                                   RegLocation rl_src1, RegLocation rl_shift, int flags) = 0;
 
     // Required for target - single operation generators.
     virtual LIR* OpUnconditionalBranch(LIR* target) = 0;
@@ -1449,9 +1438,30 @@
     virtual bool InexpensiveConstantLong(int64_t value) = 0;
     virtual bool InexpensiveConstantDouble(int64_t value) = 0;
     virtual bool InexpensiveConstantInt(int32_t value, Instruction::Code opcode) {
+      UNUSED(opcode);
       return InexpensiveConstantInt(value);
     }
 
+    /**
+     * @brief Whether division by the given divisor can be converted to multiply by its reciprocal.
+     * @param divisor A constant divisor bits of float type.
+     * @return Returns true iff, x/divisor == x*(1.0f/divisor), for every float x.
+     */
+    bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) {
+      // True, if float value significand bits are 0.
+      return ((divisor & 0x7fffff) == 0);
+    }
+
+    /**
+     * @brief Whether division by the given divisor can be converted to multiply by its reciprocal.
+     * @param divisor A constant divisor bits of double type.
+     * @return Returns true iff, x/divisor == x*(1.0/divisor), for every double x.
+     */
+    bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) {
+      // True, if double value significand bits are 0.
+      return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0);
+    }
+
     // May be optimized by targets.
     virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
     virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
@@ -1468,18 +1478,6 @@
       return cu_;
     }
     /*
-     * @brief Returns the index of the lowest set bit in 'x'.
-     * @param x Value to be examined.
-     * @returns The bit number of the lowest bit set in the value.
-     */
-    int32_t LowestSetBit(uint64_t x);
-    /*
-     * @brief Is this value a power of two?
-     * @param x Value to be examined.
-     * @returns 'true' if only 1 bit is set in the value.
-     */
-    bool IsPowerOfTwo(uint64_t x);
-    /*
      * @brief Do these SRs overlap?
      * @param rl_op1 One RegLocation
      * @param rl_op2 The other RegLocation
@@ -1489,7 +1487,18 @@
      * is not usual for dx to generate, but it is legal (for now).  In a future rev of
      * dex, we'll want to make this case illegal.
      */
-    bool BadOverlap(RegLocation rl_op1, RegLocation rl_op2);
+    bool PartiallyIntersects(RegLocation rl_op1, RegLocation rl_op2);
+
+    /*
+     * @brief Do these SRs intersect?
+     * @param rl_op1 One RegLocation
+     * @param rl_op2 The other RegLocation
+     * @return 'true' if the VR pairs intersect
+     *
+     * Check to see if a result pair has misaligned overlap or
+     * full overlap with an operand pair.
+     */
+    bool Intersects(RegLocation rl_op1, RegLocation rl_op2);
 
     /*
      * @brief Force a location (in a register) into a temporary register
@@ -1628,12 +1637,12 @@
     /**
      * Returns true iff wide GPRs are just different views on the same physical register.
      */
-    virtual bool WideGPRsAreAliases() = 0;
+    virtual bool WideGPRsAreAliases() const = 0;
 
     /**
      * Returns true iff wide FPRs are just different views on the same physical register.
      */
-    virtual bool WideFPRsAreAliases() = 0;
+    virtual bool WideFPRsAreAliases() const = 0;
 
 
     enum class WidenessCheck {  // private
@@ -1716,7 +1725,7 @@
     int live_sreg_;
     CodeBuffer code_buffer_;
     // The source mapping table data (pc -> dex). More entries than in encoded_mapping_table_
-    SrcMap src_mapping_table_;
+    DefaultSrcMap src_mapping_table_;
     // The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix.
     std::vector<uint8_t> encoded_mapping_table_;
     ArenaVector<uint32_t> core_vmap_table_;
@@ -1744,6 +1753,63 @@
     // to deduplicate the masks.
     ResourceMaskCache mask_cache_;
 
+  protected:
+    // ABI support
+    class ShortyArg {
+      public:
+        explicit ShortyArg(char type) : type_(type) { }
+        bool IsFP() { return type_ == 'F' || type_ == 'D'; }
+        bool IsWide() { return type_ == 'J' || type_ == 'D'; }
+        bool IsRef() { return type_ == 'L'; }
+        char GetType() { return type_; }
+      private:
+        char type_;
+    };
+
+    class ShortyIterator {
+      public:
+        ShortyIterator(const char* shorty, bool is_static);
+        bool Next();
+        ShortyArg GetArg() { return ShortyArg(pending_this_ ? 'L' : *cur_); }
+      private:
+        const char* cur_;
+        bool pending_this_;
+        bool initialized_;
+    };
+
+    class InToRegStorageMapper {
+     public:
+      virtual RegStorage GetNextReg(ShortyArg arg) = 0;
+      virtual ~InToRegStorageMapper() {}
+      virtual void Reset() = 0;
+    };
+
+    class InToRegStorageMapping {
+     public:
+      explicit InToRegStorageMapping(ArenaAllocator* arena)
+          : mapping_(std::less<int>(), arena->Adapter()), count_(0),
+            max_mapped_in_(0), has_arguments_on_stack_(false),  initialized_(false) {}
+      void Initialize(ShortyIterator* shorty, InToRegStorageMapper* mapper);
+      /**
+       * @return the index of last VR mapped to physical register. In other words
+       * any VR starting from (return value + 1) index is mapped to memory.
+       */
+      int GetMaxMappedIn() { return max_mapped_in_; }
+      bool HasArgumentsOnStack() { return has_arguments_on_stack_; }
+      RegStorage Get(int in_position);
+      bool IsInitialized() { return initialized_; }
+     private:
+      ArenaSafeMap<int, RegStorage> mapping_;
+      int count_;
+      int max_mapped_in_;
+      bool has_arguments_on_stack_;
+      bool initialized_;
+    };
+
+  // Cached mapping of method input to reg storage according to ABI.
+  InToRegStorageMapping in_to_reg_storage_mapping_;
+  virtual InToRegStorageMapper* GetResetedInToRegStorageMapper() = 0;
+
   private:
     static bool SizeMatchesTypeForEntrypoint(OpSize size, Primitive::Type type);
 };  // Class Mir2Lir
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index 6f2a647..102ce17 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -19,6 +19,7 @@
 #include <cstdint>
 
 #include "compiler.h"
+#include "dex_file-inl.h"
 #include "dex/frontend.h"
 #include "dex/mir_graph.h"
 #include "dex/quick/mir_to_lir.h"
@@ -40,7 +41,7 @@
  public:
   explicit QuickCompiler(CompilerDriver* driver) : Compiler(driver, 100) {}
 
-  void Init() const OVERRIDE;
+  void Init() OVERRIDE;
 
   void UnInit() const OVERRIDE;
 
@@ -78,14 +79,14 @@
   DISALLOW_COPY_AND_ASSIGN(QuickCompiler);
 };
 
-COMPILE_ASSERT(0U == static_cast<size_t>(kNone), kNone_not_0);
-COMPILE_ASSERT(1U == static_cast<size_t>(kArm), kArm_not_1);
-COMPILE_ASSERT(2U == static_cast<size_t>(kArm64), kArm64_not_2);
-COMPILE_ASSERT(3U == static_cast<size_t>(kThumb2), kThumb2_not_3);
-COMPILE_ASSERT(4U == static_cast<size_t>(kX86), kX86_not_4);
-COMPILE_ASSERT(5U == static_cast<size_t>(kX86_64), kX86_64_not_5);
-COMPILE_ASSERT(6U == static_cast<size_t>(kMips), kMips_not_6);
-COMPILE_ASSERT(7U == static_cast<size_t>(kMips64), kMips64_not_7);
+static_assert(0U == static_cast<size_t>(kNone),   "kNone not 0");
+static_assert(1U == static_cast<size_t>(kArm),    "kArm not 1");
+static_assert(2U == static_cast<size_t>(kArm64),  "kArm64 not 2");
+static_assert(3U == static_cast<size_t>(kThumb2), "kThumb2 not 3");
+static_assert(4U == static_cast<size_t>(kX86),    "kX86 not 4");
+static_assert(5U == static_cast<size_t>(kX86_64), "kX86_64 not 5");
+static_assert(6U == static_cast<size_t>(kMips),   "kMips not 6");
+static_assert(7U == static_cast<size_t>(kMips64), "kMips64 not 7");
 
 // Additional disabled optimizations (over generally disabled) per instruction set.
 static constexpr uint32_t kDisabledOptimizationsPerISA[] = {
@@ -118,7 +119,8 @@
     // 7 = kMips64.
     ~0U
 };
-COMPILE_ASSERT(sizeof(kDisabledOptimizationsPerISA) == 8 * sizeof(uint32_t), kDisabledOpts_unexp);
+static_assert(sizeof(kDisabledOptimizationsPerISA) == 8 * sizeof(uint32_t),
+              "kDisabledOpts unexpected");
 
 // Supported shorty types per instruction set. nullptr means that all are available.
 // Z : boolean
@@ -149,7 +151,7 @@
     // 7 = kMips64.
     ""
 };
-COMPILE_ASSERT(sizeof(kSupportedTypes) == 8 * sizeof(char*), kSupportedTypes_unexp);
+static_assert(sizeof(kSupportedTypes) == 8 * sizeof(char*), "kSupportedTypes unexpected");
 
 static int kAllOpcodes[] = {
     Instruction::NOP,
@@ -391,10 +393,10 @@
     Instruction::IPUT_BYTE_QUICK,
     Instruction::IPUT_CHAR_QUICK,
     Instruction::IPUT_SHORT_QUICK,
-    Instruction::UNUSED_EF,
-    Instruction::UNUSED_F0,
-    Instruction::UNUSED_F1,
-    Instruction::UNUSED_F2,
+    Instruction::IGET_BOOLEAN_QUICK,
+    Instruction::IGET_BYTE_QUICK,
+    Instruction::IGET_CHAR_QUICK,
+    Instruction::IGET_SHORT_QUICK,
     Instruction::UNUSED_F3,
     Instruction::UNUSED_F4,
     Instruction::UNUSED_F5,
@@ -425,6 +427,21 @@
     kMirOpSelect,
 };
 
+static int kInvokeOpcodes[] = {
+    Instruction::INVOKE_VIRTUAL,
+    Instruction::INVOKE_SUPER,
+    Instruction::INVOKE_DIRECT,
+    Instruction::INVOKE_STATIC,
+    Instruction::INVOKE_INTERFACE,
+    Instruction::INVOKE_VIRTUAL_RANGE,
+    Instruction::INVOKE_SUPER_RANGE,
+    Instruction::INVOKE_DIRECT_RANGE,
+    Instruction::INVOKE_STATIC_RANGE,
+    Instruction::INVOKE_INTERFACE_RANGE,
+    Instruction::INVOKE_VIRTUAL_QUICK,
+    Instruction::INVOKE_VIRTUAL_RANGE_QUICK,
+};
+
 // Unsupported opcodes. nullptr can be used when everything is supported. Size of the lists is
 // recorded below.
 static const int* kUnsupportedOpcodes[] = {
@@ -445,7 +462,7 @@
     // 7 = kMips64.
     kAllOpcodes
 };
-COMPILE_ASSERT(sizeof(kUnsupportedOpcodes) == 8 * sizeof(int*), kUnsupportedOpcodes_unexp);
+static_assert(sizeof(kUnsupportedOpcodes) == 8 * sizeof(int*), "kUnsupportedOpcodes unexpected");
 
 // Size of the arrays stored above.
 static const size_t kUnsupportedOpcodesSize[] = {
@@ -466,8 +483,8 @@
     // 7 = kMips64.
     arraysize(kAllOpcodes),
 };
-COMPILE_ASSERT(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t),
-               kUnsupportedOpcodesSize_unexp);
+static_assert(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t),
+              "kUnsupportedOpcodesSize unexpected");
 
 // The maximum amount of Dalvik register in a method for which we will start compiling. Tries to
 // avoid an abort when we need to manage more SSA registers than we can.
@@ -523,8 +540,8 @@
     for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
       int opcode = mir->dalvikInsn.opcode;
       // Check if we support the byte code.
-      if (std::find(unsupport_list, unsupport_list + unsupport_list_size,
-                    opcode) != unsupport_list + unsupport_list_size) {
+      if (std::find(unsupport_list, unsupport_list + unsupport_list_size, opcode)
+          != unsupport_list + unsupport_list_size) {
         if (!MIR::DecodedInstruction::IsPseudoMirOp(opcode)) {
           VLOG(compiler) << "Unsupported dalvik byte code : "
               << mir->dalvikInsn.opcode;
@@ -535,11 +552,8 @@
         return false;
       }
       // Check if it invokes a prototype that we cannot support.
-      if (Instruction::INVOKE_VIRTUAL == opcode ||
-          Instruction::INVOKE_SUPER == opcode ||
-          Instruction::INVOKE_DIRECT == opcode ||
-          Instruction::INVOKE_STATIC == opcode ||
-          Instruction::INVOKE_INTERFACE == opcode) {
+      if (std::find(kInvokeOpcodes, kInvokeOpcodes + arraysize(kInvokeOpcodes), opcode)
+          != kInvokeOpcodes + arraysize(kInvokeOpcodes)) {
         uint32_t invoke_method_idx = mir->dalvikInsn.vB;
         const char* invoke_method_shorty = dex_file.GetMethodShorty(
             dex_file.GetMethodId(invoke_method_idx));
@@ -560,7 +574,7 @@
   cu.disable_opt |= kDisabledOptimizationsPerISA[cu.instruction_set];
 }
 
-void QuickCompiler::Init() const {
+void QuickCompiler::Init() {
   CHECK(GetCompilerDriver()->GetCompilerContext() == nullptr);
 }
 
@@ -575,17 +589,6 @@
                                        uint32_t method_idx,
                                        jobject class_loader,
                                        const DexFile& dex_file) const {
-  CompiledMethod* method = TryCompileWithSeaIR(code_item,
-                                               access_flags,
-                                               invoke_type,
-                                               class_def_idx,
-                                               method_idx,
-                                               class_loader,
-                                               dex_file);
-  if (method != nullptr) {
-    return method;
-  }
-
   // TODO: check method fingerprint here to determine appropriate backend type.  Until then, use
   // build default.
   CompilerDriver* driver = GetCompilerDriver();
@@ -600,7 +603,8 @@
 }
 
 uintptr_t QuickCompiler::GetEntryPointOf(mirror::ArtMethod* method) const {
-  return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
+  return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize(
+      InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet())));
 }
 
 bool QuickCompiler::WriteElf(art::File* file,
@@ -613,6 +617,7 @@
 }
 
 Backend* QuickCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+  UNUSED(compilation_unit);
   Mir2Lir* mir_to_lir = nullptr;
   switch (cu->instruction_set) {
     case kThumb2:
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 6305b22..0a98c80 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -316,16 +316,16 @@
 
 // TODO: this is Thumb2 only.  Remove when DoPromotion refactored.
 RegStorage Mir2Lir::AllocPreservedDouble(int s_reg) {
-  RegStorage res;
+  UNUSED(s_reg);
   UNIMPLEMENTED(FATAL) << "Unexpected use of AllocPreservedDouble";
-  return res;
+  UNREACHABLE();
 }
 
 // TODO: this is Thumb2 only.  Remove when DoPromotion refactored.
 RegStorage Mir2Lir::AllocPreservedSingle(int s_reg) {
-  RegStorage res;
+  UNUSED(s_reg);
   UNIMPLEMENTED(FATAL) << "Unexpected use of AllocPreservedSingle";
-  return res;
+  UNREACHABLE();
 }
 
 
@@ -1392,6 +1392,7 @@
 }
 
 bool Mir2Lir::LiveOut(int s_reg) {
+  UNUSED(s_reg);
   // For now.
   return true;
 }
diff --git a/compiler/dex/quick/resource_mask.cc b/compiler/dex/quick/resource_mask.cc
index 17995fb..ca68f95 100644
--- a/compiler/dex/quick/resource_mask.cc
+++ b/compiler/dex/quick/resource_mask.cc
@@ -19,6 +19,7 @@
 #include "resource_mask.h"
 
 #include "utils/arena_allocator.h"
+#include "utils.h"
 
 namespace art {
 
@@ -33,16 +34,16 @@
     ResourceMask::Bit(ResourceMask::kCCode),
 };
 // The 127-bit is the same as CLZ(masks_[1]) for a ResourceMask with only that bit set.
-COMPILE_ASSERT(kNoRegMasks[127-ResourceMask::kHeapRef].Equals(
-    kEncodeHeapRef), check_kNoRegMasks_heap_ref_index);
-COMPILE_ASSERT(kNoRegMasks[127-ResourceMask::kLiteral].Equals(
-    kEncodeLiteral), check_kNoRegMasks_literal_index);
-COMPILE_ASSERT(kNoRegMasks[127-ResourceMask::kDalvikReg].Equals(
-    kEncodeDalvikReg), check_kNoRegMasks_dalvik_reg_index);
-COMPILE_ASSERT(kNoRegMasks[127-ResourceMask::kFPStatus].Equals(
-    ResourceMask::Bit(ResourceMask::kFPStatus)), check_kNoRegMasks_fp_status_index);
-COMPILE_ASSERT(kNoRegMasks[127-ResourceMask::kCCode].Equals(
-    ResourceMask::Bit(ResourceMask::kCCode)), check_kNoRegMasks_ccode_index);
+static_assert(kNoRegMasks[127-ResourceMask::kHeapRef].Equals(
+    kEncodeHeapRef), "kNoRegMasks heap ref index unexpected");
+static_assert(kNoRegMasks[127-ResourceMask::kLiteral].Equals(
+    kEncodeLiteral), "kNoRegMasks literal index unexpected");
+static_assert(kNoRegMasks[127-ResourceMask::kDalvikReg].Equals(
+    kEncodeDalvikReg), "kNoRegMasks dalvik reg index unexpected");
+static_assert(kNoRegMasks[127-ResourceMask::kFPStatus].Equals(
+    ResourceMask::Bit(ResourceMask::kFPStatus)), "kNoRegMasks fp status index unexpected");
+static_assert(kNoRegMasks[127-ResourceMask::kCCode].Equals(
+    ResourceMask::Bit(ResourceMask::kCCode)), "kNoRegMasks ccode index unexpected");
 
 template <size_t special_bit>
 constexpr ResourceMask OneRegOneSpecial(size_t reg) {
@@ -74,19 +75,19 @@
 }
 
 // The 127-bit is the same as CLZ(masks_[1]) for a ResourceMask with only that bit set.
-COMPILE_ASSERT(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kHeapRef, 0)].Equals(
-    OneRegOneSpecial<ResourceMask::kHeapRef>(0)), check_kSingleRegMasks_heap_ref_index);
-COMPILE_ASSERT(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kLiteral, 0)].Equals(
-    OneRegOneSpecial<ResourceMask::kLiteral>(0)), check_kSingleRegMasks_literal_index);
-COMPILE_ASSERT(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kDalvikReg, 0)].Equals(
-    OneRegOneSpecial<ResourceMask::kDalvikReg>(0)), check_kSingleRegMasks_dalvik_reg_index);
-COMPILE_ASSERT(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kFPStatus, 0)].Equals(
-    OneRegOneSpecial<ResourceMask::kFPStatus>(0)), check_kSingleRegMasks_fp_status_index);
-COMPILE_ASSERT(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kCCode, 0)].Equals(
-    OneRegOneSpecial<ResourceMask::kCCode>(0)), check_kSingleRegMasks_ccode_index);
+static_assert(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kHeapRef, 0)].Equals(
+    OneRegOneSpecial<ResourceMask::kHeapRef>(0)), "kSingleRegMasks heap ref index unexpected");
+static_assert(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kLiteral, 0)].Equals(
+    OneRegOneSpecial<ResourceMask::kLiteral>(0)), "kSingleRegMasks literal index  unexpected");
+static_assert(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kDalvikReg, 0)].Equals(
+    OneRegOneSpecial<ResourceMask::kDalvikReg>(0)), "kSingleRegMasks dalvik reg index unexpected");
+static_assert(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kFPStatus, 0)].Equals(
+    OneRegOneSpecial<ResourceMask::kFPStatus>(0)), "kSingleRegMasks fp status index unexpected");
+static_assert(kSingleRegMasks[SingleRegMaskIndex(127-ResourceMask::kCCode, 0)].Equals(
+    OneRegOneSpecial<ResourceMask::kCCode>(0)), "kSingleRegMasks ccode index unexpected");
 
 // NOTE: arraysize(kNoRegMasks) multiplied by 32 due to the gcc bug workaround, see above.
-COMPILE_ASSERT(arraysize(kSingleRegMasks) == arraysize(kNoRegMasks) * 32, check_arraysizes);
+static_assert(arraysize(kSingleRegMasks) == arraysize(kNoRegMasks) * 32, "arraysizes unexpected");
 
 constexpr ResourceMask kTwoRegsMasks[] = {
 #define TWO(a, b) ResourceMask::Bit(a).Union(ResourceMask::Bit(b))
@@ -115,7 +116,7 @@
         TWO(8, 15), TWO(9, 15), TWO(10, 15), TWO(11, 15), TWO(12, 15), TWO(13, 15), TWO(14, 15),
 #undef TWO
 };
-COMPILE_ASSERT(arraysize(kTwoRegsMasks) ==  16 * 15 / 2, check_arraysize_kTwoRegsMasks);
+static_assert(arraysize(kTwoRegsMasks) ==  16 * 15 / 2, "arraysize of kTwoRegsMasks unexpected");
 
 constexpr size_t TwoRegsIndex(size_t higher, size_t lower) {
   return (higher * (higher - 1)) / 2u + lower;
@@ -136,7 +137,7 @@
       (CheckTwoRegsMaskLine(lines - 1) && CheckTwoRegsMaskTable(lines - 1u));
 }
 
-COMPILE_ASSERT(CheckTwoRegsMaskTable(16), check_two_regs_masks_table);
+static_assert(CheckTwoRegsMaskTable(16), "two regs masks table check failed");
 
 }  // anonymous namespace
 
diff --git a/compiler/dex/quick/resource_mask.h b/compiler/dex/quick/resource_mask.h
index 436cdb5..78e81b2 100644
--- a/compiler/dex/quick/resource_mask.h
+++ b/compiler/dex/quick/resource_mask.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include "base/logging.h"
+#include "base/value_object.h"
 #include "dex/reg_storage.h"
 
 namespace art {
@@ -113,10 +114,7 @@
     return (masks_[0] & other.masks_[0]) != 0u || (masks_[1] & other.masks_[1]) != 0u;
   }
 
-  void SetBit(size_t bit) {
-    DCHECK_LE(bit, kHighestCommonResource);
-    masks_[bit / 64u] |= UINT64_C(1) << (bit & 63u);
-  }
+  void SetBit(size_t bit);
 
   constexpr bool HasBit(size_t bit) const {
     return (masks_[bit / 64u] & (UINT64_C(1) << (bit & 63u))) != 0u;
@@ -139,6 +137,12 @@
 
   friend class ResourceMaskCache;
 };
+std::ostream& operator<<(std::ostream& os, const ResourceMask::ResourceBit& rhs);
+
+inline void ResourceMask::SetBit(size_t bit) {
+  DCHECK_LE(bit, kHighestCommonResource);
+  masks_[bit / 64u] |= UINT64_C(1) << (bit & 63u);
+}
 
 constexpr ResourceMask kEncodeNone = ResourceMask::NoBits();
 constexpr ResourceMask kEncodeAll = ResourceMask::AllBits();
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index dce2b73..ad2ed01 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -424,15 +424,15 @@
   { kX86PextrbRRI, kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0  | REG_USE1, { 0x66, 0, 0x0F, 0x3A, 0x14, 0, 0, 1, false }, "PextbRRI", "!0r,!1r,!2d" },
   { kX86PextrwRRI, kRegRegImm, IS_TERTIARY_OP | REG_DEF0  | REG_USE1, { 0x66, 0, 0x0F, 0xC5, 0x00, 0, 0, 1, false }, "PextwRRI", "!0r,!1r,!2d" },
   { kX86PextrdRRI, kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0  | REG_USE1, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "PextdRRI", "!0r,!1r,!2d" },
-  { kX86PextrbMRI, kMemRegImm, IS_QUAD_OP     | REG_USE02 | IS_STORE, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "kX86PextrbMRI", "[!0r+!1d],!2r,!3d" },
-  { kX86PextrwMRI, kMemRegImm, IS_QUAD_OP     | REG_USE02 | IS_STORE, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "kX86PextrwMRI", "[!0r+!1d],!2r,!3d" },
-  { kX86PextrdMRI, kMemRegImm, IS_QUAD_OP     | REG_USE02 | IS_STORE, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "kX86PextrdMRI", "[!0r+!1d],!2r,!3d" },
+  { kX86PextrbMRI, kMemRegImm, IS_QUAD_OP     | REG_USE02 | IS_STORE, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "PextrbMRI", "[!0r+!1d],!2r,!3d" },
+  { kX86PextrwMRI, kMemRegImm, IS_QUAD_OP     | REG_USE02 | IS_STORE, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "PextrwMRI", "[!0r+!1d],!2r,!3d" },
+  { kX86PextrdMRI, kMemRegImm, IS_QUAD_OP     | REG_USE02 | IS_STORE, { 0x66, 0, 0x0F, 0x3A, 0x16, 0, 0, 1, false }, "PextrdMRI", "[!0r+!1d],!2r,!3d" },
 
   { kX86PshuflwRRI, kRegRegImm, IS_TERTIARY_OP | REG_DEF0 | REG_USE1, { 0xF2, 0, 0x0F, 0x70, 0, 0, 0, 1, false }, "PshuflwRRI", "!0r,!1r,!2d" },
   { kX86PshufdRRI,  kRegRegImm, IS_TERTIARY_OP | REG_DEF0 | REG_USE1, { 0x66, 0, 0x0F, 0x70, 0, 0, 0, 1, false }, "PshuffRRI", "!0r,!1r,!2d" },
 
-  { kX86ShufpsRRI, kRegRegImm, IS_TERTIARY_OP | REG_DEF0 | REG_USE1, { 0x00, 0, 0x0F, 0xC6, 0, 0, 0, 1, false }, "kX86ShufpsRRI", "!0r,!1r,!2d" },
-  { kX86ShufpdRRI, kRegRegImm, IS_TERTIARY_OP | REG_DEF0 | REG_USE1, { 0x66, 0, 0x0F, 0xC6, 0, 0, 0, 1, false }, "kX86ShufpdRRI", "!0r,!1r,!2d" },
+  { kX86ShufpsRRI, kRegRegImm, IS_TERTIARY_OP | REG_DEF0_USE0 | REG_USE1, { 0x00, 0, 0x0F, 0xC6, 0, 0, 0, 1, false }, "ShufpsRRI", "!0r,!1r,!2d" },
+  { kX86ShufpdRRI, kRegRegImm, IS_TERTIARY_OP | REG_DEF0_USE0 | REG_USE1, { 0x66, 0, 0x0F, 0xC6, 0, 0, 0, 1, false }, "ShufpdRRI", "!0r,!1r,!2d" },
 
   { kX86PsrawRI, kRegImm, IS_BINARY_OP | REG_DEF0_USE0, { 0x66, 0, 0x0F, 0x71, 0, 4, 0, 1, false }, "PsrawRI", "!0r,!1d" },
   { kX86PsradRI, kRegImm, IS_BINARY_OP | REG_DEF0_USE0, { 0x66, 0, 0x0F, 0x72, 0, 4, 0, 1, false }, "PsradRI", "!0r,!1d" },
@@ -541,14 +541,19 @@
   { kX86CallI, kCall, IS_UNARY_OP  | IS_BRANCH,                             { 0,             0, 0xE8, 0,    0, 0, 0, 4, false }, "CallI", "!0d" },
   { kX86Ret,   kNullary, NO_OPERAND | IS_BRANCH,                            { 0,             0, 0xC3, 0,    0, 0, 0, 0, false }, "Ret", "" },
 
-  { kX86StartOfMethod, kMacro,  IS_UNARY_OP | SETS_CCODES,             { 0, 0, 0,    0, 0, 0, 0, 0, false }, "StartOfMethod", "!0r" },
+  { kX86StartOfMethod, kMacro,  IS_UNARY_OP | REG_DEF0 | SETS_CCODES,  { 0, 0, 0,    0, 0, 0, 0, 0, false }, "StartOfMethod", "!0r" },
   { kX86PcRelLoadRA,   kPcRel,  IS_LOAD | IS_QUIN_OP | REG_DEF0_USE12, { 0, 0, 0x8B, 0, 0, 0, 0, 0, false }, "PcRelLoadRA",   "!0r,[!1r+!2r<<!3d+!4p]" },
   { kX86PcRelAdr,      kPcRel,  IS_LOAD | IS_BINARY_OP | REG_DEF0,     { 0, 0, 0xB8, 0, 0, 0, 0, 4, false }, "PcRelAdr",      "!0r,!1p" },
   { kX86RepneScasw,    kNullary, NO_OPERAND | REG_USEA | REG_USEC | SETS_CCODES, { 0x66, 0xF2, 0xAF, 0, 0, 0, 0, 0, false }, "RepNE ScasW", "" },
 };
 
+std::ostream& operator<<(std::ostream& os, const X86OpCode& rhs) {
+  os << X86Mir2Lir::EncodingMap[rhs].name;
+  return os;
+}
+
 static bool NeedsRex(int32_t raw_reg) {
-  return RegStorage::RegNum(raw_reg) > 7;
+  return raw_reg != kRIPReg && RegStorage::RegNum(raw_reg) > 7;
 }
 
 static uint8_t LowRegisterBits(int32_t raw_reg) {
@@ -672,7 +677,7 @@
     ++size;  // modrm
   }
   if (!modrm_is_reg_reg) {
-    if (has_sib || LowRegisterBits(raw_base) == rs_rX86_SP.GetRegNum()
+    if (has_sib || (LowRegisterBits(raw_base) == rs_rX86_SP_32.GetRegNum())
         || (cu_->target64 && entry->skeleton.prefix1 == THREAD_PREFIX)) {
       // SP requires a SIB byte.
       // GS access also needs a SIB byte for absolute adressing in 64-bit mode.
@@ -684,7 +689,13 @@
           entry->opcode != kX86Lea32RM && entry->opcode != kX86Lea64RM) {
         DCHECK_NE(entry->flags & (IS_LOAD | IS_STORE), UINT64_C(0)) << entry->name;
       }
-      size += IS_SIMM8(displacement) ? 1 : 4;
+      if (raw_base == kRIPReg) {
+        DCHECK(cu_->target64) <<
+          "Attempt to use a 64-bit RIP adressing with instruction " << entry->name;
+        size += 4;
+      } else {
+        size += IS_SIMM8(displacement) ? 1 : 4;
+      }
     }
   }
   size += entry->skeleton.immediate_bytes;
@@ -1005,9 +1016,9 @@
 void X86Mir2Lir::EmitModrmThread(uint8_t reg_or_opcode) {
   if (cu_->target64) {
     // Absolute adressing for GS access.
-    uint8_t modrm = (0 << 6) | (reg_or_opcode << 3) | rs_rX86_SP.GetRegNum();
+    uint8_t modrm = (0 << 6) | (reg_or_opcode << 3) | rs_rX86_SP_32.GetRegNum();
     code_buffer_.push_back(modrm);
-    uint8_t sib = (0/*TIMES_1*/ << 6) | (rs_rX86_SP.GetRegNum() << 3) | rs_rBP.GetRegNum();
+    uint8_t sib = (0/*TIMES_1*/ << 6) | (rs_rX86_SP_32.GetRegNum() << 3) | rs_rBP.GetRegNum();
     code_buffer_.push_back(sib);
   } else {
     uint8_t modrm = (0 << 6) | (reg_or_opcode << 3) | rs_rBP.GetRegNum();
@@ -1017,21 +1028,31 @@
 
 void X86Mir2Lir::EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int32_t disp) {
   DCHECK_LT(reg_or_opcode, 8);
-  DCHECK_LT(base, 8);
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base;
-  code_buffer_.push_back(modrm);
-  if (base == rs_rX86_SP.GetRegNum()) {
-    // Special SIB for SP base
-    code_buffer_.push_back(0 << 6 | rs_rX86_SP.GetRegNum() << 3 | rs_rX86_SP.GetRegNum());
+  if (base == kRIPReg) {
+    // x86_64 RIP handling: always 32 bit displacement.
+    uint8_t modrm = (0x0 << 6) | (reg_or_opcode << 3) | 0x5;
+    code_buffer_.push_back(modrm);
+    code_buffer_.push_back(disp & 0xFF);
+    code_buffer_.push_back((disp >> 8) & 0xFF);
+    code_buffer_.push_back((disp >> 16) & 0xFF);
+    code_buffer_.push_back((disp >> 24) & 0xFF);
+  } else {
+    DCHECK_LT(base, 8);
+    uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base;
+    code_buffer_.push_back(modrm);
+    if (base == rs_rX86_SP_32.GetRegNum()) {
+      // Special SIB for SP base
+      code_buffer_.push_back(0 << 6 | rs_rX86_SP_32.GetRegNum() << 3 | rs_rX86_SP_32.GetRegNum());
+    }
+    EmitDisp(base, disp);
   }
-  EmitDisp(base, disp);
 }
 
 void X86Mir2Lir::EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index,
                                   int scale, int32_t disp) {
   DCHECK_LT(RegStorage::RegNum(reg_or_opcode), 8);
   uint8_t modrm = (ModrmForDisp(base, disp) << 6) | RegStorage::RegNum(reg_or_opcode) << 3 |
-      rs_rX86_SP.GetRegNum();
+      rs_rX86_SP_32.GetRegNum();
   code_buffer_.push_back(modrm);
   DCHECK_LT(scale, 4);
   DCHECK_LT(RegStorage::RegNum(index), 8);
@@ -1136,7 +1157,7 @@
   CheckValidByteRegister(entry, raw_reg);
   EmitPrefixAndOpcode(entry, raw_reg, NO_REG, raw_base);
   uint8_t low_reg = LowRegisterBits(raw_reg);
-  uint8_t low_base = LowRegisterBits(raw_base);
+  uint8_t low_base = (raw_base == kRIPReg) ? raw_base : LowRegisterBits(raw_base);
   EmitModrmDisp(low_reg, low_base, disp);
   DCHECK_EQ(0, entry->skeleton.modrm_opcode);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -1579,7 +1600,7 @@
     DCHECK_EQ(0, entry->skeleton.extra_opcode1);
     DCHECK_EQ(0, entry->skeleton.extra_opcode2);
     uint8_t low_reg = LowRegisterBits(raw_reg);
-    uint8_t modrm = (2 << 6) | (low_reg << 3) | rs_rX86_SP.GetRegNum();
+    uint8_t modrm = (2 << 6) | (low_reg << 3) | rs_rX86_SP_32.GetRegNum();
     code_buffer_.push_back(modrm);
     DCHECK_LT(scale, 4);
     uint8_t low_base_or_table = LowRegisterBits(raw_base_or_table);
@@ -1631,6 +1652,7 @@
  * sequence or request that the trace be shortened and retried.
  */
 AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) {
+  UNUSED(start_addr);
   LIR *lir;
   AssemblerStatus res = kSuccess;  // Assume success
 
@@ -1752,12 +1774,29 @@
             LIR *target_lir = lir->target;
             DCHECK(target_lir != NULL);
             CodeOffset target = target_lir->offset;
-            lir->operands[2] = target;
-            int newSize = GetInsnSize(lir);
-            if (newSize != lir->flags.size) {
-              lir->flags.size = newSize;
-              res = kRetryAll;
+            // Handle 64 bit RIP addressing.
+            if (lir->operands[1] == kRIPReg) {
+              // Offset is relative to next instruction.
+              lir->operands[2] = target - (lir->offset + lir->flags.size);
+            } else {
+              lir->operands[2] = target;
+              int newSize = GetInsnSize(lir);
+              if (newSize != lir->flags.size) {
+                lir->flags.size = newSize;
+                res = kRetryAll;
+              }
             }
+          } else if (lir->flags.fixup == kFixupSwitchTable) {
+            DCHECK(cu_->target64);
+            DCHECK_EQ(lir->opcode, kX86Lea64RM) << "Unknown instruction: " << X86Mir2Lir::EncodingMap[lir->opcode].name;
+            DCHECK_EQ(lir->operands[1], static_cast<int>(kRIPReg));
+            // Grab the target offset from the saved data.
+            Mir2Lir::EmbeddedData* tab_rec =
+                reinterpret_cast<Mir2Lir::EmbeddedData*>(UnwrapPointer(lir->operands[4]));
+            CodeOffset target = tab_rec->offset;
+            // Handle 64 bit RIP addressing.
+            // Offset is relative to next instruction.
+            lir->operands[2] = target - (lir->offset + lir->flags.size);
           }
           break;
       }
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 441ec9e..544ac3b 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -30,23 +30,88 @@
  * pairs.
  */
 void X86Mir2Lir::GenLargeSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
-  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
+  GenSmallSparseSwitch(mir, table_offset, rl_src);
+}
+
+/*
+ * We override InsertCaseLabel, because the first parameter represents
+ * a basic block id, instead of a dex offset.
+ */
+LIR* X86Mir2Lir::InsertCaseLabel(DexOffset bbid, int keyVal) {
+  LIR* boundary_lir = &block_label_list_[bbid];
+  LIR* res = boundary_lir;
   if (cu_->verbose) {
-    DumpSparseSwitchTable(table);
+    // Only pay the expense if we're pretty-printing.
+    LIR* new_label = static_cast<LIR*>(arena_->Alloc(sizeof(LIR), kArenaAllocLIR));
+    BasicBlock* bb = mir_graph_->GetBasicBlock(bbid);
+    DCHECK(bb != nullptr);
+    new_label->dalvik_offset = bb->start_offset;;
+    new_label->opcode = kPseudoCaseLabel;
+    new_label->operands[0] = keyVal;
+    new_label->flags.fixup = kFixupLabel;
+    DCHECK(!new_label->flags.use_def_invalid);
+    new_label->u.m.def_mask = &kEncodeAll;
+    InsertLIRAfter(boundary_lir, new_label);
+    res = new_label;
   }
+  return res;
+}
+
+void X86Mir2Lir::MarkPackedCaseLabels(Mir2Lir::SwitchTable* tab_rec) {
+  const uint16_t* table = tab_rec->table;
+  const int32_t *targets = reinterpret_cast<const int32_t*>(&table[4]);
   int entries = table[1];
-  const int32_t* keys = reinterpret_cast<const int32_t*>(&table[2]);
-  const int32_t* targets = &keys[entries];
-  rl_src = LoadValue(rl_src, kCoreReg);
+  int low_key = s4FromSwitchData(&table[2]);
   for (int i = 0; i < entries; i++) {
-    int key = keys[i];
-    BasicBlock* case_block =
-        mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
-    OpCmpImmBranch(kCondEq, rl_src.reg, key, &block_label_list_[case_block->id]);
+    // The value at targets[i] is a basic block id, instead of a dex offset.
+    tab_rec->targets[i] = InsertCaseLabel(targets[i], i + low_key);
   }
 }
 
 /*
+ * We convert and create a new packed switch table that stores
+ * basic block ids to targets[] by examining successor blocks.
+ * Note that the original packed switch table stores dex offsets to targets[].
+ */
+const uint16_t* X86Mir2Lir::ConvertPackedSwitchTable(MIR* mir, const uint16_t* table) {
+  /*
+   * The original packed switch data format:
+   *  ushort ident = 0x0100  magic value
+   *  ushort size            number of entries in the table
+   *  int first_key          first (and lowest) switch case value
+   *  int targets[size]      branch targets, relative to switch opcode
+   *
+   * Total size is (4+size*2) 16-bit code units.
+   *
+   * Note that the new packed switch data format is the same as the original
+   * format, except that targets[] are basic block ids.
+   *
+   */
+  BasicBlock* bb = mir_graph_->GetBasicBlock(mir->bb);
+  DCHECK(bb != nullptr);
+  // Get the number of entries.
+  int entries = table[1];
+  const int32_t* as_int32 = reinterpret_cast<const int32_t*>(&table[2]);
+  int32_t starting_key = as_int32[0];
+  // Create a new table.
+  int size = sizeof(uint16_t) * (4 + entries * 2);
+  uint16_t* new_table = reinterpret_cast<uint16_t*>(arena_->Alloc(size, kArenaAllocMisc));
+  // Copy ident, size, and first_key to the new table.
+  memcpy(new_table, table, sizeof(uint16_t) * 4);
+  // Get the new targets.
+  int32_t* new_targets = reinterpret_cast<int32_t*>(&new_table[4]);
+  // Find out targets for each entry.
+  int i = 0;
+  for (SuccessorBlockInfo* successor_block_info : bb->successor_blocks) {
+    DCHECK_EQ(starting_key + i, successor_block_info->key);
+    // Save target basic block id.
+    new_targets[i++] = successor_block_info->block;
+  }
+  DCHECK_EQ(i, entries);
+  return new_table;
+}
+
+/*
  * Code pattern will look something like:
  *
  * mov  r_val, ..
@@ -63,10 +128,8 @@
  * done:
  */
 void X86Mir2Lir::GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
-  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
-  if (cu_->verbose) {
-    DumpPackedSwitchTable(table);
-  }
+  const uint16_t* old_table = mir_graph_->GetTable(mir, table_offset);
+  const uint16_t* table = ConvertPackedSwitchTable(mir, old_table);
   // Add the table to the list - we'll process it later
   SwitchTable* tab_rec =
       static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData));
@@ -79,25 +142,7 @@
 
   // Get the switch value
   rl_src = LoadValue(rl_src, kCoreReg);
-  // NewLIR0(kX86Bkpt);
 
-  // Materialize a pointer to the switch table
-  RegStorage start_of_method_reg;
-  if (base_of_code_ != nullptr) {
-    // We can use the saved value.
-    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
-    if (rl_method.wide) {
-      rl_method = LoadValueWide(rl_method, kCoreReg);
-    } else {
-      rl_method = LoadValue(rl_method, kCoreReg);
-    }
-    start_of_method_reg = rl_method.reg;
-    store_method_addr_used_ = true;
-  } else {
-    start_of_method_reg = AllocTempRef();
-    NewLIR1(kX86StartOfMethod, start_of_method_reg.GetReg());
-  }
-  DCHECK_EQ(start_of_method_reg.Is64Bit(), cu_->target64);
   int low_key = s4FromSwitchData(&table[2]);
   RegStorage keyReg;
   // Remove the bias, if necessary
@@ -107,73 +152,55 @@
     keyReg = AllocTemp();
     OpRegRegImm(kOpSub, keyReg, rl_src.reg, low_key);
   }
+
   // Bounds check - if < 0 or >= size continue following switch
   OpRegImm(kOpCmp, keyReg, size - 1);
   LIR* branch_over = OpCondBranch(kCondHi, NULL);
 
-  // Load the displacement from the switch table
-  RegStorage disp_reg = AllocTemp();
-  NewLIR5(kX86PcRelLoadRA, disp_reg.GetReg(), start_of_method_reg.GetReg(), keyReg.GetReg(),
-          2, WrapPointer(tab_rec));
-  // Add displacement to start of method
-  OpRegReg(kOpAdd, start_of_method_reg, cu_->target64 ? As64BitReg(disp_reg) : disp_reg);
+  RegStorage addr_for_jump;
+  if (cu_->target64) {
+    RegStorage table_base = AllocTempWide();
+    // Load the address of the table into table_base.
+    LIR* lea = RawLIR(current_dalvik_offset_, kX86Lea64RM, table_base.GetReg(), kRIPReg,
+                      256, 0, WrapPointer(tab_rec));
+    lea->flags.fixup = kFixupSwitchTable;
+    AppendLIR(lea);
+
+    // Load the offset from the table out of the table.
+    addr_for_jump = AllocTempWide();
+    NewLIR5(kX86MovsxdRA, addr_for_jump.GetReg(), table_base.GetReg(), keyReg.GetReg(), 2, 0);
+
+    // Add the offset from the table to the table base.
+    OpRegReg(kOpAdd, addr_for_jump, table_base);
+  } else {
+    // Materialize a pointer to the switch table.
+    RegStorage start_of_method_reg;
+    if (base_of_code_ != nullptr) {
+      // We can use the saved value.
+      RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+      rl_method = LoadValue(rl_method, kCoreReg);
+      start_of_method_reg = rl_method.reg;
+      store_method_addr_used_ = true;
+    } else {
+      start_of_method_reg = AllocTempRef();
+      NewLIR1(kX86StartOfMethod, start_of_method_reg.GetReg());
+    }
+    // Load the displacement from the switch table.
+    addr_for_jump = AllocTemp();
+    NewLIR5(kX86PcRelLoadRA, addr_for_jump.GetReg(), start_of_method_reg.GetReg(), keyReg.GetReg(),
+            2, WrapPointer(tab_rec));
+    // Add displacement to start of method.
+    OpRegReg(kOpAdd, addr_for_jump, start_of_method_reg);
+  }
+
   // ..and go!
-  LIR* switch_branch = NewLIR1(kX86JmpR, start_of_method_reg.GetReg());
-  tab_rec->anchor = switch_branch;
+  tab_rec->anchor = NewLIR1(kX86JmpR, addr_for_jump.GetReg());
 
   /* branch_over target here */
   LIR* target = NewLIR0(kPseudoTargetLabel);
   branch_over->target = target;
 }
 
-/*
- * Array data table format:
- *  ushort ident = 0x0300   magic value
- *  ushort width            width of each element in the table
- *  uint   size             number of elements in the table
- *  ubyte  data[size*width] table of data values (may contain a single-byte
- *                          padding at the end)
- *
- * Total size is 4+(width * size + 1)/2 16-bit code units.
- */
-void X86Mir2Lir::GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
-  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
-  // Add the table to the list - we'll process it later
-  FillArrayData* tab_rec =
-      static_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData), kArenaAllocData));
-  tab_rec->table = table;
-  tab_rec->vaddr = current_dalvik_offset_;
-  uint16_t width = tab_rec->table[1];
-  uint32_t size = tab_rec->table[2] | ((static_cast<uint32_t>(tab_rec->table[3])) << 16);
-  tab_rec->size = (size * width) + 8;
-
-  fill_array_data_.push_back(tab_rec);
-
-  // Making a call - use explicit registers
-  FlushAllRegs();   /* Everything to home location */
-  RegStorage array_ptr = TargetReg(kArg0, kRef);
-  RegStorage payload = TargetPtrReg(kArg1);
-  RegStorage method_start = TargetPtrReg(kArg2);
-
-  LoadValueDirectFixed(rl_src, array_ptr);
-  // Materialize a pointer to the fill data image
-  if (base_of_code_ != nullptr) {
-    // We can use the saved value.
-    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
-    if (rl_method.wide) {
-      LoadValueDirectWide(rl_method, method_start);
-    } else {
-      LoadValueDirect(rl_method, method_start);
-    }
-    store_method_addr_used_ = true;
-  } else {
-    NewLIR1(kX86StartOfMethod, method_start.GetReg());
-  }
-  NewLIR2(kX86PcRelAdr, payload.GetReg(), WrapPointer(tab_rec));
-  OpRegReg(kOpAdd, payload, method_start);
-  CallRuntimeHelperRegReg(kQuickHandleFillArrayData, array_ptr, payload, true);
-}
-
 void X86Mir2Lir::GenMoveException(RegLocation rl_dest) {
   int ex_offset = cu_->target64 ?
       Thread::ExceptionOffset<8>().Int32Value() :
@@ -184,23 +211,16 @@
   StoreValue(rl_dest, rl_result);
 }
 
-/*
- * Mark garbage collection card. Skip if the value we're storing is null.
- */
-void X86Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
+void X86Mir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) {
   DCHECK_EQ(tgt_addr_reg.Is64Bit(), cu_->target64);
-  DCHECK_EQ(val_reg.Is64Bit(), cu_->target64);
   RegStorage reg_card_base = AllocTempRef();
   RegStorage reg_card_no = AllocTempRef();
-  LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   int ct_offset = cu_->target64 ?
       Thread::CardTableOffset<8>().Int32Value() :
       Thread::CardTableOffset<4>().Int32Value();
   NewLIR2(cu_->target64 ? kX86Mov64RT : kX86Mov32RT, reg_card_base.GetReg(), ct_offset);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
-  LIR* target = NewLIR0(kPseudoTargetLabel);
-  branch_over->target = target;
   FreeTemp(reg_card_base);
   FreeTemp(reg_card_no);
 }
@@ -212,16 +232,20 @@
    * expanding the frame or flushing.  This leaves the utility
    * code with no spare temps.
    */
-  LockTemp(rs_rX86_ARG0);
-  LockTemp(rs_rX86_ARG1);
-  LockTemp(rs_rX86_ARG2);
+  const RegStorage arg0 = TargetReg32(kArg0);
+  const RegStorage arg1 = TargetReg32(kArg1);
+  const RegStorage arg2 = TargetReg32(kArg2);
+  LockTemp(arg0);
+  LockTemp(arg1);
+  LockTemp(arg2);
 
   /*
    * We can safely skip the stack overflow check if we're
    * a leaf *and* our frame size < fudge factor.
    */
-  InstructionSet isa =  cu_->target64 ? kX86_64 : kX86;
+  const InstructionSet isa =  cu_->target64 ? kX86_64 : kX86;
   bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, isa);
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
 
   // If we doing an implicit stack overflow check, perform the load immediately
   // before the stack pointer is decremented and anything is saved.
@@ -230,12 +254,12 @@
     // Implicit stack overflow check.
     // test eax,[esp + -overflow]
     int overflow = GetStackOverflowReservedBytes(isa);
-    NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rX86_SP.GetReg(), -overflow);
+    NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rSP.GetReg(), -overflow);
     MarkPossibleStackOverflowException();
   }
 
   /* Build frame, return address already on stack */
-  stack_decrement_ = OpRegImm(kOpSub, rs_rX86_SP, frame_size_ -
+  stack_decrement_ = OpRegImm(kOpSub, rs_rSP, frame_size_ -
                               GetInstructionSetPointerSize(cu_->instruction_set));
 
   NewLIR0(kPseudoMethodEntry);
@@ -252,7 +276,8 @@
         m2l_->ResetRegPool();
         m2l_->ResetDefTracking();
         GenerateTargetLabel(kPseudoThrowTarget);
-        m2l_->OpRegImm(kOpAdd, rs_rX86_SP, sp_displace_);
+        const RegStorage local_rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
+        m2l_->OpRegImm(kOpAdd, local_rs_rSP, sp_displace_);
         m2l_->ClobberCallerSave();
         // Assumes codegen and target are in thumb2 mode.
         m2l_->CallHelper(RegStorage::InvalidReg(), kQuickThrowStackOverflow,
@@ -273,9 +298,9 @@
       // may have moved us outside of the reserved area at the end of the stack.
       // cmp rs_rX86_SP, fs:[stack_end_]; jcc throw_slowpath
       if (cu_->target64) {
-        OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<8>());
+        OpRegThreadMem(kOpCmp, rs_rX86_SP_64, Thread::StackEndOffset<8>());
       } else {
-        OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
+        OpRegThreadMem(kOpCmp, rs_rX86_SP_32, Thread::StackEndOffset<4>());
       }
       LIR* branch = OpCondBranch(kCondUlt, nullptr);
       AddSlowPath(
@@ -293,13 +318,13 @@
     setup_method_address_[0] = NewLIR1(kX86StartOfMethod, method_start.GetReg());
     int displacement = SRegOffset(base_of_code_->s_reg_low);
     // Native pointer - must be natural word size.
-    setup_method_address_[1] = StoreBaseDisp(rs_rX86_SP, displacement, method_start,
+    setup_method_address_[1] = StoreBaseDisp(rs_rSP, displacement, method_start,
                                              cu_->target64 ? k64 : k32, kNotVolatile);
   }
 
-  FreeTemp(rs_rX86_ARG0);
-  FreeTemp(rs_rX86_ARG1);
-  FreeTemp(rs_rX86_ARG2);
+  FreeTemp(arg0);
+  FreeTemp(arg1);
+  FreeTemp(arg2);
 }
 
 void X86Mir2Lir::GenExitSequence() {
@@ -314,7 +339,9 @@
   UnSpillCoreRegs();
   UnSpillFPRegs();
   /* Remove frame except for return address */
-  stack_increment_ = OpRegImm(kOpAdd, rs_rX86_SP, frame_size_ - GetInstructionSetPointerSize(cu_->instruction_set));
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
+  stack_increment_ = OpRegImm(kOpAdd, rs_rSP,
+                              frame_size_ - GetInstructionSetPointerSize(cu_->instruction_set));
   NewLIR0(kX86Ret);
 }
 
@@ -338,9 +365,10 @@
  */
 static int X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
                              int state, const MethodReference& target_method,
-                             uint32_t unused,
+                             uint32_t,
                              uintptr_t direct_code, uintptr_t direct_method,
                              InvokeType type) {
+  UNUSED(info, direct_code);
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   if (direct_method != 0) {
     switch (state) {
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 8edfc01..c7d83dd 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -28,40 +28,48 @@
 
 class X86Mir2Lir : public Mir2Lir {
  protected:
-  class InToRegStorageMapper {
-   public:
-    virtual RegStorage GetNextReg(bool is_double_or_float, bool is_wide, bool is_ref) = 0;
-    virtual ~InToRegStorageMapper() {}
-  };
-
   class InToRegStorageX86_64Mapper : public InToRegStorageMapper {
    public:
-    explicit InToRegStorageX86_64Mapper(Mir2Lir* ml) : ml_(ml), cur_core_reg_(0), cur_fp_reg_(0) {}
-    virtual ~InToRegStorageX86_64Mapper() {}
-    virtual RegStorage GetNextReg(bool is_double_or_float, bool is_wide, bool is_ref);
+    explicit InToRegStorageX86_64Mapper(Mir2Lir* m2l)
+        : m2l_(m2l), cur_core_reg_(0), cur_fp_reg_(0) {}
+    virtual RegStorage GetNextReg(ShortyArg arg);
+    virtual void Reset() OVERRIDE {
+      cur_core_reg_ = 0;
+      cur_fp_reg_ = 0;
+    }
    protected:
-    Mir2Lir* ml_;
+    Mir2Lir* m2l_;
    private:
-    int cur_core_reg_;
-    int cur_fp_reg_;
+    size_t cur_core_reg_;
+    size_t cur_fp_reg_;
   };
 
-  class InToRegStorageMapping {
+  class InToRegStorageX86Mapper : public InToRegStorageMapper {
    public:
-    InToRegStorageMapping() : max_mapped_in_(0), is_there_stack_mapped_(false),
-    initialized_(false) {}
-    void Initialize(RegLocation* arg_locs, int count, InToRegStorageMapper* mapper);
-    int GetMaxMappedIn() { return max_mapped_in_; }
-    bool IsThereStackMapped() { return is_there_stack_mapped_; }
-    RegStorage Get(int in_position);
-    bool IsInitialized() { return initialized_; }
+    explicit InToRegStorageX86Mapper(Mir2Lir* m2l) : m2l_(m2l), cur_core_reg_(0) {}
+    virtual RegStorage GetNextReg(ShortyArg arg);
+    virtual void Reset() OVERRIDE {
+      cur_core_reg_ = 0;
+    }
+   protected:
+    Mir2Lir* m2l_;
    private:
-    std::map<int, RegStorage> mapping_;
-    int max_mapped_in_;
-    bool is_there_stack_mapped_;
-    bool initialized_;
+    size_t cur_core_reg_;
   };
 
+  InToRegStorageX86_64Mapper in_to_reg_storage_x86_64_mapper_;
+  InToRegStorageX86Mapper in_to_reg_storage_x86_mapper_;
+  InToRegStorageMapper* GetResetedInToRegStorageMapper() OVERRIDE {
+    InToRegStorageMapper* res;
+    if (cu_->target64) {
+      res = &in_to_reg_storage_x86_64_mapper_;
+    } else {
+      res = &in_to_reg_storage_x86_mapper_;
+    }
+    res->Reset();
+    return res;
+  }
+
   class ExplicitTempRegisterLock {
   public:
     ExplicitTempRegisterLock(X86Mir2Lir* mir_to_lir, int n_regs, ...);
@@ -71,6 +79,8 @@
     X86Mir2Lir* const mir_to_lir_;
   };
 
+  virtual int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE;
+
  public:
   X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
@@ -78,6 +88,10 @@
   bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
                           RegLocation rl_dest, int lit) OVERRIDE;
   bool EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) OVERRIDE;
+  void GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                  int32_t constant) OVERRIDE;
+  void GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                   int64_t constant) OVERRIDE;
   LIR* CheckSuspendUsingLoad() OVERRIDE;
   RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
   LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
@@ -86,11 +100,15 @@
                        OpSize size) OVERRIDE;
   LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
   LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
+  void GenLongToInt(RegLocation rl_dest, RegLocation rl_src);
   LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
                      OpSize size, VolatileKind is_volatile) OVERRIDE;
   LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                         OpSize size) OVERRIDE;
-  void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) OVERRIDE;
+
+  /// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
+  void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
+
   void GenImplicitNullCheck(RegStorage reg, int opt_flags) OVERRIDE;
 
   // Required for target - register utilities.
@@ -117,8 +135,6 @@
     return TargetReg(symbolic_reg, cu_->target64 ? kWide : kNotWide);
   }
 
-  RegStorage GetArgMappingToPhysicalReg(int arg_num) OVERRIDE;
-
   RegLocation GetReturnAlt() OVERRIDE;
   RegLocation GetReturnWideAlt() OVERRIDE;
   RegLocation LocCReturn() OVERRIDE;
@@ -180,11 +196,11 @@
 
   // Long instructions.
   void GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                      RegLocation rl_src2) OVERRIDE;
+                      RegLocation rl_src2, int flags) OVERRIDE;
   void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                         RegLocation rl_src2) OVERRIDE;
+                         RegLocation rl_src2, int flags) OVERRIDE;
   void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                         RegLocation rl_src1, RegLocation rl_shift) OVERRIDE;
+                         RegLocation rl_src1, RegLocation rl_shift, int flags) OVERRIDE;
   void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) OVERRIDE;
   void GenIntToLong(RegLocation rl_dest, RegLocation rl_src) OVERRIDE;
   void GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
@@ -245,21 +261,23 @@
   void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
   void GenExitSequence() OVERRIDE;
   void GenSpecialExitSequence() OVERRIDE;
-  void GenFillArrayData(MIR* mir, DexOffset table_offset, RegLocation rl_src) OVERRIDE;
   void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) OVERRIDE;
   void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) OVERRIDE;
   void GenSelect(BasicBlock* bb, MIR* mir) OVERRIDE;
   void GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                         int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                        int dest_reg_class) OVERRIDE;
+                        RegisterClass dest_reg_class) OVERRIDE;
   bool GenMemBarrier(MemBarrierKind barrier_kind) OVERRIDE;
   void GenMoveException(RegLocation rl_dest) OVERRIDE;
   void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
                                      int first_bit, int second_bit) OVERRIDE;
   void GenNegDouble(RegLocation rl_dest, RegLocation rl_src) OVERRIDE;
   void GenNegFloat(RegLocation rl_dest, RegLocation rl_src) OVERRIDE;
+  const uint16_t* ConvertPackedSwitchTable(MIR* mir, const uint16_t* table);
   void GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) OVERRIDE;
   void GenLargeSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) OVERRIDE;
+  LIR* InsertCaseLabel(DexOffset vaddr, int keyVal) OVERRIDE;
+  void MarkPackedCaseLabels(Mir2Lir::SwitchTable* tab_rec) OVERRIDE;
 
   /**
    * @brief Implement instanceof a final class with x86 specific code.
@@ -315,9 +333,10 @@
    * @param rl_dest Destination for the result.
    * @param rl_lhs Left hand operand.
    * @param rl_rhs Right hand operand.
+   * @param flags The instruction optimization flags.
    */
   void GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_lhs,
-                     RegLocation rl_rhs) OVERRIDE;
+                     RegLocation rl_rhs, int flags) OVERRIDE;
 
   /*
    * @brief Load the Method* of a dex method into the register.
@@ -339,22 +358,7 @@
   void LoadClassType(const DexFile& dex_file, uint32_t type_idx,
                      SpecialTargetRegister symbolic_reg) OVERRIDE;
 
-  void FlushIns(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
-
   NextCallInsn GetNextSDCallInsn() OVERRIDE;
-  int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                           NextCallInsn next_call_insn,
-                           const MethodReference& target_method,
-                           uint32_t vtable_idx,
-                           uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                           bool skip_this) OVERRIDE;
-
-  int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                         NextCallInsn next_call_insn,
-                         const MethodReference& target_method,
-                         uint32_t vtable_idx,
-                         uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
-                         bool skip_this) OVERRIDE;
 
   /*
    * @brief Generate a relative call to the method that will be patched at link time.
@@ -385,7 +389,7 @@
   LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
 
  protected:
-  RegStorage TargetReg32(SpecialTargetRegister reg);
+  RegStorage TargetReg32(SpecialTargetRegister reg) const;
   // Casting of RegStorage
   RegStorage As32BitReg(RegStorage reg) {
     DCHECK(!reg.IsPair());
@@ -428,8 +432,6 @@
   LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
                             RegStorage r_src, OpSize size, int opt_flags = 0);
 
-  RegStorage GetCoreArgMappingToPhysicalReg(int core_arg_num);
-
   int AssignInsnOffsets();
   void AssignOffsets();
   AssemblerStatus AssembleInstructions(CodeOffset start_addr);
@@ -499,7 +501,7 @@
   void GenConstWide(RegLocation rl_dest, int64_t value);
   void GenMultiplyVectorSignedByte(RegStorage rs_dest_src1, RegStorage rs_src2);
   void GenMultiplyVectorLong(RegStorage rs_dest_src1, RegStorage rs_src2);
-  void GenShiftByteVector(BasicBlock *bb, MIR *mir);
+  void GenShiftByteVector(MIR* mir);
   void AndMaskVectorRegister(RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3,
                              uint32_t m4);
   void MaskVectorRegister(X86OpCode opcode, RegStorage rs_src1, uint32_t m1, uint32_t m2,
@@ -526,7 +528,7 @@
    * @brief Check if a register is byte addressable.
    * @returns true if a register is byte addressable.
    */
-  bool IsByteRegister(RegStorage reg);
+  bool IsByteRegister(RegStorage reg) const;
 
   void GenDivRemLongLit(RegLocation rl_dest, RegLocation rl_src, int64_t imm, bool is_div);
 
@@ -557,88 +559,80 @@
 
   /*
    * @brief Load 128 bit constant into vector register.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector
    * @note vA is the TypeSize for the register.
    * @note vB is the destination XMM register. arg[0..3] are 32 bit constant values.
    */
-  void GenConst128(BasicBlock* bb, MIR* mir);
+  void GenConst128(MIR* mir);
 
   /*
    * @brief MIR to move a vectorized register to another.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination
    * @note vC: source
    */
-  void GenMoveVector(BasicBlock *bb, MIR *mir);
+  void GenMoveVector(MIR* mir);
 
   /*
    * @brief Packed multiply of units in two vector registers: vB = vB .* @note vC using vA to know
    * the type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: source
    */
-  void GenMultiplyVector(BasicBlock *bb, MIR *mir);
+  void GenMultiplyVector(MIR* mir);
 
   /*
    * @brief Packed addition of units in two vector registers: vB = vB .+ vC using vA to know the
    * type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: source
    */
-  void GenAddVector(BasicBlock *bb, MIR *mir);
+  void GenAddVector(MIR* mir);
 
   /*
    * @brief Packed subtraction of units in two vector registers: vB = vB .- vC using vA to know the
    * type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: source
    */
-  void GenSubtractVector(BasicBlock *bb, MIR *mir);
+  void GenSubtractVector(MIR* mir);
 
   /*
    * @brief Packed shift left of units in two vector registers: vB = vB .<< vC using vA to know the
    * type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: immediate
    */
-  void GenShiftLeftVector(BasicBlock *bb, MIR *mir);
+  void GenShiftLeftVector(MIR* mir);
 
   /*
    * @brief Packed signed shift right of units in two vector registers: vB = vB .>> vC using vA to
    * know the type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: immediate
    */
-  void GenSignedShiftRightVector(BasicBlock *bb, MIR *mir);
+  void GenSignedShiftRightVector(MIR* mir);
 
   /*
    * @brief Packed unsigned shift right of units in two vector registers: vB = vB .>>> vC using vA
    * to know the type of the vector.
-   * @param bb The basic block in which the MIR is from..
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: immediate
    */
-  void GenUnsignedShiftRightVector(BasicBlock *bb, MIR *mir);
+  void GenUnsignedShiftRightVector(MIR* mir);
 
   /*
    * @brief Packed bitwise and of units in two vector registers: vB = vB .& vC using vA to know the
@@ -647,51 +641,47 @@
    * @note vB: destination and source
    * @note vC: source
    */
-  void GenAndVector(BasicBlock *bb, MIR *mir);
+  void GenAndVector(MIR* mir);
 
   /*
    * @brief Packed bitwise or of units in two vector registers: vB = vB .| vC using vA to know the
    * type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: source
    */
-  void GenOrVector(BasicBlock *bb, MIR *mir);
+  void GenOrVector(MIR* mir);
 
   /*
    * @brief Packed bitwise xor of units in two vector registers: vB = vB .^ vC using vA to know the
    * type of the vector.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: source
    */
-  void GenXorVector(BasicBlock *bb, MIR *mir);
+  void GenXorVector(MIR* mir);
 
   /*
    * @brief Reduce a 128-bit packed element into a single VR by taking lower bits
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @details Instruction does a horizontal addition of the packed elements and then adds it to VR.
    * @note vA: TypeSize
    * @note vB: destination and source VR (not vector register)
    * @note vC: source (vector register)
    */
-  void GenAddReduceVector(BasicBlock *bb, MIR *mir);
+  void GenAddReduceVector(MIR* mir);
 
   /*
    * @brief Extract a packed element into a single VR.
-   * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
    * @note vB: destination VR (not vector register)
    * @note vC: source (vector register)
    * @note arg[0]: The index to use for extraction from vector register (which packed element).
    */
-  void GenReduceVector(BasicBlock *bb, MIR *mir);
+  void GenReduceVector(MIR* mir);
 
   /*
    * @brief Create a vector value, with all TypeSize values equal to vC
@@ -701,21 +691,21 @@
    * @note vB: destination vector register.
    * @note vC: source VR (not vector register).
    */
-  void GenSetVector(BasicBlock *bb, MIR *mir);
+  void GenSetVector(MIR* mir);
 
   /**
    * @brief Used to generate code for kMirOpPackedArrayGet.
    * @param bb The basic block of MIR.
    * @param mir The mir whose opcode is kMirOpPackedArrayGet.
    */
-  void GenPackedArrayGet(BasicBlock *bb, MIR *mir);
+  void GenPackedArrayGet(BasicBlock* bb, MIR* mir);
 
   /**
    * @brief Used to generate code for kMirOpPackedArrayPut.
    * @param bb The basic block of MIR.
    * @param mir The mir whose opcode is kMirOpPackedArrayPut.
    */
-  void GenPackedArrayPut(BasicBlock *bb, MIR *mir);
+  void GenPackedArrayPut(BasicBlock* bb, MIR* mir);
 
   /*
    * @brief Generate code for a vector opcode.
@@ -769,10 +759,11 @@
    * @param rl_src1 Numerator Location.
    * @param rl_src2 Divisor Location.
    * @param is_div 'true' if this is a division, 'false' for a remainder.
-   * @param check_zero 'true' if an exception should be generated if the divisor is 0.
+   * @param flags The instruction optimization flags. It can include information
+   * if exception check can be elided.
    */
   RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
-                        bool is_div, bool check_zero);
+                        bool is_div, int flags);
 
   /*
    * @brief Generate an integer div or rem operation by a literal.
@@ -789,10 +780,11 @@
    * @param rl_dest The destination.
    * @param rl_src The value to be shifted.
    * @param shift_amount How much to shift.
+   * @param flags The instruction optimization flags.
    * @returns the RegLocation of the result.
    */
   RegLocation GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                RegLocation rl_src, int shift_amount);
+                                RegLocation rl_src, int shift_amount, int flags);
   /*
    * Generate an imul of a register by a constant or a better sequence.
    * @param dest Destination Register.
@@ -859,13 +851,13 @@
 
   // Try to do a long multiplication where rl_src2 is a constant. This simplified setup might fail,
   // in which case false will be returned.
-  bool GenMulLongConst(RegLocation rl_dest, RegLocation rl_src1, int64_t val);
+  bool GenMulLongConst(RegLocation rl_dest, RegLocation rl_src1, int64_t val, int flags);
   void GenMulLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                  RegLocation rl_src2);
+                  RegLocation rl_src2, int flags);
   void GenNotLong(RegLocation rl_dest, RegLocation rl_src);
   void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
   void GenDivRemLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
-                     RegLocation rl_src2, bool is_div);
+                     RegLocation rl_src2, bool is_div, int flags);
 
   void SpillCoreRegs();
   void UnSpillCoreRegs();
@@ -888,8 +880,8 @@
    * the value is live in a temp register of the correct class.  Additionally, if the value is in
    * a temp register of the wrong register class, it will be clobbered.
    */
-  RegLocation UpdateLocTyped(RegLocation loc, int reg_class);
-  RegLocation UpdateLocWideTyped(RegLocation loc, int reg_class);
+  RegLocation UpdateLocTyped(RegLocation loc);
+  RegLocation UpdateLocWideTyped(RegLocation loc);
 
   /*
    * @brief Analyze MIR before generating code, to prepare for the code generation.
@@ -900,7 +892,7 @@
    * @brief Analyze one basic block.
    * @param bb Basic block to analyze.
    */
-  void AnalyzeBB(BasicBlock * bb);
+  void AnalyzeBB(BasicBlock* bb);
 
   /*
    * @brief Analyze one extended MIR instruction
@@ -908,7 +900,7 @@
    * @param bb Basic block containing instruction.
    * @param mir Extended instruction to analyze.
    */
-  void AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir);
+  void AnalyzeExtendedMIR(int opcode, BasicBlock* bb, MIR* mir);
 
   /*
    * @brief Analyze one MIR instruction
@@ -916,7 +908,7 @@
    * @param bb Basic block containing instruction.
    * @param mir Instruction to analyze.
    */
-  virtual void AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir);
+  virtual void AnalyzeMIR(int opcode, BasicBlock* bb, MIR* mir);
 
   /*
    * @brief Analyze one MIR float/double instruction
@@ -924,7 +916,7 @@
    * @param bb Basic block containing instruction.
    * @param mir Instruction to analyze.
    */
-  virtual void AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir);
+  virtual void AnalyzeFPInstruction(int opcode, BasicBlock* bb, MIR* mir);
 
   /*
    * @brief Analyze one use of a double operand.
@@ -938,7 +930,7 @@
    * @param bb Basic block containing instruction.
    * @param mir Instruction to analyze.
    */
-  void AnalyzeInvokeStatic(int opcode, BasicBlock * bb, MIR *mir);
+  void AnalyzeInvokeStatic(int opcode, BasicBlock* bb, MIR* mir);
 
   // Information derived from analysis of MIR
 
@@ -985,12 +977,11 @@
    */
   LIR* AddVectorLiteral(int32_t* constants);
 
-  InToRegStorageMapping in_to_reg_storage_mapping_;
-
-  bool WideGPRsAreAliases() OVERRIDE {
+  bool WideGPRsAreAliases() const OVERRIDE {
     return cu_->target64;  // On 64b, we have 64b GPRs.
   }
-  bool WideFPRsAreAliases() OVERRIDE {
+
+  bool WideFPRsAreAliases() const OVERRIDE {
     return true;  // xmm registers have 64b views even on x86.
   }
 
@@ -1000,11 +991,15 @@
    */
   static void DumpRegLocation(RegLocation loc);
 
-  static const X86EncodingMap EncodingMap[kX86Last];
-
  private:
   void SwapBits(RegStorage result_reg, int shift, int32_t value);
   void SwapBits64(RegStorage result_reg, int shift, int64_t value);
+
+  static const X86EncodingMap EncodingMap[kX86Last];
+
+  friend std::ostream& operator<<(std::ostream& os, const X86OpCode& rhs);
+
+  DISALLOW_COPY_AND_ASSIGN(X86Mir2Lir);
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 21d1a5c..4825db6 100755
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -122,6 +122,20 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+void X86Mir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
+                                            int32_t constant) {
+  // TODO: need x86 implementation.
+  UNUSED(rl_dest, rl_src1, constant);
+  LOG(FATAL) << "Unimplemented GenMultiplyByConstantFloat in x86";
+}
+
+void X86Mir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
+                                             int64_t constant) {
+  // TODO: need x86 implementation.
+  UNUSED(rl_dest, rl_src1, constant);
+  LOG(FATAL) << "Unimplemented GenMultiplyByConstantDouble in x86";
+}
+
 void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double) {
   // Compute offsets to the source and destination VRs on stack
   int src_v_reg_offset = SRegOffset(rl_src.s_reg_low);
@@ -145,12 +159,13 @@
     } else {
       // It must have been register promoted if it is not a temp but is still in physical
       // register. Since we need it to be in memory to convert, we place it there now.
-      StoreBaseDisp(rs_rX86_SP, src_v_reg_offset, rl_src.reg, k64, kNotVolatile);
+      const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
+      StoreBaseDisp(rs_rSP, src_v_reg_offset, rl_src.reg, k64, kNotVolatile);
     }
   }
 
   // Push the source virtual register onto the x87 stack.
-  LIR *fild64 = NewLIR2NoDest(kX86Fild64M, rs_rX86_SP.GetReg(),
+  LIR *fild64 = NewLIR2NoDest(kX86Fild64M, rs_rX86_SP_32.GetReg(),
                               src_v_reg_offset + LOWORD_OFFSET);
   AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
                           true /* is_load */, true /* is64bit */);
@@ -158,7 +173,7 @@
   // Now pop off x87 stack and store it in the destination VR's stack location.
   int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
   int displacement = is_double ? dest_v_reg_offset + LOWORD_OFFSET : dest_v_reg_offset;
-  LIR *fstp = NewLIR2NoDest(opcode, rs_rX86_SP.GetReg(), displacement);
+  LIR *fstp = NewLIR2NoDest(opcode, rs_rX86_SP_32.GetReg(), displacement);
   AnnotateDalvikRegAccess(fstp, displacement >> 2, false /* is_load */, is_double);
 
   /*
@@ -169,8 +184,7 @@
    * If the result's location is in memory, then we do not need to do anything
    * more since the fstp has already placed the correct value in memory.
    */
-  RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) :
-      UpdateLocTyped(rl_dest, kFPReg);
+  RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
   if (rl_result.location == kLocPhysReg) {
     /*
      * We already know that the result is in a physical register but do not know if it is the
@@ -178,12 +192,13 @@
      * correct register class.
      */
     rl_result = EvalLoc(rl_dest, kFPReg, true);
+    const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
     if (is_double) {
-      LoadBaseDisp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
+      LoadBaseDisp(rs_rSP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
 
       StoreFinalValueWide(rl_dest, rl_result);
     } else {
-      Load32Disp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg);
+      Load32Disp(rs_rSP, dest_v_reg_offset, rl_result.reg);
 
       StoreFinalValue(rl_dest, rl_result);
     }
@@ -353,6 +368,7 @@
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
 
   // If the source is in physical register, then put it in its location on stack.
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
   if (rl_src1.location == kLocPhysReg) {
     RegisterInfo* reg_info = GetRegInfo(rl_src1.reg);
 
@@ -364,7 +380,7 @@
     } else {
       // It must have been register promoted if it is not a temp but is still in physical
       // register. Since we need it to be in memory to convert, we place it there now.
-      StoreBaseDisp(rs_rX86_SP, src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32,
+      StoreBaseDisp(rs_rSP, src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32,
                     kNotVolatile);
     }
   }
@@ -375,7 +391,7 @@
       FlushSpecificReg(reg_info);
       ResetDef(rl_src2.reg);
     } else {
-      StoreBaseDisp(rs_rX86_SP, src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32,
+      StoreBaseDisp(rs_rSP, src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32,
                     kNotVolatile);
     }
   }
@@ -383,12 +399,12 @@
   int fld_opcode = is_double ? kX86Fld64M : kX86Fld32M;
 
   // Push the source virtual registers onto the x87 stack.
-  LIR *fld_2 = NewLIR2NoDest(fld_opcode, rs_rX86_SP.GetReg(),
+  LIR *fld_2 = NewLIR2NoDest(fld_opcode, rs_rSP.GetReg(),
                              src2_v_reg_offset + LOWORD_OFFSET);
   AnnotateDalvikRegAccess(fld_2, (src2_v_reg_offset + LOWORD_OFFSET) >> 2,
                           true /* is_load */, is_double /* is64bit */);
 
-  LIR *fld_1 = NewLIR2NoDest(fld_opcode, rs_rX86_SP.GetReg(),
+  LIR *fld_1 = NewLIR2NoDest(fld_opcode, rs_rSP.GetReg(),
                              src1_v_reg_offset + LOWORD_OFFSET);
   AnnotateDalvikRegAccess(fld_1, (src1_v_reg_offset + LOWORD_OFFSET) >> 2,
                           true /* is_load */, is_double /* is64bit */);
@@ -417,7 +433,7 @@
   // Now store result in the destination VR's stack location.
   int displacement = dest_v_reg_offset + LOWORD_OFFSET;
   int opcode = is_double ? kX86Fst64M : kX86Fst32M;
-  LIR *fst = NewLIR2NoDest(opcode, rs_rX86_SP.GetReg(), displacement);
+  LIR *fst = NewLIR2NoDest(opcode, rs_rSP.GetReg(), displacement);
   AnnotateDalvikRegAccess(fst, displacement >> 2, false /* is_load */, is_double /* is64bit */);
 
   // Pop ST(1) and ST(0).
@@ -431,15 +447,14 @@
    * If the result's location is in memory, then we do not need to do anything
    * more since the fstp has already placed the correct value in memory.
    */
-  RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) :
-      UpdateLocTyped(rl_dest, kFPReg);
+  RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
   if (rl_result.location == kLocPhysReg) {
     rl_result = EvalLoc(rl_dest, kFPReg, true);
     if (is_double) {
-      LoadBaseDisp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
+      LoadBaseDisp(rs_rSP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
       StoreFinalValueWide(rl_dest, rl_result);
     } else {
-      Load32Disp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg);
+      Load32Disp(rs_rSP, dest_v_reg_offset, rl_result.reg);
       StoreFinalValue(rl_dest, rl_result);
     }
   }
@@ -569,16 +584,16 @@
 void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
   RegLocation rl_result;
   rl_src = LoadValueWide(rl_src, kCoreReg);
-  rl_result = EvalLocWide(rl_dest, kCoreReg, true);
   if (cu_->target64) {
+    rl_result = EvalLocWide(rl_dest, kCoreReg, true);
     OpRegCopy(rl_result.reg, rl_src.reg);
     // Flip sign bit.
     NewLIR2(kX86Rol64RI, rl_result.reg.GetReg(), 1);
     NewLIR2(kX86Xor64RI, rl_result.reg.GetReg(), 1);
     NewLIR2(kX86Ror64RI, rl_result.reg.GetReg(), 1);
   } else {
-    OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
-    OpRegCopy(rl_result.reg, rl_src.reg);
+    rl_result = ForceTempWide(rl_src);
+    OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), 0x80000000);
   }
   StoreValueWide(rl_dest, rl_result);
 }
@@ -627,7 +642,7 @@
     // Operate directly into memory.
     int displacement = SRegOffset(rl_dest.s_reg_low);
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP.GetReg(), displacement, 0x7fffffff);
+    LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP_32.GetReg(), displacement, 0x7fffffff);
     AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
     AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
     return true;
@@ -691,7 +706,7 @@
     // Operate directly into memory.
     int displacement = SRegOffset(rl_dest.s_reg_low);
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP.GetReg(), displacement  + HIWORD_OFFSET, 0x7fffffff);
+    LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP_32.GetReg(), displacement  + HIWORD_OFFSET, 0x7fffffff);
     AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
     AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
     return true;
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 4357657..ba9c611 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -20,7 +20,8 @@
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "mirror/art_method.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
+#include "utils.h"
 #include "x86_lir.h"
 
 namespace art {
@@ -208,7 +209,7 @@
 
 void X86Mir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
                                   int32_t true_val, int32_t false_val, RegStorage rs_dest,
-                                  int dest_reg_class) {
+                                  RegisterClass dest_reg_class) {
   DCHECK(!left_op.IsPair() && !right_op.IsPair() && !rs_dest.IsPair());
   DCHECK(!left_op.IsFloat() && !right_op.IsFloat() && !rs_dest.IsFloat());
 
@@ -268,6 +269,7 @@
 }
 
 void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb);
   RegLocation rl_result;
   RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
   RegLocation rl_dest = mir_graph_->GetDest(mir);
@@ -594,8 +596,9 @@
 }
 
 RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div) {
+  UNUSED(rl_dest, reg_lo, lit, is_div);
   LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
-  return rl_dest;
+  UNREACHABLE();
 }
 
 RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src,
@@ -654,7 +657,7 @@
     NewLIR3(kX86Lea32RM, rl_result.reg.GetReg(), rl_src.reg.GetReg(), std::abs(imm) - 1);
     NewLIR2(kX86Test32RR, rl_src.reg.GetReg(), rl_src.reg.GetReg());
     OpCondRegReg(kOpCmov, kCondPl, rl_result.reg, rl_src.reg);
-    int shift_amount = LowestSetBit(imm);
+    int shift_amount = CTZ(imm);
     OpRegImm(kOpAsr, rl_result.reg, shift_amount);
     if (imm < 0) {
       OpReg(kOpNeg, rl_result.reg);
@@ -763,12 +766,14 @@
 
 RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi,
                                   bool is_div) {
+  UNUSED(rl_dest, reg_lo, reg_hi, is_div);
   LOG(FATAL) << "Unexpected use of GenDivRem for x86";
-  return rl_dest;
+  UNREACHABLE();
 }
 
 RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
-                                  RegLocation rl_src2, bool is_div, bool check_zero) {
+                                  RegLocation rl_src2, bool is_div, int flags) {
+  UNUSED(rl_dest);
   // We have to use fixed registers, so flush all the temps.
 
   // Prepare for explicit register usage.
@@ -783,7 +788,7 @@
   // Copy LHS sign bit into EDX.
   NewLIR0(kx86Cdq32Da);
 
-  if (check_zero) {
+  if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
     // Handle division by zero case.
     GenDivZeroCheck(rs_r1);
   }
@@ -858,6 +863,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
@@ -1017,7 +1027,7 @@
     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
     // In 32-bit mode the only EAX..EDX registers can be used with Mov8MR.
     if (!cu_->target64 && size == kSignedByte) {
-      rl_src_value = UpdateLocTyped(rl_src_value, kCoreReg);
+      rl_src_value = UpdateLocTyped(rl_src_value);
       if (rl_src_value.location == kLocPhysReg && !IsByteRegister(rl_src_value.reg)) {
         RegStorage temp = AllocateByteRegister();
         OpRegCopy(temp, rl_src_value.reg);
@@ -1115,15 +1125,16 @@
     }
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
     const size_t push_offset = (push_si ? 4u : 0u) + (push_di ? 4u : 0u);
+    const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
     if (!obj_in_si && !obj_in_di) {
-      LoadWordDisp(rs_rX86_SP, SRegOffset(rl_src_obj.s_reg_low) + push_offset, rs_obj);
+      LoadWordDisp(rs_rSP, SRegOffset(rl_src_obj.s_reg_low) + push_offset, rs_obj);
       // Dalvik register annotation in LoadBaseIndexedDisp() used wrong offset. Fix it.
       DCHECK(!DECODE_ALIAS_INFO_WIDE(last_lir_insn_->flags.alias_info));
       int reg_id = DECODE_ALIAS_INFO_REG(last_lir_insn_->flags.alias_info) - push_offset / 4u;
       AnnotateDalvikRegAccess(last_lir_insn_, reg_id, true, false);
     }
     if (!off_in_si && !off_in_di) {
-      LoadWordDisp(rs_rX86_SP, SRegOffset(rl_src_offset.s_reg_low) + push_offset, rs_off);
+      LoadWordDisp(rs_rSP, SRegOffset(rl_src_offset.s_reg_low) + push_offset, rs_off);
       // Dalvik register annotation in LoadBaseIndexedDisp() used wrong offset. Fix it.
       DCHECK(!DECODE_ALIAS_INFO_WIDE(last_lir_insn_->flags.alias_info));
       int reg_id = DECODE_ALIAS_INFO_REG(last_lir_insn_->flags.alias_info) - push_offset / 4u;
@@ -1155,12 +1166,12 @@
     LockTemp(rs_r0);
 
     RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
-    RegLocation rl_new_value = LoadValue(rl_src_new_value);
+    RegLocation rl_new_value = LoadValue(rl_src_new_value, LocToRegClass(rl_src_new_value));
 
     if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
       // Mark card for object assuming new value is stored.
       FreeTemp(rs_r0);  // Temporarily release EAX for MarkGCCard().
-      MarkGCCard(rl_new_value.reg, rl_object.reg);
+      MarkGCCard(0, rl_new_value.reg, rl_object.reg);
       LockTemp(rs_r0);
     }
 
@@ -1279,6 +1290,18 @@
 }
 
 LIR* X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
+  if (cu_->target64) {
+    // We can do this directly using RIP addressing.
+    // We don't know the proper offset for the value, so pick one that will force
+    // 4 byte offset.  We will fix this up in the assembler later to have the right
+    // value.
+    ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
+    LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), kRIPReg, 256);
+    res->target = target;
+    res->flags.fixup = kFixupLoad;
+    return res;
+  }
+
   CHECK(base_of_code_ != nullptr);
 
   // Address the start of the method
@@ -1299,23 +1322,25 @@
                     0, 0, target);
   res->target = target;
   res->flags.fixup = kFixupLoad;
-  store_method_addr_used_ = true;
   return res;
 }
 
 LIR* X86Mir2Lir::OpVldm(RegStorage r_base, int count) {
+  UNUSED(r_base, count);
   LOG(FATAL) << "Unexpected use of OpVldm for x86";
-  return NULL;
+  UNREACHABLE();
 }
 
 LIR* X86Mir2Lir::OpVstm(RegStorage r_base, int count) {
+  UNUSED(r_base, count);
   LOG(FATAL) << "Unexpected use of OpVstm for x86";
-  return NULL;
+  UNREACHABLE();
 }
 
 void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
                                                RegLocation rl_result, int lit,
                                                int first_bit, int second_bit) {
+  UNUSED(lit);
   RegStorage t_reg = AllocTemp();
   OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
   OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
@@ -1350,10 +1375,10 @@
                                      int len_offset) {
   class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
    public:
-    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch,
-                             RegStorage index, RegStorage array_base, int32_t len_offset)
-        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
-          index_(index), array_base_(array_base), len_offset_(len_offset) {
+    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch_in,
+                             RegStorage index_in, RegStorage array_base_in, int32_t len_offset_in)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in),
+          index_(index_in), array_base_(array_base_in), len_offset_(len_offset_in) {
     }
 
     void Compile() OVERRIDE {
@@ -1398,10 +1423,10 @@
                                      int32_t len_offset) {
   class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
    public:
-    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch,
-                             int32_t index, RegStorage array_base, int32_t len_offset)
-        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
-          index_(index), array_base_(array_base), len_offset_(len_offset) {
+    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch_in,
+                             int32_t index_in, RegStorage array_base_in, int32_t len_offset_in)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch_in),
+          index_(index_in), array_base_(array_base_in), len_offset_(len_offset_in) {
     }
 
     void Compile() OVERRIDE {
@@ -1448,22 +1473,27 @@
 
 bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(dalvik_opcode, is_div, rl_src, rl_dest, lit);
   LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
-  return false;
+  UNREACHABLE();
 }
 
 bool X86Mir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
+  UNUSED(rl_src, rl_dest, lit);
   LOG(FATAL) << "Unexpected use of easyMultiply in x86";
-  return false;
+  UNREACHABLE();
 }
 
 LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
+  UNUSED(cond, guide);
   LOG(FATAL) << "Unexpected use of OpIT in x86";
-  return NULL;
+  UNREACHABLE();
 }
 
 void X86Mir2Lir::OpEndIT(LIR* it) {
+  UNUSED(it);
   LOG(FATAL) << "Unexpected use of OpEndIT in x86";
+  UNREACHABLE();
 }
 
 void X86Mir2Lir::GenImulRegImm(RegStorage dest, RegStorage src, int val) {
@@ -1481,6 +1511,7 @@
 }
 
 void X86Mir2Lir::GenImulMemImm(RegStorage dest, int sreg, int displacement, int val) {
+  UNUSED(sreg);
   // All memory accesses below reference dalvik regs.
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
 
@@ -1489,19 +1520,21 @@
     case 0:
       NewLIR2(kX86Xor32RR, dest.GetReg(), dest.GetReg());
       break;
-    case 1:
-      LoadBaseDisp(rs_rX86_SP, displacement, dest, k32, kNotVolatile);
+    case 1: {
+      const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
+      LoadBaseDisp(rs_rSP, displacement, dest, k32, kNotVolatile);
       break;
+    }
     default:
       m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(),
-                  rs_rX86_SP.GetReg(), displacement, val);
+                  rs_rX86_SP_32.GetReg(), displacement, val);
       AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */);
       break;
   }
 }
 
 void X86Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                                RegLocation rl_src2) {
+                                RegLocation rl_src2, int flags) {
   if (!cu_->target64) {
     // Some x86 32b ops are fallback.
     switch (opcode) {
@@ -1510,7 +1543,7 @@
       case Instruction::DIV_LONG_2ADDR:
       case Instruction::REM_LONG:
       case Instruction::REM_LONG_2ADDR:
-        Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+        Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
         return;
 
       default:
@@ -1536,17 +1569,17 @@
 
     case Instruction::MUL_LONG:
     case Instruction::MUL_LONG_2ADDR:
-      GenMulLong(opcode, rl_dest, rl_src1, rl_src2);
+      GenMulLong(opcode, rl_dest, rl_src1, rl_src2, flags);
       return;
 
     case Instruction::DIV_LONG:
     case Instruction::DIV_LONG_2ADDR:
-      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true);
+      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true, flags);
       return;
 
     case Instruction::REM_LONG:
     case Instruction::REM_LONG_2ADDR:
-      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false);
+      GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false, flags);
       return;
 
     case Instruction::AND_LONG_2ADDR:
@@ -1574,7 +1607,7 @@
   }
 }
 
-bool X86Mir2Lir::GenMulLongConst(RegLocation rl_dest, RegLocation rl_src1, int64_t val) {
+bool X86Mir2Lir::GenMulLongConst(RegLocation rl_dest, RegLocation rl_src1, int64_t val, int flags) {
   // All memory accesses below reference dalvik regs.
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
 
@@ -1592,14 +1625,14 @@
     StoreValueWide(rl_dest, rl_src1);
     return true;
   } else if (val == 2) {
-    GenArithOpLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1);
+    GenArithOpLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1, flags);
     return true;
   } else if (IsPowerOfTwo(val)) {
-    int shift_amount = LowestSetBit(val);
-    if (!BadOverlap(rl_src1, rl_dest)) {
+    int shift_amount = CTZ(val);
+    if (!PartiallyIntersects(rl_src1, rl_dest)) {
       rl_src1 = LoadValueWide(rl_src1, kCoreReg);
       RegLocation rl_result = GenShiftImmOpLong(Instruction::SHL_LONG, rl_dest, rl_src1,
-                                                shift_amount);
+                                                shift_amount, flags);
       StoreValueWide(rl_dest, rl_result);
       return true;
     }
@@ -1611,7 +1644,7 @@
     int32_t val_hi = High32Bits(val);
     // Prepare for explicit register usage.
     ExplicitTempRegisterLock(this, 3, &rs_r0, &rs_r1, &rs_r2);
-    rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
+    rl_src1 = UpdateLocWideTyped(rl_src1);
     bool src1_in_reg = rl_src1.location == kLocPhysReg;
     int displacement = SRegOffset(rl_src1.s_reg_low);
 
@@ -1635,7 +1668,7 @@
     if (src1_in_reg) {
       NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
     } else {
-      LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP.GetReg(), displacement + LOWORD_OFFSET);
+      LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP_32.GetReg(), displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
     }
@@ -1653,13 +1686,13 @@
 }
 
 void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
-                            RegLocation rl_src2) {
+                            RegLocation rl_src2, int flags) {
   if (rl_src1.is_const) {
     std::swap(rl_src1, rl_src2);
   }
 
   if (rl_src2.is_const) {
-    if (GenMulLongConst(rl_dest, rl_src1, mir_graph_->ConstantValueWide(rl_src2))) {
+    if (GenMulLongConst(rl_dest, rl_src1, mir_graph_->ConstantValueWide(rl_src2), flags)) {
       return;
     }
   }
@@ -1695,18 +1728,19 @@
 
   // Prepare for explicit register usage.
   ExplicitTempRegisterLock(this, 3, &rs_r0, &rs_r1, &rs_r2);
-  rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
-  rl_src2 = UpdateLocWideTyped(rl_src2, kCoreReg);
+  rl_src1 = UpdateLocWideTyped(rl_src1);
+  rl_src2 = UpdateLocWideTyped(rl_src2);
 
   // At this point, the VRs are in their home locations.
   bool src1_in_reg = rl_src1.location == kLocPhysReg;
   bool src2_in_reg = rl_src2.location == kLocPhysReg;
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
 
   // ECX <- 1H
   if (src1_in_reg) {
     NewLIR2(kX86Mov32RR, rs_r1.GetReg(), rl_src1.reg.GetHighReg());
   } else {
-    LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1, k32,
+    LoadBaseDisp(rs_rSP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1, k32,
                  kNotVolatile);
   }
 
@@ -1717,7 +1751,7 @@
       NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
     } else {
       int displacement = SRegOffset(rl_src2.s_reg_low);
-      LIR* m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP.GetReg(),
+      LIR* m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP_32.GetReg(),
                        displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
@@ -1730,7 +1764,7 @@
     if (src2_in_reg) {
       NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetHighReg());
     } else {
-      LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0, k32,
+      LoadBaseDisp(rs_rSP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0, k32,
                    kNotVolatile);
     }
 
@@ -1739,7 +1773,7 @@
       NewLIR2(kX86Imul32RR, rs_r0.GetReg(), rl_src1.reg.GetLowReg());
     } else {
       int displacement = SRegOffset(rl_src1.s_reg_low);
-      LIR *m = NewLIR3(kX86Imul32RM, rs_r0.GetReg(), rs_rX86_SP.GetReg(),
+      LIR *m = NewLIR3(kX86Imul32RM, rs_r0.GetReg(), rs_rX86_SP_32.GetReg(),
                        displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
@@ -1750,7 +1784,7 @@
       NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
     } else {
       int displacement = SRegOffset(rl_src2.s_reg_low);
-      LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP.GetReg(),
+      LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP_32.GetReg(),
                        displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
@@ -1764,7 +1798,7 @@
   if (src2_in_reg) {
     NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetLowReg());
   } else {
-    LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0, k32,
+    LoadBaseDisp(rs_rSP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0, k32,
                  kNotVolatile);
   }
 
@@ -1773,7 +1807,7 @@
     NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
   } else {
     int displacement = SRegOffset(rl_src1.s_reg_low);
-    LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP.GetReg(), displacement + LOWORD_OFFSET);
+    LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP_32.GetReg(), displacement + LOWORD_OFFSET);
     AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                             true /* is_load */, true /* is_64bit */);
   }
@@ -1808,7 +1842,6 @@
 
       x86op = GetOpcode(op, rl_dest, rl_src, true);
       NewLIR2(x86op, rl_dest.reg.GetHighReg(), rl_src.reg.GetHighReg());
-      FreeTemp(rl_src.reg);  // ???
     }
     return;
   }
@@ -1816,7 +1849,7 @@
   // RHS is in memory.
   DCHECK((rl_src.location == kLocDalvikFrame) ||
          (rl_src.location == kLocCompilerTemp));
-  int r_base = rs_rX86_SP.GetReg();
+  int r_base = rs_rX86_SP_32.GetReg();
   int displacement = SRegOffset(rl_src.s_reg_low);
 
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -1833,12 +1866,20 @@
 }
 
 void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
-  rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
+  rl_dest = UpdateLocWideTyped(rl_dest);
   if (rl_dest.location == kLocPhysReg) {
     // Ensure we are in a register pair
     RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
 
-    rl_src = UpdateLocWideTyped(rl_src, kCoreReg);
+    rl_src = UpdateLocWideTyped(rl_src);
+    GenLongRegOrMemOp(rl_result, rl_src, op);
+    StoreFinalValueWide(rl_dest, rl_result);
+    return;
+  } else if (!cu_->target64 && Intersects(rl_src, rl_dest)) {
+    // Handle the case when src and dest are intersect.
+    rl_src = LoadValueWide(rl_src, kCoreReg);
+    RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+    rl_src = UpdateLocWideTyped(rl_src);
     GenLongRegOrMemOp(rl_result, rl_src, op);
     StoreFinalValueWide(rl_dest, rl_result);
     return;
@@ -1851,7 +1892,7 @@
 
   // Operate directly into memory.
   X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
-  int r_base = rs_rX86_SP.GetReg();
+  int r_base = rs_rX86_SP_32.GetReg();
   int displacement = SRegOffset(rl_dest.s_reg_low);
 
   ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -1869,7 +1910,16 @@
     AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
                             false /* is_load */, true /* is64bit */);
   }
-  FreeTemp(rl_src.reg);
+
+  int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
+  int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+
+  // If the left operand is in memory and the right operand is in a register
+  // and both belong to the same dalvik register then we should clobber the
+  // right one because it doesn't hold valid data anymore.
+  if (v_src_reg == v_dst_reg) {
+    Clobber(rl_src.reg);
+  }
 }
 
 void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1,
@@ -1899,7 +1949,7 @@
     rl_result = ForceTempWide(rl_result);
 
     // Perform the operation using the RHS.
-    rl_src2 = UpdateLocWideTyped(rl_src2, kCoreReg);
+    rl_src2 = UpdateLocWideTyped(rl_src2);
     GenLongRegOrMemOp(rl_result, rl_src2, op);
 
     // And now record that the result is in the temp.
@@ -1908,10 +1958,9 @@
   }
 
   // It wasn't in registers, so it better be in memory.
-  DCHECK((rl_dest.location == kLocDalvikFrame) ||
-         (rl_dest.location == kLocCompilerTemp));
-  rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
-  rl_src2 = UpdateLocWideTyped(rl_src2, kCoreReg);
+  DCHECK((rl_dest.location == kLocDalvikFrame) || (rl_dest.location == kLocCompilerTemp));
+  rl_src1 = UpdateLocWideTyped(rl_src1);
+  rl_src2 = UpdateLocWideTyped(rl_src2);
 
   // Get one of the source operands into temporary register.
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
@@ -2022,7 +2071,7 @@
     OpRegReg(kOpAdd, rl_result.reg, rl_src.reg);
     NewLIR2(kX86Test64RR, rl_src.reg.GetReg(), rl_src.reg.GetReg());
     OpCondRegReg(kOpCmov, kCondPl, rl_result.reg, rl_src.reg);
-    int shift_amount = LowestSetBit(imm);
+    int shift_amount = CTZ(imm);
     OpRegImm(kOpAsr, rl_result.reg, shift_amount);
     if (imm < 0) {
       OpReg(kOpNeg, rl_result.reg);
@@ -2077,13 +2126,13 @@
       NewLIR1(kX86Imul64DaR, numerator_reg.GetReg());
     } else {
       // Only need this once.  Multiply directly from the value.
-      rl_src = UpdateLocWideTyped(rl_src, kCoreReg);
+      rl_src = UpdateLocWideTyped(rl_src);
       if (rl_src.location != kLocPhysReg) {
         // Okay, we can do this from memory.
         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
         int displacement = SRegOffset(rl_src.s_reg_low);
         // RDX:RAX = magic * numerator.
-        LIR *m = NewLIR2(kX86Imul64DaM, rs_rX86_SP.GetReg(), displacement);
+        LIR *m = NewLIR2(kX86Imul64DaM, rs_rX86_SP_32.GetReg(), displacement);
         AnnotateDalvikRegAccess(m, displacement >> 2,
                                 true /* is_load */, true /* is_64bit */);
       } else {
@@ -2153,7 +2202,7 @@
 }
 
 void X86Mir2Lir::GenDivRemLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
-                               RegLocation rl_src2, bool is_div) {
+                               RegLocation rl_src2, bool is_div, int flags) {
   if (!cu_->target64) {
     LOG(FATAL) << "Unexpected use GenDivRemLong()";
     return;
@@ -2180,7 +2229,9 @@
   NewLIR0(kx86Cqo64Da);
 
   // Handle division by zero case.
-  GenDivZeroCheckWide(rs_r1q);
+  if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
+    GenDivZeroCheckWide(rs_r1q);
+  }
 
   // Have to catch 0x8000000000000000/-1 case, or we will get an exception!
   NewLIR2(kX86Cmp64RI8, rs_r1q.GetReg(), -1);
@@ -2221,13 +2272,6 @@
     OpRegReg(kOpNeg, rl_result.reg, rl_src.reg);
   } else {
     rl_result = ForceTempWide(rl_src);
-    if (((rl_dest.location == kLocPhysReg) && (rl_src.location == kLocPhysReg)) &&
-        ((rl_dest.reg.GetLowReg() == rl_src.reg.GetHighReg()))) {
-      // The registers are the same, so we would clobber it before the use.
-      RegStorage temp_reg = AllocTemp();
-      OpRegCopy(temp_reg, rl_result.reg);
-      rl_result.reg.SetHighReg(temp_reg.GetReg());
-    }
     OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_result.reg.GetLow());    // rLow = -rLow
     OpRegImm(kOpAdc, rl_result.reg.GetHigh(), 0);                   // rHigh = rHigh + CF
     OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_result.reg.GetHigh());  // rHigh = -rHigh
@@ -2276,7 +2320,7 @@
  */
 void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale) {
-  RegisterClass reg_class = RegClassBySize(size);
+  RegisterClass reg_class = RegClassForFieldLoadStore(size, false);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   RegLocation rl_result;
   rl_array = LoadValue(rl_array, kRefReg);
@@ -2325,7 +2369,7 @@
  */
 void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
-  RegisterClass reg_class = RegClassBySize(size);
+  RegisterClass reg_class = RegClassForFieldLoadStore(size, false);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
 
@@ -2376,12 +2420,13 @@
     if (!constant_index) {
       FreeTemp(rl_index.reg);
     }
-    MarkGCCard(rl_src.reg, rl_array.reg);
+    MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
   }
 }
 
 RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                          RegLocation rl_src, int shift_amount) {
+                                          RegLocation rl_src, int shift_amount, int flags) {
+  UNUSED(flags);
   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
   if (cu_->target64) {
     OpKind op = static_cast<OpKind>(0);    /* Make gcc happy */
@@ -2466,7 +2511,7 @@
 }
 
 void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src, RegLocation rl_shift) {
+                                   RegLocation rl_src, RegLocation rl_shift, int flags) {
   // Per spec, we only care about low 6 bits of shift amount.
   int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
   if (shift_amount == 0) {
@@ -2476,20 +2521,21 @@
   } else if (shift_amount == 1 &&
             (opcode ==  Instruction::SHL_LONG || opcode == Instruction::SHL_LONG_2ADDR)) {
     // Need to handle this here to avoid calling StoreValueWide twice.
-    GenArithOpLong(Instruction::ADD_LONG, rl_dest, rl_src, rl_src);
+    GenArithOpLong(Instruction::ADD_LONG, rl_dest, rl_src, rl_src, flags);
     return;
   }
-  if (BadOverlap(rl_src, rl_dest)) {
+  if (PartiallyIntersects(rl_src, rl_dest)) {
     GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
     return;
   }
   rl_src = LoadValueWide(rl_src, kCoreReg);
-  RegLocation rl_result = GenShiftImmOpLong(opcode, rl_dest, rl_src, shift_amount);
+  RegLocation rl_result = GenShiftImmOpLong(opcode, rl_dest, rl_src, shift_amount, flags);
   StoreValueWide(rl_dest, rl_result);
 }
 
 void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
-                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
+                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
+                                   int flags) {
   bool isConstSuccess = false;
   switch (opcode) {
     case Instruction::ADD_LONG:
@@ -2508,7 +2554,7 @@
       if (rl_src2.is_const) {
         isConstSuccess = GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
       } else {
-        GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+        GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
         isConstSuccess = true;
       }
       break;
@@ -2534,7 +2580,7 @@
 
   if (!isConstSuccess) {
     // Default - bail to non-const handler.
-    GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+    GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
   }
 }
 
@@ -2678,7 +2724,7 @@
       return in_mem ? kX86Xor32MI : kX86Xor32RI;
     default:
       LOG(FATAL) << "Unexpected opcode: " << op;
-      return kX86Add32MI;
+      UNREACHABLE();
   }
 }
 
@@ -2692,11 +2738,11 @@
       return false;
     }
 
-    rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
+    rl_dest = UpdateLocWideTyped(rl_dest);
 
     if ((rl_dest.location == kLocDalvikFrame) ||
         (rl_dest.location == kLocCompilerTemp)) {
-      int r_base = rs_rX86_SP.GetReg();
+      int r_base = rs_rX86_SP_32.GetReg();
       int displacement = SRegOffset(rl_dest.s_reg_low);
 
       ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -2722,12 +2768,12 @@
 
   int32_t val_lo = Low32Bits(val);
   int32_t val_hi = High32Bits(val);
-  rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
+  rl_dest = UpdateLocWideTyped(rl_dest);
 
   // Can we just do this into memory?
   if ((rl_dest.location == kLocDalvikFrame) ||
       (rl_dest.location == kLocCompilerTemp)) {
-    int r_base = rs_rX86_SP.GetReg();
+    int r_base = rs_rX86_SP_32.GetReg();
     int displacement = SRegOffset(rl_dest.s_reg_low);
 
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -2798,8 +2844,8 @@
 
   int32_t val_lo = Low32Bits(val);
   int32_t val_hi = High32Bits(val);
-  rl_dest = UpdateLocWideTyped(rl_dest, kCoreReg);
-  rl_src1 = UpdateLocWideTyped(rl_src1, kCoreReg);
+  rl_dest = UpdateLocWideTyped(rl_dest);
+  rl_src1 = UpdateLocWideTyped(rl_src1);
 
   // Can we do this directly into the destination registers?
   if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
@@ -2906,7 +2952,7 @@
 }
 
 void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
-                            RegLocation rl_lhs, RegLocation rl_rhs) {
+                            RegLocation rl_lhs, RegLocation rl_rhs, int flags) {
   OpKind op = kOpBkpt;
   bool is_div_rem = false;
   bool unary = false;
@@ -2924,25 +2970,25 @@
       break;
     case Instruction::ADD_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::ADD_INT:
       op = kOpAdd;
       break;
     case Instruction::SUB_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::SUB_INT:
       op = kOpSub;
       break;
     case Instruction::MUL_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::MUL_INT:
       op = kOpMul;
       break;
     case Instruction::DIV_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::DIV_INT:
       op = kOpDiv;
       is_div_rem = true;
@@ -2950,46 +2996,46 @@
     /* NOTE: returns in kArg1 */
     case Instruction::REM_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::REM_INT:
       op = kOpRem;
       is_div_rem = true;
       break;
     case Instruction::AND_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::AND_INT:
       op = kOpAnd;
       break;
     case Instruction::OR_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::OR_INT:
       op = kOpOr;
       break;
     case Instruction::XOR_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::XOR_INT:
       op = kOpXor;
       break;
     case Instruction::SHL_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::SHL_INT:
       shift_op = true;
       op = kOpLsl;
       break;
     case Instruction::SHR_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::SHR_INT:
       shift_op = true;
       op = kOpAsr;
       break;
     case Instruction::USHR_INT_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::USHR_INT:
       shift_op = true;
       op = kOpLsr;
@@ -3011,7 +3057,7 @@
 
   // Get the div/rem stuff out of the way.
   if (is_div_rem) {
-    rl_result = GenDivRem(rl_dest, rl_lhs, rl_rhs, op == kOpDiv, true);
+    rl_result = GenDivRem(rl_dest, rl_lhs, rl_rhs, op == kOpDiv, flags);
     StoreValue(rl_dest, rl_result);
     return;
   }
@@ -3021,7 +3067,7 @@
 
   if (unary) {
     rl_lhs = LoadValue(rl_lhs, kCoreReg);
-    rl_result = UpdateLocTyped(rl_dest, kCoreReg);
+    rl_result = UpdateLocTyped(rl_dest);
     rl_result = EvalLoc(rl_dest, kCoreReg, true);
     OpRegReg(op, rl_result.reg, rl_lhs.reg);
   } else {
@@ -3031,7 +3077,7 @@
       LoadValueDirectFixed(rl_rhs, t_reg);
       if (is_two_addr) {
         // Can we do this directly into memory?
-        rl_result = UpdateLocTyped(rl_dest, kCoreReg);
+        rl_result = UpdateLocTyped(rl_dest);
         if (rl_result.location != kLocPhysReg) {
           // Okay, we can do this into memory
           OpMemReg(op, rl_result, t_reg.GetReg());
@@ -3054,12 +3100,12 @@
       // Multiply is 3 operand only (sort of).
       if (is_two_addr && op != kOpMul) {
         // Can we do this directly into memory?
-        rl_result = UpdateLocTyped(rl_dest, kCoreReg);
+        rl_result = UpdateLocTyped(rl_dest);
         if (rl_result.location == kLocPhysReg) {
           // Ensure res is in a core reg
           rl_result = EvalLoc(rl_dest, kCoreReg, true);
           // Can we do this from memory directly?
-          rl_rhs = UpdateLocTyped(rl_rhs, kCoreReg);
+          rl_rhs = UpdateLocTyped(rl_rhs);
           if (rl_rhs.location != kLocPhysReg) {
             OpRegMem(op, rl_result.reg, rl_rhs);
             StoreFinalValue(rl_dest, rl_result);
@@ -3074,7 +3120,7 @@
         // It might happen rl_rhs and rl_dest are the same VR
         // in this case rl_dest is in reg after LoadValue while
         // rl_result is not updated yet, so do this
-        rl_result = UpdateLocTyped(rl_dest, kCoreReg);
+        rl_result = UpdateLocTyped(rl_dest);
         if (rl_result.location != kLocPhysReg) {
           // Okay, we can do this into memory.
           OpMemReg(op, rl_result, rl_rhs.reg.GetReg());
@@ -3091,8 +3137,8 @@
         }
       } else {
         // Try to use reg/memory instructions.
-        rl_lhs = UpdateLocTyped(rl_lhs, kCoreReg);
-        rl_rhs = UpdateLocTyped(rl_rhs, kCoreReg);
+        rl_lhs = UpdateLocTyped(rl_lhs);
+        rl_rhs = UpdateLocTyped(rl_rhs);
         // We can't optimize with FP registers.
         if (!IsOperationSafeWithoutTemps(rl_lhs, rl_rhs)) {
           // Something is difficult, so fall back to the standard case.
@@ -3164,14 +3210,14 @@
     Mir2Lir::GenIntToLong(rl_dest, rl_src);
     return;
   }
-  rl_src = UpdateLocTyped(rl_src, kCoreReg);
+  rl_src = UpdateLocTyped(rl_src);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (rl_src.location == kLocPhysReg) {
     NewLIR2(kX86MovsxdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
   } else {
     int displacement = SRegOffset(rl_src.s_reg_low);
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    LIR *m = NewLIR3(kX86MovsxdRM, rl_result.reg.GetReg(), rs_rX86_SP.GetReg(),
+    LIR *m = NewLIR3(kX86MovsxdRM, rl_result.reg.GetReg(), rs_rX86_SP_32.GetReg(),
                      displacement + LOWORD_OFFSET);
     AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                             true /* is_load */, true /* is_64bit */);
@@ -3179,6 +3225,26 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
+void X86Mir2Lir::GenLongToInt(RegLocation rl_dest, RegLocation rl_src) {
+  rl_src = UpdateLocWide(rl_src);
+  rl_src = NarrowRegLoc(rl_src);
+  StoreValue(rl_dest, rl_src);
+
+  if (cu_->target64) {
+    // if src and dest are in the same phys reg then StoreValue generates
+    // no operation but we need explicit 32-bit mov R, R to clear
+    // the higher 32-bits
+    rl_dest = UpdateLoc(rl_dest);
+    if (rl_src.location == kLocPhysReg && rl_dest.location == kLocPhysReg
+           && IsSameReg(rl_src.reg, rl_dest.reg)) {
+        LIR* copy_lir = OpRegCopyNoInsert(rl_dest.reg, rl_dest.reg);
+        // remove nop flag set by OpRegCopyNoInsert if src == dest
+        copy_lir->flags.is_nop = false;
+        AppendLIR(copy_lir);
+    }
+  }
+}
+
 void X86Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
                         RegLocation rl_src1, RegLocation rl_shift) {
   if (!cu_->target64) {
@@ -3239,19 +3305,19 @@
   switch (opcode) {
     case Instruction::SHL_LONG_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::SHL_LONG:
       op = kOpLsl;
       break;
     case Instruction::SHR_LONG_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::SHR_LONG:
       op = kOpAsr;
       break;
     case Instruction::USHR_LONG_2ADDR:
       is_two_addr = true;
-      // Fallthrough
+      FALLTHROUGH_INTENDED;
     case Instruction::USHR_LONG:
       op = kOpLsr;
       break;
@@ -3264,7 +3330,7 @@
   LoadValueDirectFixed(rl_shift, t_reg);
   if (is_two_addr) {
     // Can we do this directly into memory?
-    rl_result = UpdateLocWideTyped(rl_dest, kCoreReg);
+    rl_result = UpdateLocWideTyped(rl_dest);
     if (rl_result.location != kLocPhysReg) {
       // Okay, we can do this into memory
       ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 9aeaf60..142acbc 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -18,12 +18,13 @@
 #include <inttypes.h>
 #include <string>
 
+#include "arch/instruction_set_features.h"
 #include "backend_x86.h"
 #include "codegen_x86.h"
 #include "dex/compiler_internals.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/string.h"
 #include "oat.h"
@@ -141,46 +142,6 @@
 static constexpr ArrayRef<const RegStorage> xp_temps_32(xp_temps_arr_32);
 static constexpr ArrayRef<const RegStorage> xp_temps_64(xp_temps_arr_64);
 
-RegStorage rs_rX86_SP;
-
-X86NativeRegisterPool rX86_ARG0;
-X86NativeRegisterPool rX86_ARG1;
-X86NativeRegisterPool rX86_ARG2;
-X86NativeRegisterPool rX86_ARG3;
-X86NativeRegisterPool rX86_ARG4;
-X86NativeRegisterPool rX86_ARG5;
-X86NativeRegisterPool rX86_FARG0;
-X86NativeRegisterPool rX86_FARG1;
-X86NativeRegisterPool rX86_FARG2;
-X86NativeRegisterPool rX86_FARG3;
-X86NativeRegisterPool rX86_FARG4;
-X86NativeRegisterPool rX86_FARG5;
-X86NativeRegisterPool rX86_FARG6;
-X86NativeRegisterPool rX86_FARG7;
-X86NativeRegisterPool rX86_RET0;
-X86NativeRegisterPool rX86_RET1;
-X86NativeRegisterPool rX86_INVOKE_TGT;
-X86NativeRegisterPool rX86_COUNT;
-
-RegStorage rs_rX86_ARG0;
-RegStorage rs_rX86_ARG1;
-RegStorage rs_rX86_ARG2;
-RegStorage rs_rX86_ARG3;
-RegStorage rs_rX86_ARG4;
-RegStorage rs_rX86_ARG5;
-RegStorage rs_rX86_FARG0;
-RegStorage rs_rX86_FARG1;
-RegStorage rs_rX86_FARG2;
-RegStorage rs_rX86_FARG3;
-RegStorage rs_rX86_FARG4;
-RegStorage rs_rX86_FARG5;
-RegStorage rs_rX86_FARG6;
-RegStorage rs_rX86_FARG7;
-RegStorage rs_rX86_RET0;
-RegStorage rs_rX86_RET1;
-RegStorage rs_rX86_INVOKE_TGT;
-RegStorage rs_rX86_COUNT;
-
 RegLocation X86Mir2Lir::LocCReturn() {
   return x86_loc_c_return;
 }
@@ -201,44 +162,100 @@
   return x86_loc_c_return_double;
 }
 
+// 32-bit reg storage locations for 32-bit targets.
+static const RegStorage RegStorage32FromSpecialTargetRegister_Target32[] {
+  RegStorage::InvalidReg(),  // kSelf - Thread pointer.
+  RegStorage::InvalidReg(),  // kSuspend - Used to reduce suspend checks for some targets.
+  RegStorage::InvalidReg(),  // kLr - no register as the return address is pushed on entry.
+  RegStorage::InvalidReg(),  // kPc - not exposed on X86 see kX86StartOfMethod.
+  rs_rX86_SP_32,             // kSp
+  rs_rAX,                    // kArg0
+  rs_rCX,                    // kArg1
+  rs_rDX,                    // kArg2
+  rs_rBX,                    // kArg3
+  RegStorage::InvalidReg(),  // kArg4
+  RegStorage::InvalidReg(),  // kArg5
+  RegStorage::InvalidReg(),  // kArg6
+  RegStorage::InvalidReg(),  // kArg7
+  rs_rAX,                    // kFArg0
+  rs_rCX,                    // kFArg1
+  rs_rDX,                    // kFArg2
+  rs_rBX,                    // kFArg3
+  RegStorage::InvalidReg(),  // kFArg4
+  RegStorage::InvalidReg(),  // kFArg5
+  RegStorage::InvalidReg(),  // kFArg6
+  RegStorage::InvalidReg(),  // kFArg7
+  RegStorage::InvalidReg(),  // kFArg8
+  RegStorage::InvalidReg(),  // kFArg9
+  RegStorage::InvalidReg(),  // kFArg10
+  RegStorage::InvalidReg(),  // kFArg11
+  RegStorage::InvalidReg(),  // kFArg12
+  RegStorage::InvalidReg(),  // kFArg13
+  RegStorage::InvalidReg(),  // kFArg14
+  RegStorage::InvalidReg(),  // kFArg15
+  rs_rAX,                    // kRet0
+  rs_rDX,                    // kRet1
+  rs_rAX,                    // kInvokeTgt
+  rs_rAX,                    // kHiddenArg - used to hold the method index before copying to fr0.
+  rs_fr0,                    // kHiddenFpArg
+  rs_rCX,                    // kCount
+};
+
+// 32-bit reg storage locations for 64-bit targets.
+static const RegStorage RegStorage32FromSpecialTargetRegister_Target64[] {
+  RegStorage::InvalidReg(),  // kSelf - Thread pointer.
+  RegStorage::InvalidReg(),  // kSuspend - Used to reduce suspend checks for some targets.
+  RegStorage::InvalidReg(),  // kLr - no register as the return address is pushed on entry.
+  RegStorage(kRIPReg),       // kPc
+  rs_rX86_SP_32,             // kSp
+  rs_rDI,                    // kArg0
+  rs_rSI,                    // kArg1
+  rs_rDX,                    // kArg2
+  rs_rCX,                    // kArg3
+  rs_r8,                     // kArg4
+  rs_r9,                     // kArg5
+  RegStorage::InvalidReg(),  // kArg6
+  RegStorage::InvalidReg(),  // kArg7
+  rs_fr0,                    // kFArg0
+  rs_fr1,                    // kFArg1
+  rs_fr2,                    // kFArg2
+  rs_fr3,                    // kFArg3
+  rs_fr4,                    // kFArg4
+  rs_fr5,                    // kFArg5
+  rs_fr6,                    // kFArg6
+  rs_fr7,                    // kFArg7
+  RegStorage::InvalidReg(),  // kFArg8
+  RegStorage::InvalidReg(),  // kFArg9
+  RegStorage::InvalidReg(),  // kFArg10
+  RegStorage::InvalidReg(),  // kFArg11
+  RegStorage::InvalidReg(),  // kFArg12
+  RegStorage::InvalidReg(),  // kFArg13
+  RegStorage::InvalidReg(),  // kFArg14
+  RegStorage::InvalidReg(),  // kFArg15
+  rs_rAX,                    // kRet0
+  rs_rDX,                    // kRet1
+  rs_rAX,                    // kInvokeTgt
+  rs_rAX,                    // kHiddenArg
+  RegStorage::InvalidReg(),  // kHiddenFpArg
+  rs_rCX,                    // kCount
+};
+static_assert(arraysize(RegStorage32FromSpecialTargetRegister_Target32) ==
+              arraysize(RegStorage32FromSpecialTargetRegister_Target64),
+              "Mismatch in RegStorage array sizes");
+
 // Return a target-dependent special register for 32-bit.
-RegStorage X86Mir2Lir::TargetReg32(SpecialTargetRegister reg) {
-  RegStorage res_reg = RegStorage::InvalidReg();
-  switch (reg) {
-    case kSelf: res_reg = RegStorage::InvalidReg(); break;
-    case kSuspend: res_reg =  RegStorage::InvalidReg(); break;
-    case kLr: res_reg =  RegStorage::InvalidReg(); break;
-    case kPc: res_reg =  RegStorage::InvalidReg(); break;
-    case kSp: res_reg =  rs_rX86_SP_32; break;  // This must be the concrete one, as _SP is target-
-                                                // specific size.
-    case kArg0: res_reg = rs_rX86_ARG0; break;
-    case kArg1: res_reg = rs_rX86_ARG1; break;
-    case kArg2: res_reg = rs_rX86_ARG2; break;
-    case kArg3: res_reg = rs_rX86_ARG3; break;
-    case kArg4: res_reg = rs_rX86_ARG4; break;
-    case kArg5: res_reg = rs_rX86_ARG5; break;
-    case kFArg0: res_reg = rs_rX86_FARG0; break;
-    case kFArg1: res_reg = rs_rX86_FARG1; break;
-    case kFArg2: res_reg = rs_rX86_FARG2; break;
-    case kFArg3: res_reg = rs_rX86_FARG3; break;
-    case kFArg4: res_reg = rs_rX86_FARG4; break;
-    case kFArg5: res_reg = rs_rX86_FARG5; break;
-    case kFArg6: res_reg = rs_rX86_FARG6; break;
-    case kFArg7: res_reg = rs_rX86_FARG7; break;
-    case kRet0: res_reg = rs_rX86_RET0; break;
-    case kRet1: res_reg = rs_rX86_RET1; break;
-    case kInvokeTgt: res_reg = rs_rX86_INVOKE_TGT; break;
-    case kHiddenArg: res_reg = rs_rAX; break;
-    case kHiddenFpArg: DCHECK(!cu_->target64); res_reg = rs_fr0; break;
-    case kCount: res_reg = rs_rX86_COUNT; break;
-    default: res_reg = RegStorage::InvalidReg();
-  }
-  return res_reg;
+RegStorage X86Mir2Lir::TargetReg32(SpecialTargetRegister reg) const {
+  DCHECK_EQ(RegStorage32FromSpecialTargetRegister_Target32[kCount], rs_rCX);
+  DCHECK_EQ(RegStorage32FromSpecialTargetRegister_Target64[kCount], rs_rCX);
+  DCHECK_LT(reg, arraysize(RegStorage32FromSpecialTargetRegister_Target32));
+  return cu_->target64 ? RegStorage32FromSpecialTargetRegister_Target64[reg]
+                       : RegStorage32FromSpecialTargetRegister_Target32[reg];
 }
 
 RegStorage X86Mir2Lir::TargetReg(SpecialTargetRegister reg) {
+  UNUSED(reg);
   LOG(FATAL) << "Do not use this function!!!";
-  return RegStorage::InvalidReg();
+  UNREACHABLE();
 }
 
 /*
@@ -451,7 +468,7 @@
 RegStorage X86Mir2Lir::AllocateByteRegister() {
   RegStorage reg = AllocTypedTemp(false, kCoreReg);
   if (!cu_->target64) {
-    DCHECK_LT(reg.GetRegNum(), rs_rX86_SP.GetRegNum());
+    DCHECK_LT(reg.GetRegNum(), rs_rX86_SP_32.GetRegNum());
   }
   return reg;
 }
@@ -460,8 +477,8 @@
   return GetRegInfo(reg)->Master()->GetReg();
 }
 
-bool X86Mir2Lir::IsByteRegister(RegStorage reg) {
-  return cu_->target64 || reg.GetRegNum() < rs_rX86_SP.GetRegNum();
+bool X86Mir2Lir::IsByteRegister(RegStorage reg) const {
+  return cu_->target64 || reg.GetRegNum() < rs_rX86_SP_32.GetRegNum();
 }
 
 /* Clobber all regs that might be used by an external C call */
@@ -501,8 +518,8 @@
 
 RegLocation X86Mir2Lir::GetReturnWideAlt() {
   RegLocation res = LocCReturnWide();
-  DCHECK(res.reg.GetLowReg() == rs_rAX.GetReg());
-  DCHECK(res.reg.GetHighReg() == rs_rDX.GetReg());
+  DCHECK_EQ(res.reg.GetLowReg(), rs_rAX.GetReg());
+  DCHECK_EQ(res.reg.GetHighReg(), rs_rDX.GetReg());
   Clobber(rs_rAX);
   Clobber(rs_rDX);
   MarkInUse(rs_rAX);
@@ -521,41 +538,42 @@
 
 /* To be used when explicitly managing register use */
 void X86Mir2Lir::LockCallTemps() {
-  LockTemp(rs_rX86_ARG0);
-  LockTemp(rs_rX86_ARG1);
-  LockTemp(rs_rX86_ARG2);
-  LockTemp(rs_rX86_ARG3);
+  LockTemp(TargetReg32(kArg0));
+  LockTemp(TargetReg32(kArg1));
+  LockTemp(TargetReg32(kArg2));
+  LockTemp(TargetReg32(kArg3));
   if (cu_->target64) {
-    LockTemp(rs_rX86_ARG4);
-    LockTemp(rs_rX86_ARG5);
-    LockTemp(rs_rX86_FARG0);
-    LockTemp(rs_rX86_FARG1);
-    LockTemp(rs_rX86_FARG2);
-    LockTemp(rs_rX86_FARG3);
-    LockTemp(rs_rX86_FARG4);
-    LockTemp(rs_rX86_FARG5);
-    LockTemp(rs_rX86_FARG6);
-    LockTemp(rs_rX86_FARG7);
+    LockTemp(TargetReg32(kArg4));
+    LockTemp(TargetReg32(kArg5));
+    LockTemp(TargetReg32(kFArg0));
+    LockTemp(TargetReg32(kFArg1));
+    LockTemp(TargetReg32(kFArg2));
+    LockTemp(TargetReg32(kFArg3));
+    LockTemp(TargetReg32(kFArg4));
+    LockTemp(TargetReg32(kFArg5));
+    LockTemp(TargetReg32(kFArg6));
+    LockTemp(TargetReg32(kFArg7));
   }
 }
 
 /* To be used when explicitly managing register use */
 void X86Mir2Lir::FreeCallTemps() {
-  FreeTemp(rs_rX86_ARG0);
-  FreeTemp(rs_rX86_ARG1);
-  FreeTemp(rs_rX86_ARG2);
-  FreeTemp(rs_rX86_ARG3);
+  FreeTemp(TargetReg32(kArg0));
+  FreeTemp(TargetReg32(kArg1));
+  FreeTemp(TargetReg32(kArg2));
+  FreeTemp(TargetReg32(kArg3));
+  FreeTemp(TargetReg32(kHiddenArg));
   if (cu_->target64) {
-    FreeTemp(rs_rX86_ARG4);
-    FreeTemp(rs_rX86_ARG5);
-    FreeTemp(rs_rX86_FARG0);
-    FreeTemp(rs_rX86_FARG1);
-    FreeTemp(rs_rX86_FARG2);
-    FreeTemp(rs_rX86_FARG3);
-    FreeTemp(rs_rX86_FARG4);
-    FreeTemp(rs_rX86_FARG5);
-    FreeTemp(rs_rX86_FARG6);
-    FreeTemp(rs_rX86_FARG7);
+    FreeTemp(TargetReg32(kArg4));
+    FreeTemp(TargetReg32(kArg5));
+    FreeTemp(TargetReg32(kFArg0));
+    FreeTemp(TargetReg32(kFArg1));
+    FreeTemp(TargetReg32(kFArg2));
+    FreeTemp(TargetReg32(kFArg3));
+    FreeTemp(TargetReg32(kFArg4));
+    FreeTemp(TargetReg32(kFArg5));
+    FreeTemp(TargetReg32(kFArg6));
+    FreeTemp(TargetReg32(kFArg7));
   }
 }
 
@@ -578,7 +596,9 @@
 }
 
 bool X86Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
-#if ANDROID_SMP != 0
+  if (!cu_->GetInstructionSetFeatures()->IsSmp()) {
+    return false;
+  }
   // Start off with using the last LIR as the barrier. If it is not enough, then we will update it.
   LIR* mem_barrier = last_lir_insn_;
 
@@ -614,9 +634,6 @@
     mem_barrier->u.m.def_mask = &kEncodeAll;
   }
   return ret;
-#else
-  return false;
-#endif
 }
 
 void X86Mir2Lir::CompilerInitializeRegAlloc() {
@@ -646,6 +663,12 @@
     xp_reg_info->SetIsTemp(true);
   }
 
+  // Special Handling for x86_64 RIP addressing.
+  if (cu_->target64) {
+    RegisterInfo* info = new (arena_) RegisterInfo(RegStorage(kRIPReg), kEncodeNone);
+    reginfo_map_[kRIPReg] = info;
+  }
+
   // Alias single precision xmm to double xmms.
   // TODO: as needed, add larger vector sizes - alias all to the largest.
   for (RegisterInfo* info : reg_pool_->sp_regs_) {
@@ -705,11 +728,14 @@
   }
   // Spill mask not including fake return address register
   uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
-  int offset = frame_size_ - (GetInstructionSetPointerSize(cu_->instruction_set) * num_core_spills_);
+  int offset =
+      frame_size_ - (GetInstructionSetPointerSize(cu_->instruction_set) * num_core_spills_);
   OpSize size = cu_->target64 ? k64 : k32;
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
   for (int reg = 0; mask; mask >>= 1, reg++) {
     if (mask & 0x1) {
-      StoreBaseDisp(rs_rX86_SP, offset, cu_->target64 ? RegStorage::Solo64(reg) :  RegStorage::Solo32(reg),
+      StoreBaseDisp(rs_rSP, offset,
+                    cu_->target64 ? RegStorage::Solo64(reg) :  RegStorage::Solo32(reg),
                    size, kNotVolatile);
       offset += GetInstructionSetPointerSize(cu_->instruction_set);
     }
@@ -724,9 +750,10 @@
   uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
   int offset = frame_size_ - (GetInstructionSetPointerSize(cu_->instruction_set) * num_core_spills_);
   OpSize size = cu_->target64 ? k64 : k32;
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
   for (int reg = 0; mask; mask >>= 1, reg++) {
     if (mask & 0x1) {
-      LoadBaseDisp(rs_rX86_SP, offset, cu_->target64 ? RegStorage::Solo64(reg) :  RegStorage::Solo32(reg),
+      LoadBaseDisp(rs_rSP, offset, cu_->target64 ? RegStorage::Solo64(reg) :  RegStorage::Solo32(reg),
                    size, kNotVolatile);
       offset += GetInstructionSetPointerSize(cu_->instruction_set);
     }
@@ -738,11 +765,12 @@
     return;
   }
   uint32_t mask = fp_spill_mask_;
-  int offset = frame_size_ - (GetInstructionSetPointerSize(cu_->instruction_set) * (num_fp_spills_ + num_core_spills_));
+  int offset = frame_size_ -
+      (GetInstructionSetPointerSize(cu_->instruction_set) * (num_fp_spills_ + num_core_spills_));
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
   for (int reg = 0; mask; mask >>= 1, reg++) {
     if (mask & 0x1) {
-      StoreBaseDisp(rs_rX86_SP, offset, RegStorage::FloatSolo64(reg),
-                   k64, kNotVolatile);
+      StoreBaseDisp(rs_rSP, offset, RegStorage::FloatSolo64(reg), k64, kNotVolatile);
       offset += sizeof(double);
     }
   }
@@ -752,10 +780,12 @@
     return;
   }
   uint32_t mask = fp_spill_mask_;
-  int offset = frame_size_ - (GetInstructionSetPointerSize(cu_->instruction_set) * (num_fp_spills_ + num_core_spills_));
+  int offset = frame_size_ -
+      (GetInstructionSetPointerSize(cu_->instruction_set) * (num_fp_spills_ + num_core_spills_));
+  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
   for (int reg = 0; mask; mask >>= 1, reg++) {
     if (mask & 0x1) {
-      LoadBaseDisp(rs_rX86_SP, offset, RegStorage::FloatSolo64(reg),
+      LoadBaseDisp(rs_rSP, offset, RegStorage::FloatSolo64(reg),
                    k64, kNotVolatile);
       offset += sizeof(double);
     }
@@ -768,6 +798,12 @@
 }
 
 RegisterClass X86Mir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
+  // Prefer XMM registers.  Fixes a problem with iget/iput to a FP when cached temporary
+  // with same VR is a Core register.
+  if (size == kSingle || size == kDouble) {
+    return kFPReg;
+  }
+
   // X86_64 can handle any size.
   if (cu_->target64) {
     return RegClassBySize(size);
@@ -785,6 +821,7 @@
 
 X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
     : Mir2Lir(cu, mir_graph, arena),
+      in_to_reg_storage_x86_64_mapper_(this), in_to_reg_storage_x86_mapper_(this),
       base_of_code_(nullptr), store_method_addr_(false), store_method_addr_used_(false),
       method_address_insns_(arena->Adapter()),
       class_type_address_insns_(arena->Adapter()),
@@ -795,84 +832,12 @@
   class_type_address_insns_.reserve(100);
   call_method_insns_.reserve(100);
   store_method_addr_used_ = false;
-  if (kIsDebugBuild) {
     for (int i = 0; i < kX86Last; i++) {
-      if (X86Mir2Lir::EncodingMap[i].opcode != i) {
-        LOG(FATAL) << "Encoding order for " << X86Mir2Lir::EncodingMap[i].name
-                   << " is wrong: expecting " << i << ", seeing "
-                   << static_cast<int>(X86Mir2Lir::EncodingMap[i].opcode);
-      }
-    }
+      DCHECK_EQ(X86Mir2Lir::EncodingMap[i].opcode, i)
+          << "Encoding order for " << X86Mir2Lir::EncodingMap[i].name
+          << " is wrong: expecting " << i << ", seeing "
+          << static_cast<int>(X86Mir2Lir::EncodingMap[i].opcode);
   }
-  if (cu_->target64) {
-    rs_rX86_SP = rs_rX86_SP_64;
-
-    rs_rX86_ARG0 = rs_rDI;
-    rs_rX86_ARG1 = rs_rSI;
-    rs_rX86_ARG2 = rs_rDX;
-    rs_rX86_ARG3 = rs_rCX;
-    rs_rX86_ARG4 = rs_r8;
-    rs_rX86_ARG5 = rs_r9;
-    rs_rX86_FARG0 = rs_fr0;
-    rs_rX86_FARG1 = rs_fr1;
-    rs_rX86_FARG2 = rs_fr2;
-    rs_rX86_FARG3 = rs_fr3;
-    rs_rX86_FARG4 = rs_fr4;
-    rs_rX86_FARG5 = rs_fr5;
-    rs_rX86_FARG6 = rs_fr6;
-    rs_rX86_FARG7 = rs_fr7;
-    rX86_ARG0 = rDI;
-    rX86_ARG1 = rSI;
-    rX86_ARG2 = rDX;
-    rX86_ARG3 = rCX;
-    rX86_ARG4 = r8;
-    rX86_ARG5 = r9;
-    rX86_FARG0 = fr0;
-    rX86_FARG1 = fr1;
-    rX86_FARG2 = fr2;
-    rX86_FARG3 = fr3;
-    rX86_FARG4 = fr4;
-    rX86_FARG5 = fr5;
-    rX86_FARG6 = fr6;
-    rX86_FARG7 = fr7;
-    rs_rX86_INVOKE_TGT = rs_rDI;
-  } else {
-    rs_rX86_SP = rs_rX86_SP_32;
-
-    rs_rX86_ARG0 = rs_rAX;
-    rs_rX86_ARG1 = rs_rCX;
-    rs_rX86_ARG2 = rs_rDX;
-    rs_rX86_ARG3 = rs_rBX;
-    rs_rX86_ARG4 = RegStorage::InvalidReg();
-    rs_rX86_ARG5 = RegStorage::InvalidReg();
-    rs_rX86_FARG0 = rs_rAX;
-    rs_rX86_FARG1 = rs_rCX;
-    rs_rX86_FARG2 = rs_rDX;
-    rs_rX86_FARG3 = rs_rBX;
-    rs_rX86_FARG4 = RegStorage::InvalidReg();
-    rs_rX86_FARG5 = RegStorage::InvalidReg();
-    rs_rX86_FARG6 = RegStorage::InvalidReg();
-    rs_rX86_FARG7 = RegStorage::InvalidReg();
-    rX86_ARG0 = rAX;
-    rX86_ARG1 = rCX;
-    rX86_ARG2 = rDX;
-    rX86_ARG3 = rBX;
-    rX86_FARG0 = rAX;
-    rX86_FARG1 = rCX;
-    rX86_FARG2 = rDX;
-    rX86_FARG3 = rBX;
-    rs_rX86_INVOKE_TGT = rs_rAX;
-    // TODO(64): Initialize with invalid reg
-//    rX86_ARG4 = RegStorage::InvalidReg();
-//    rX86_ARG5 = RegStorage::InvalidReg();
-  }
-  rs_rX86_RET0 = rs_rAX;
-  rs_rX86_RET1 = rs_rDX;
-  rs_rX86_COUNT = rs_rCX;
-  rX86_RET0 = rAX;
-  rX86_RET1 = rDX;
-  rX86_INVOKE_TGT = rAX;
-  rX86_COUNT = rCX;
 }
 
 Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
@@ -882,8 +847,9 @@
 
 // Not used in x86(-64)
 RegStorage X86Mir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
+  UNUSED(trampoline);
   LOG(FATAL) << "Unexpected use of LoadHelper in x86";
-  return RegStorage::InvalidReg();
+  UNREACHABLE();
 }
 
 LIR* X86Mir2Lir::CheckSuspendUsingLoad() {
@@ -921,7 +887,7 @@
       (rl_dest.location == kLocCompilerTemp)) {
     int32_t val_lo = Low32Bits(value);
     int32_t val_hi = High32Bits(value);
-    int r_base = rs_rX86_SP.GetReg();
+    int r_base = rs_rX86_SP_32.GetReg();
     int displacement = SRegOffset(rl_dest.s_reg_low);
 
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -1054,7 +1020,8 @@
       call_insn = CallWithLinkerFixup(method_info.GetTargetMethod(), method_info.GetSharpType());
     } else {
       call_insn = OpMem(kOpBlx, TargetReg(kArg0, kRef),
-                        mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
+                        mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+                            cu_->target64 ? 8 : 4).Int32Value());
     }
   } else {
     call_insn = GenInvokeNoInlineCall(this, method_info.GetSharpType());
@@ -1373,7 +1340,7 @@
         // Load the start index from stack, remembering that we pushed EDI.
         int displacement = SRegOffset(rl_start.s_reg_low) + sizeof(uint32_t);
         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        Load32Disp(rs_rX86_SP, displacement, rs_rDI);
+        Load32Disp(rs_rX86_SP_32, displacement, rs_rDI);
         // Dalvik register annotation in LoadBaseIndexedDisp() used wrong offset. Fix it.
         DCHECK(!DECODE_ALIAS_INFO_WIDE(last_lir_insn_->flags.alias_info));
         int reg_id = DECODE_ALIAS_INFO_REG(last_lir_insn_->flags.alias_info) - 1;
@@ -1548,46 +1515,46 @@
       ReturnVectorRegisters(mir);
       break;
     case kMirOpConstVector:
-      GenConst128(bb, mir);
+      GenConst128(mir);
       break;
     case kMirOpMoveVector:
-      GenMoveVector(bb, mir);
+      GenMoveVector(mir);
       break;
     case kMirOpPackedMultiply:
-      GenMultiplyVector(bb, mir);
+      GenMultiplyVector(mir);
       break;
     case kMirOpPackedAddition:
-      GenAddVector(bb, mir);
+      GenAddVector(mir);
       break;
     case kMirOpPackedSubtract:
-      GenSubtractVector(bb, mir);
+      GenSubtractVector(mir);
       break;
     case kMirOpPackedShiftLeft:
-      GenShiftLeftVector(bb, mir);
+      GenShiftLeftVector(mir);
       break;
     case kMirOpPackedSignedShiftRight:
-      GenSignedShiftRightVector(bb, mir);
+      GenSignedShiftRightVector(mir);
       break;
     case kMirOpPackedUnsignedShiftRight:
-      GenUnsignedShiftRightVector(bb, mir);
+      GenUnsignedShiftRightVector(mir);
       break;
     case kMirOpPackedAnd:
-      GenAndVector(bb, mir);
+      GenAndVector(mir);
       break;
     case kMirOpPackedOr:
-      GenOrVector(bb, mir);
+      GenOrVector(mir);
       break;
     case kMirOpPackedXor:
-      GenXorVector(bb, mir);
+      GenXorVector(mir);
       break;
     case kMirOpPackedAddReduce:
-      GenAddReduceVector(bb, mir);
+      GenAddReduceVector(mir);
       break;
     case kMirOpPackedReduce:
-      GenReduceVector(bb, mir);
+      GenReduceVector(mir);
       break;
     case kMirOpPackedSet:
-      GenSetVector(bb, mir);
+      GenSetVector(mir);
       break;
     case kMirOpMemBarrier:
       GenMemBarrier(static_cast<MemBarrierKind>(mir->dalvikInsn.vA));
@@ -1638,7 +1605,7 @@
   }
 }
 
-void X86Mir2Lir::GenConst128(BasicBlock* bb, MIR* mir) {
+void X86Mir2Lir::GenConst128(MIR* mir) {
   RegStorage rs_dest = RegStorage::Solo128(mir->dalvikInsn.vA);
   Clobber(rs_dest);
 
@@ -1655,9 +1622,6 @@
 }
 
 void X86Mir2Lir::AppendOpcodeWithConst(X86OpCode opcode, int reg, MIR* mir) {
-  // The literal pool needs position independent logic.
-  store_method_addr_used_ = true;
-
   // To deal with correct memory ordering, reverse order of constants.
   int32_t constants[4];
   constants[3] = mir->dalvikInsn.arg[0];
@@ -1671,25 +1635,33 @@
     data_target = AddVectorLiteral(constants);
   }
 
-  // Address the start of the method.
-  RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
-  if (rl_method.wide) {
-    rl_method = LoadValueWide(rl_method, kCoreReg);
-  } else {
-    rl_method = LoadValue(rl_method, kCoreReg);
-  }
-
   // Load the proper value from the literal area.
   // We don't know the proper offset for the value, so pick one that will force
-  // 4 byte offset.  We will fix this up in the assembler later to have the right
-  // value.
+  // 4 byte offset.  We will fix this up in the assembler later to have the
+  // right value.
+  LIR* load;
   ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
-  LIR *load = NewLIR3(opcode, reg, rl_method.reg.GetReg(), 256 /* bogus */);
+  if (cu_->target64) {
+    load = NewLIR3(opcode, reg, kRIPReg, 256 /* bogus */);
+  } else {
+    // Address the start of the method.
+    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+    if (rl_method.wide) {
+      rl_method = LoadValueWide(rl_method, kCoreReg);
+    } else {
+      rl_method = LoadValue(rl_method, kCoreReg);
+    }
+
+    load = NewLIR3(opcode, reg, rl_method.reg.GetReg(), 256 /* bogus */);
+
+    // The literal pool needs position independent logic.
+    store_method_addr_used_ = true;
+  }
   load->flags.fixup = kFixupLoad;
   load->target = data_target;
 }
 
-void X86Mir2Lir::GenMoveVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenMoveVector(MIR* mir) {
   // We only support 128 bit registers.
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   RegStorage rs_dest = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1805,7 +1777,7 @@
   NewLIR2(kX86PaddqRR, rs_dest_src1.GetReg(), rs_tmp_vector_1.GetReg());
 }
 
-void X86Mir2Lir::GenMultiplyVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenMultiplyVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1839,7 +1811,7 @@
   NewLIR2(opcode, rs_dest_src1.GetReg(), rs_src2.GetReg());
 }
 
-void X86Mir2Lir::GenAddVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenAddVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1874,7 +1846,7 @@
   NewLIR2(opcode, rs_dest_src1.GetReg(), rs_src2.GetReg());
 }
 
-void X86Mir2Lir::GenSubtractVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenSubtractVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1909,7 +1881,7 @@
   NewLIR2(opcode, rs_dest_src1.GetReg(), rs_src2.GetReg());
 }
 
-void X86Mir2Lir::GenShiftByteVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenShiftByteVector(MIR* mir) {
   // Destination does not need clobbered because it has already been as part
   // of the general packed shift handler (caller of this method).
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1953,7 +1925,7 @@
   AndMaskVectorRegister(rs_dest_src1, int_mask, int_mask, int_mask, int_mask);
 }
 
-void X86Mir2Lir::GenShiftLeftVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenShiftLeftVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1973,7 +1945,7 @@
       break;
     case kSignedByte:
     case kUnsignedByte:
-      GenShiftByteVector(bb, mir);
+      GenShiftByteVector(mir);
       return;
     default:
       LOG(FATAL) << "Unsupported vector shift left " << opsize;
@@ -1982,7 +1954,7 @@
   NewLIR2(opcode, rs_dest_src1.GetReg(), imm);
 }
 
-void X86Mir2Lir::GenSignedShiftRightVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenSignedShiftRightVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -1999,18 +1971,18 @@
       break;
     case kSignedByte:
     case kUnsignedByte:
-      GenShiftByteVector(bb, mir);
+      GenShiftByteVector(mir);
       return;
     case k64:
       // TODO Implement emulated shift algorithm.
     default:
       LOG(FATAL) << "Unsupported vector signed shift right " << opsize;
-      break;
+      UNREACHABLE();
   }
   NewLIR2(opcode, rs_dest_src1.GetReg(), imm);
 }
 
-void X86Mir2Lir::GenUnsignedShiftRightVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenUnsignedShiftRightVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -2030,7 +2002,7 @@
       break;
     case kSignedByte:
     case kUnsignedByte:
-      GenShiftByteVector(bb, mir);
+      GenShiftByteVector(mir);
       return;
     default:
       LOG(FATAL) << "Unsupported vector unsigned shift right " << opsize;
@@ -2039,7 +2011,7 @@
   NewLIR2(opcode, rs_dest_src1.GetReg(), imm);
 }
 
-void X86Mir2Lir::GenAndVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenAndVector(MIR* mir) {
   // We only support 128 bit registers.
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -2048,7 +2020,7 @@
   NewLIR2(kX86PandRR, rs_dest_src1.GetReg(), rs_src2.GetReg());
 }
 
-void X86Mir2Lir::GenOrVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenOrVector(MIR* mir) {
   // We only support 128 bit registers.
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -2057,7 +2029,7 @@
   NewLIR2(kX86PorRR, rs_dest_src1.GetReg(), rs_src2.GetReg());
 }
 
-void X86Mir2Lir::GenXorVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenXorVector(MIR* mir) {
   // We only support 128 bit registers.
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   RegStorage rs_dest_src1 = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -2084,7 +2056,7 @@
   AppendOpcodeWithConst(opcode, rs_src1.GetReg(), const_mirp);
 }
 
-void X86Mir2Lir::GenAddReduceVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenAddReduceVector(MIR* mir) {
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage vector_src = RegStorage::Solo128(mir->dalvikInsn.vB);
   bool is_wide = opsize == k64 || opsize == kDouble;
@@ -2166,7 +2138,7 @@
       NewLIR2(kX86MovdrxRR, temp_loc.reg.GetHighReg(), vector_src.GetReg());
     }
 
-    GenArithOpLong(Instruction::ADD_LONG_2ADDR, rl_dest, temp_loc, temp_loc);
+    GenArithOpLong(Instruction::ADD_LONG_2ADDR, rl_dest, temp_loc, temp_loc, mir->optimization_flags);
   } else if (opsize == kSignedByte || opsize == kUnsignedByte) {
     RegStorage rs_tmp = Get128BitRegister(AllocTempDouble());
     NewLIR2(kX86PxorRR, rs_tmp.GetReg(), rs_tmp.GetReg());
@@ -2219,7 +2191,7 @@
     // except the rhs is not a VR but a physical register allocated above.
     // No load of source VR is done because it assumes that rl_result will
     // share physical register / memory location.
-    rl_result = UpdateLocTyped(rl_dest, kCoreReg);
+    rl_result = UpdateLocTyped(rl_dest);
     if (rl_result.location == kLocPhysReg) {
       // Ensure res is in a core reg.
       rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -2232,7 +2204,7 @@
   }
 }
 
-void X86Mir2Lir::GenReduceVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenReduceVector(MIR* mir) {
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegLocation rl_dest = mir_graph_->GetDest(mir);
   RegStorage vector_src = RegStorage::Solo128(mir->dalvikInsn.vB);
@@ -2244,18 +2216,36 @@
     // Handle float case.
     // TODO Add support for fast math (not value safe) and do horizontal add in that case.
 
+    int extract_index = mir->dalvikInsn.arg[0];
+
     rl_result = EvalLoc(rl_dest, kFPReg, true);
     NewLIR2(kX86PxorRR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
-    NewLIR2(kX86AddssRR, rl_result.reg.GetReg(), vector_src.GetReg());
 
-    // Since FP must keep order of operation for value safety, we shift to low
-    // 32-bits and add to result.
-    for (int i = 0; i < 3; i++) {
-      NewLIR3(kX86ShufpsRRI, vector_src.GetReg(), vector_src.GetReg(), 0x39);
+    if (LIKELY(extract_index != 0)) {
+      // We know the index of element which we want to extract. We want to extract it and
+      // keep values in vector register correct for future use. So the way we act is:
+      // 1. Generate shuffle mask that allows to swap zeroth and required elements;
+      // 2. Shuffle vector register with this mask;
+      // 3. Extract zeroth element where required value lies;
+      // 4. Shuffle with same mask again to restore original values in vector register.
+      // The mask is generated from equivalence mask 0b11100100 swapping 0th and extracted
+      // element indices.
+      int shuffle[4] = {0b00, 0b01, 0b10, 0b11};
+      shuffle[0] = extract_index;
+      shuffle[extract_index] = 0;
+      int mask = 0;
+      for (int i = 0; i < 4; i++) {
+        mask |= (shuffle[i] << (2 * i));
+      }
+      NewLIR3(kX86ShufpsRRI, vector_src.GetReg(), vector_src.GetReg(), mask);
+      NewLIR2(kX86AddssRR, rl_result.reg.GetReg(), vector_src.GetReg());
+      NewLIR3(kX86ShufpsRRI, vector_src.GetReg(), vector_src.GetReg(), mask);
+    } else {
+      // We need to extract zeroth element and don't need any complex stuff to do it.
       NewLIR2(kX86AddssRR, rl_result.reg.GetReg(), vector_src.GetReg());
     }
 
-    StoreValue(rl_dest, rl_result);
+    StoreFinalValue(rl_dest, rl_result);
   } else if (opsize == kDouble) {
     // TODO Handle double case.
     LOG(FATAL) << "Unsupported add reduce for double.";
@@ -2286,7 +2276,7 @@
   } else {
     int extract_index = mir->dalvikInsn.arg[0];
     int extr_opcode = 0;
-    rl_result = UpdateLocTyped(rl_dest, kCoreReg);
+    rl_result = UpdateLocTyped(rl_dest);
 
     // Handle the rest of integral types now.
     switch (opsize) {
@@ -2302,7 +2292,7 @@
         break;
       default:
         LOG(FATAL) << "Unsupported vector reduce " << opsize;
-        return;
+        UNREACHABLE();
     }
 
     if (rl_result.location == kLocPhysReg) {
@@ -2310,7 +2300,8 @@
       StoreFinalValue(rl_dest, rl_result);
     } else {
       int displacement = SRegOffset(rl_result.s_reg_low);
-      LIR *l = NewLIR3(extr_opcode, rs_rX86_SP.GetReg(), displacement, vector_src.GetReg());
+      LIR *l = NewLIR4(extr_opcode, rs_rX86_SP_32.GetReg(), displacement, vector_src.GetReg(),
+                       extract_index);
       AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, is_wide /* is_64bit */);
       AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, is_wide /* is_64bit */);
     }
@@ -2331,7 +2322,7 @@
   }
 }
 
-void X86Mir2Lir::GenSetVector(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenSetVector(MIR* mir) {
   DCHECK_EQ(mir->dalvikInsn.vC & 0xFFFF, 128U);
   OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
   RegStorage rs_dest = RegStorage::Solo128(mir->dalvikInsn.vA);
@@ -2406,11 +2397,13 @@
   }
 }
 
-void X86Mir2Lir::GenPackedArrayGet(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenPackedArrayGet(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb, mir);
   UNIMPLEMENTED(FATAL) << "Extended opcode kMirOpPackedArrayGet not supported.";
 }
 
-void X86Mir2Lir::GenPackedArrayPut(BasicBlock *bb, MIR *mir) {
+void X86Mir2Lir::GenPackedArrayPut(BasicBlock* bb, MIR* mir) {
+  UNUSED(bb, mir);
   UNIMPLEMENTED(FATAL) << "Extended opcode kMirOpPackedArrayPut not supported.";
 }
 
@@ -2440,455 +2433,45 @@
 }
 
 // ------------ ABI support: mapping of args to physical registers -------------
-RegStorage X86Mir2Lir::InToRegStorageX86_64Mapper::GetNextReg(bool is_double_or_float, bool is_wide,
-                                                              bool is_ref) {
+RegStorage X86Mir2Lir::InToRegStorageX86_64Mapper::GetNextReg(ShortyArg arg) {
   const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3, kArg4, kArg5};
-  const int coreArgMappingToPhysicalRegSize = sizeof(coreArgMappingToPhysicalReg) /
-      sizeof(SpecialTargetRegister);
+  const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
   const SpecialTargetRegister fpArgMappingToPhysicalReg[] = {kFArg0, kFArg1, kFArg2, kFArg3,
                                                              kFArg4, kFArg5, kFArg6, kFArg7};
-  const int fpArgMappingToPhysicalRegSize = sizeof(fpArgMappingToPhysicalReg) /
-      sizeof(SpecialTargetRegister);
+  const size_t fpArgMappingToPhysicalRegSize = arraysize(fpArgMappingToPhysicalReg);
 
-  if (is_double_or_float) {
+  if (arg.IsFP()) {
     if (cur_fp_reg_ < fpArgMappingToPhysicalRegSize) {
-      return ml_->TargetReg(fpArgMappingToPhysicalReg[cur_fp_reg_++], is_wide ? kWide : kNotWide);
+      return m2l_->TargetReg(fpArgMappingToPhysicalReg[cur_fp_reg_++],
+                             arg.IsWide() ? kWide : kNotWide);
     }
   } else {
     if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
-      return ml_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
-                            is_ref ? kRef : (is_wide ? kWide : kNotWide));
+      return m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
+                             arg.IsRef() ? kRef : (arg.IsWide() ? kWide : kNotWide));
     }
   }
   return RegStorage::InvalidReg();
 }
 
-RegStorage X86Mir2Lir::InToRegStorageMapping::Get(int in_position) {
-  DCHECK(IsInitialized());
-  auto res = mapping_.find(in_position);
-  return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
-}
+RegStorage X86Mir2Lir::InToRegStorageX86Mapper::GetNextReg(ShortyArg arg) {
+  const SpecialTargetRegister coreArgMappingToPhysicalReg[] = {kArg1, kArg2, kArg3};
+  const size_t coreArgMappingToPhysicalRegSize = arraysize(coreArgMappingToPhysicalReg);
 
-void X86Mir2Lir::InToRegStorageMapping::Initialize(RegLocation* arg_locs, int count,
-                                                   InToRegStorageMapper* mapper) {
-  DCHECK(mapper != nullptr);
-  max_mapped_in_ = -1;
-  is_there_stack_mapped_ = false;
-  for (int in_position = 0; in_position < count; in_position++) {
-     RegStorage reg = mapper->GetNextReg(arg_locs[in_position].fp,
-             arg_locs[in_position].wide, arg_locs[in_position].ref);
-     if (reg.Valid()) {
-       mapping_[in_position] = reg;
-       max_mapped_in_ = std::max(max_mapped_in_, in_position);
-       if (arg_locs[in_position].wide) {
-         // We covered 2 args, so skip the next one
-         in_position++;
-       }
-     } else {
-       is_there_stack_mapped_ = true;
-     }
+  RegStorage result = RegStorage::InvalidReg();
+  if (cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+    result = m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++],
+                          arg.IsRef() ? kRef : kNotWide);
+    if (arg.IsWide() && cur_core_reg_ < coreArgMappingToPhysicalRegSize) {
+      result = RegStorage::MakeRegPair(
+          result, m2l_->TargetReg(coreArgMappingToPhysicalReg[cur_core_reg_++], kNotWide));
+    }
   }
-  initialized_ = true;
-}
-
-RegStorage X86Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
-  if (!cu_->target64) {
-    return GetCoreArgMappingToPhysicalReg(arg_num);
-  }
-
-  if (!in_to_reg_storage_mapping_.IsInitialized()) {
-    int start_vreg = cu_->mir_graph->GetFirstInVR();
-    RegLocation* arg_locs = &mir_graph_->reg_location_[start_vreg];
-
-    InToRegStorageX86_64Mapper mapper(this);
-    in_to_reg_storage_mapping_.Initialize(arg_locs, mir_graph_->GetNumOfInVRs(), &mapper);
-  }
-  return in_to_reg_storage_mapping_.Get(arg_num);
-}
-
-RegStorage X86Mir2Lir::GetCoreArgMappingToPhysicalReg(int core_arg_num) {
-  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
-  // Not used for 64-bit, TODO: Move X86_32 to the same framework
-  switch (core_arg_num) {
-    case 0:
-      return rs_rX86_ARG1;
-    case 1:
-      return rs_rX86_ARG2;
-    case 2:
-      return rs_rX86_ARG3;
-    default:
-      return RegStorage::InvalidReg();
-  }
+  return result;
 }
 
 // ---------End of ABI support: mapping of args to physical registers -------------
 
-/*
- * If there are any ins passed in registers that have not been promoted
- * to a callee-save register, flush them to the frame.  Perform initial
- * assignment of promoted arguments.
- *
- * ArgLocs is an array of location records describing the incoming arguments
- * with one location record per word of argument.
- */
-void X86Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
-  if (!cu_->target64) return Mir2Lir::FlushIns(ArgLocs, rl_method);
-  /*
-   * Dummy up a RegLocation for the incoming Method*
-   * It will attempt to keep kArg0 live (or copy it to home location
-   * if promoted).
-   */
-
-  RegLocation rl_src = rl_method;
-  rl_src.location = kLocPhysReg;
-  rl_src.reg = TargetReg(kArg0, kRef);
-  rl_src.home = false;
-  MarkLive(rl_src);
-  StoreValue(rl_method, rl_src);
-  // If Method* has been promoted, explicitly flush
-  if (rl_method.location == kLocPhysReg) {
-    StoreRefDisp(rs_rX86_SP, 0, As32BitReg(TargetReg(kArg0, kRef)), kNotVolatile);
-  }
-
-  if (mir_graph_->GetNumOfInVRs() == 0) {
-    return;
-  }
-
-  int start_vreg = cu_->mir_graph->GetFirstInVR();
-  /*
-   * Copy incoming arguments to their proper home locations.
-   * NOTE: an older version of dx had an issue in which
-   * it would reuse static method argument registers.
-   * This could result in the same Dalvik virtual register
-   * being promoted to both core and fp regs. To account for this,
-   * we only copy to the corresponding promoted physical register
-   * if it matches the type of the SSA name for the incoming
-   * argument.  It is also possible that long and double arguments
-   * end up half-promoted.  In those cases, we must flush the promoted
-   * half to memory as well.
-   */
-  ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-  for (uint32_t i = 0; i < mir_graph_->GetNumOfInVRs(); i++) {
-    // get reg corresponding to input
-    RegStorage reg = GetArgMappingToPhysicalReg(i);
-
-    RegLocation* t_loc = &ArgLocs[i];
-    if (reg.Valid()) {
-      // If arriving in register.
-
-      // We have already updated the arg location with promoted info
-      // so we can be based on it.
-      if (t_loc->location == kLocPhysReg) {
-        // Just copy it.
-        OpRegCopy(t_loc->reg, reg);
-      } else {
-        // Needs flush.
-        if (t_loc->ref) {
-          StoreRefDisp(rs_rX86_SP, SRegOffset(start_vreg + i), reg, kNotVolatile);
-        } else {
-          StoreBaseDisp(rs_rX86_SP, SRegOffset(start_vreg + i), reg, t_loc->wide ? k64 : k32,
-                        kNotVolatile);
-        }
-      }
-    } else {
-      // If arriving in frame & promoted.
-      if (t_loc->location == kLocPhysReg) {
-        if (t_loc->ref) {
-          LoadRefDisp(rs_rX86_SP, SRegOffset(start_vreg + i), t_loc->reg, kNotVolatile);
-        } else {
-          LoadBaseDisp(rs_rX86_SP, SRegOffset(start_vreg + i), t_loc->reg,
-                       t_loc->wide ? k64 : k32, kNotVolatile);
-        }
-      }
-    }
-    if (t_loc->wide) {
-      // Increment i to skip the next one.
-      i++;
-    }
-  }
-}
-
-/*
- * Load up to 5 arguments, the first three of which will be in
- * kArg1 .. kArg3.  On entry kArg0 contains the current method pointer,
- * and as part of the load sequence, it must be replaced with
- * the target method pointer.  Note, this may also be called
- * for "range" variants if the number of arguments is 5 or fewer.
- */
-int X86Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
-                                  int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                  const MethodReference& target_method,
-                                  uint32_t vtable_idx, uintptr_t direct_code,
-                                  uintptr_t direct_method, InvokeType type, bool skip_this) {
-  if (!cu_->target64) {
-    return Mir2Lir::GenDalvikArgsNoRange(info,
-                                  call_state, pcrLabel, next_call_insn,
-                                  target_method,
-                                  vtable_idx, direct_code,
-                                  direct_method, type, skip_this);
-  }
-  return GenDalvikArgsRange(info,
-                       call_state, pcrLabel, next_call_insn,
-                       target_method,
-                       vtable_idx, direct_code,
-                       direct_method, type, skip_this);
-}
-
-/*
- * May have 0+ arguments (also used for jumbo).  Note that
- * source virtual registers may be in physical registers, so may
- * need to be flushed to home location before copying.  This
- * applies to arg3 and above (see below).
- *
- * Two general strategies:
- *    If < 20 arguments
- *       Pass args 3-18 using vldm/vstm block copy
- *       Pass arg0, arg1 & arg2 in kArg1-kArg3
- *    If 20+ arguments
- *       Pass args arg19+ using memcpy block copy
- *       Pass arg0, arg1 & arg2 in kArg1-kArg3
- *
- */
-int X86Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
-                                LIR** pcrLabel, NextCallInsn next_call_insn,
-                                const MethodReference& target_method,
-                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
-                                InvokeType type, bool skip_this) {
-  if (!cu_->target64) {
-    return Mir2Lir::GenDalvikArgsRange(info, call_state,
-                                pcrLabel, next_call_insn,
-                                target_method,
-                                vtable_idx, direct_code, direct_method,
-                                type, skip_this);
-  }
-
-  /* If no arguments, just return */
-  if (info->num_arg_words == 0)
-    return call_state;
-
-  const int start_index = skip_this ? 1 : 0;
-
-  InToRegStorageX86_64Mapper mapper(this);
-  InToRegStorageMapping in_to_reg_storage_mapping;
-  in_to_reg_storage_mapping.Initialize(info->args, info->num_arg_words, &mapper);
-  const int last_mapped_in = in_to_reg_storage_mapping.GetMaxMappedIn();
-  const int size_of_the_last_mapped = last_mapped_in == -1 ? 1 :
-          info->args[last_mapped_in].wide ? 2 : 1;
-  int regs_left_to_pass_via_stack = info->num_arg_words - (last_mapped_in + size_of_the_last_mapped);
-
-  // Fisrt of all, check whether it make sense to use bulk copying
-  // Optimization is aplicable only for range case
-  // TODO: make a constant instead of 2
-  if (info->is_range && regs_left_to_pass_via_stack >= 2) {
-    // Scan the rest of the args - if in phys_reg flush to memory
-    for (int next_arg = last_mapped_in + size_of_the_last_mapped; next_arg < info->num_arg_words;) {
-      RegLocation loc = info->args[next_arg];
-      if (loc.wide) {
-        loc = UpdateLocWide(loc);
-        if (loc.location == kLocPhysReg) {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          StoreBaseDisp(rs_rX86_SP, SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
-        }
-        next_arg += 2;
-      } else {
-        loc = UpdateLoc(loc);
-        if (loc.location == kLocPhysReg) {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          StoreBaseDisp(rs_rX86_SP, SRegOffset(loc.s_reg_low), loc.reg, k32, kNotVolatile);
-        }
-        next_arg++;
-      }
-    }
-
-    // The rest can be copied together
-    int start_offset = SRegOffset(info->args[last_mapped_in + size_of_the_last_mapped].s_reg_low);
-    int outs_offset = StackVisitor::GetOutVROffset(last_mapped_in + size_of_the_last_mapped,
-                                                   cu_->instruction_set);
-
-    int current_src_offset = start_offset;
-    int current_dest_offset = outs_offset;
-
-    // Only davik regs are accessed in this loop; no next_call_insn() calls.
-    ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    while (regs_left_to_pass_via_stack > 0) {
-      // This is based on the knowledge that the stack itself is 16-byte aligned.
-      bool src_is_16b_aligned = (current_src_offset & 0xF) == 0;
-      bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0;
-      size_t bytes_to_move;
-
-      /*
-       * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a
-       * a 128-bit move because we won't get the chance to try to aligned. If there are more than
-       * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned.
-       * We do this because we could potentially do a smaller move to align.
-       */
-      if (regs_left_to_pass_via_stack == 4 ||
-          (regs_left_to_pass_via_stack > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) {
-        // Moving 128-bits via xmm register.
-        bytes_to_move = sizeof(uint32_t) * 4;
-
-        // Allocate a free xmm temp. Since we are working through the calling sequence,
-        // we expect to have an xmm temporary available.  AllocTempDouble will abort if
-        // there are no free registers.
-        RegStorage temp = AllocTempDouble();
-
-        LIR* ld1 = nullptr;
-        LIR* ld2 = nullptr;
-        LIR* st1 = nullptr;
-        LIR* st2 = nullptr;
-
-        /*
-         * The logic is similar for both loads and stores. If we have 16-byte alignment,
-         * do an aligned move. If we have 8-byte alignment, then do the move in two
-         * parts. This approach prevents possible cache line splits. Finally, fall back
-         * to doing an unaligned move. In most cases we likely won't split the cache
-         * line but we cannot prove it and thus take a conservative approach.
-         */
-        bool src_is_8b_aligned = (current_src_offset & 0x7) == 0;
-        bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0;
-
-        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        if (src_is_16b_aligned) {
-          ld1 = OpMovRegMem(temp, rs_rX86_SP, current_src_offset, kMovA128FP);
-        } else if (src_is_8b_aligned) {
-          ld1 = OpMovRegMem(temp, rs_rX86_SP, current_src_offset, kMovLo128FP);
-          ld2 = OpMovRegMem(temp, rs_rX86_SP, current_src_offset + (bytes_to_move >> 1),
-                            kMovHi128FP);
-        } else {
-          ld1 = OpMovRegMem(temp, rs_rX86_SP, current_src_offset, kMovU128FP);
-        }
-
-        if (dest_is_16b_aligned) {
-          st1 = OpMovMemReg(rs_rX86_SP, current_dest_offset, temp, kMovA128FP);
-        } else if (dest_is_8b_aligned) {
-          st1 = OpMovMemReg(rs_rX86_SP, current_dest_offset, temp, kMovLo128FP);
-          st2 = OpMovMemReg(rs_rX86_SP, current_dest_offset + (bytes_to_move >> 1),
-                            temp, kMovHi128FP);
-        } else {
-          st1 = OpMovMemReg(rs_rX86_SP, current_dest_offset, temp, kMovU128FP);
-        }
-
-        // TODO If we could keep track of aliasing information for memory accesses that are wider
-        // than 64-bit, we wouldn't need to set up a barrier.
-        if (ld1 != nullptr) {
-          if (ld2 != nullptr) {
-            // For 64-bit load we can actually set up the aliasing information.
-            AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true);
-            AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true, true);
-          } else {
-            // Set barrier for 128-bit load.
-            ld1->u.m.def_mask = &kEncodeAll;
-          }
-        }
-        if (st1 != nullptr) {
-          if (st2 != nullptr) {
-            // For 64-bit store we can actually set up the aliasing information.
-            AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true);
-            AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false, true);
-          } else {
-            // Set barrier for 128-bit store.
-            st1->u.m.def_mask = &kEncodeAll;
-          }
-        }
-
-        // Free the temporary used for the data movement.
-        FreeTemp(temp);
-      } else {
-        // Moving 32-bits via general purpose register.
-        bytes_to_move = sizeof(uint32_t);
-
-        // Instead of allocating a new temp, simply reuse one of the registers being used
-        // for argument passing.
-        RegStorage temp = TargetReg(kArg3, kNotWide);
-
-        // Now load the argument VR and store to the outs.
-        Load32Disp(rs_rX86_SP, current_src_offset, temp);
-        Store32Disp(rs_rX86_SP, current_dest_offset, temp);
-      }
-
-      current_src_offset += bytes_to_move;
-      current_dest_offset += bytes_to_move;
-      regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
-    }
-    DCHECK_EQ(regs_left_to_pass_via_stack, 0);
-  }
-
-  // Now handle rest not registers if they are
-  if (in_to_reg_storage_mapping.IsThereStackMapped()) {
-    RegStorage regSingle = TargetReg(kArg2, kNotWide);
-    RegStorage regWide = TargetReg(kArg3, kWide);
-    for (int i = start_index;
-         i < last_mapped_in + size_of_the_last_mapped + regs_left_to_pass_via_stack; i++) {
-      RegLocation rl_arg = info->args[i];
-      rl_arg = UpdateRawLoc(rl_arg);
-      RegStorage reg = in_to_reg_storage_mapping.Get(i);
-      if (!reg.Valid()) {
-        int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
-
-        {
-          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          if (rl_arg.wide) {
-            if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(rs_rX86_SP, out_offset, rl_arg.reg, k64, kNotVolatile);
-            } else {
-              LoadValueDirectWideFixed(rl_arg, regWide);
-              StoreBaseDisp(rs_rX86_SP, out_offset, regWide, k64, kNotVolatile);
-            }
-          } else {
-            if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(rs_rX86_SP, out_offset, rl_arg.reg, k32, kNotVolatile);
-            } else {
-              LoadValueDirectFixed(rl_arg, regSingle);
-              StoreBaseDisp(rs_rX86_SP, out_offset, regSingle, k32, kNotVolatile);
-            }
-          }
-        }
-        call_state = next_call_insn(cu_, info, call_state, target_method,
-                                    vtable_idx, direct_code, direct_method, type);
-      }
-      if (rl_arg.wide) {
-        i++;
-      }
-    }
-  }
-
-  // Finish with mapped registers
-  for (int i = start_index; i <= last_mapped_in; i++) {
-    RegLocation rl_arg = info->args[i];
-    rl_arg = UpdateRawLoc(rl_arg);
-    RegStorage reg = in_to_reg_storage_mapping.Get(i);
-    if (reg.Valid()) {
-      if (rl_arg.wide) {
-        LoadValueDirectWideFixed(rl_arg, reg);
-      } else {
-        LoadValueDirectFixed(rl_arg, reg);
-      }
-      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                               direct_code, direct_method, type);
-    }
-    if (rl_arg.wide) {
-      i++;
-    }
-  }
-
-  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
-                           direct_code, direct_method, type);
-  if (pcrLabel) {
-    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
-      *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
-    } else {
-      *pcrLabel = nullptr;
-      // In lieu of generating a check for kArg1 being null, we need to
-      // perform a load when doing implicit checks.
-      RegStorage tmp = AllocTemp();
-      Load32Disp(TargetReg(kArg1, kRef), 0, tmp);
-      MarkPossibleNullPointerException(info->opt_flags);
-      FreeTemp(tmp);
-    }
-  }
-  return call_state;
-}
-
 bool X86Mir2Lir::GenInlinedCharAt(CallInfo* info) {
   // Location of reference to data array
   int value_offset = mirror::String::ValueOffset().Int32Value();
@@ -3016,4 +2599,122 @@
   }
 }
 
+int X86Mir2Lir::GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) {
+  if (count < 4) {
+    // It does not make sense to use this utility if we have no chance to use
+    // 128-bit move.
+    return count;
+  }
+  GenDalvikArgsFlushPromoted(info, first);
+
+  // The rest can be copied together
+  int current_src_offset = SRegOffset(info->args[first].s_reg_low);
+  int current_dest_offset = StackVisitor::GetOutVROffset(first, cu_->instruction_set);
+
+  // Only davik regs are accessed in this loop; no next_call_insn() calls.
+  ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+  while (count > 0) {
+    // This is based on the knowledge that the stack itself is 16-byte aligned.
+    bool src_is_16b_aligned = (current_src_offset & 0xF) == 0;
+    bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0;
+    size_t bytes_to_move;
+
+    /*
+     * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a
+     * a 128-bit move because we won't get the chance to try to aligned. If there are more than
+     * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned.
+     * We do this because we could potentially do a smaller move to align.
+     */
+    if (count == 4 || (count > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) {
+      // Moving 128-bits via xmm register.
+      bytes_to_move = sizeof(uint32_t) * 4;
+
+      // Allocate a free xmm temp. Since we are working through the calling sequence,
+      // we expect to have an xmm temporary available. AllocTempDouble will abort if
+      // there are no free registers.
+      RegStorage temp = AllocTempDouble();
+
+      LIR* ld1 = nullptr;
+      LIR* ld2 = nullptr;
+      LIR* st1 = nullptr;
+      LIR* st2 = nullptr;
+
+      /*
+       * The logic is similar for both loads and stores. If we have 16-byte alignment,
+       * do an aligned move. If we have 8-byte alignment, then do the move in two
+       * parts. This approach prevents possible cache line splits. Finally, fall back
+       * to doing an unaligned move. In most cases we likely won't split the cache
+       * line but we cannot prove it and thus take a conservative approach.
+       */
+      bool src_is_8b_aligned = (current_src_offset & 0x7) == 0;
+      bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0;
+
+      if (src_is_16b_aligned) {
+        ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovA128FP);
+      } else if (src_is_8b_aligned) {
+        ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovLo128FP);
+        ld2 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset + (bytes_to_move >> 1),
+                          kMovHi128FP);
+      } else {
+        ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovU128FP);
+      }
+
+      if (dest_is_16b_aligned) {
+        st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovA128FP);
+      } else if (dest_is_8b_aligned) {
+        st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovLo128FP);
+        st2 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset + (bytes_to_move >> 1),
+                          temp, kMovHi128FP);
+      } else {
+        st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovU128FP);
+      }
+
+      // TODO If we could keep track of aliasing information for memory accesses that are wider
+      // than 64-bit, we wouldn't need to set up a barrier.
+      if (ld1 != nullptr) {
+        if (ld2 != nullptr) {
+          // For 64-bit load we can actually set up the aliasing information.
+          AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true);
+          AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true,
+                                  true);
+        } else {
+          // Set barrier for 128-bit load.
+          ld1->u.m.def_mask = &kEncodeAll;
+        }
+      }
+      if (st1 != nullptr) {
+        if (st2 != nullptr) {
+          // For 64-bit store we can actually set up the aliasing information.
+          AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true);
+          AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false,
+                                  true);
+        } else {
+          // Set barrier for 128-bit store.
+          st1->u.m.def_mask = &kEncodeAll;
+        }
+      }
+
+      // Free the temporary used for the data movement.
+      FreeTemp(temp);
+    } else {
+      // Moving 32-bits via general purpose register.
+      bytes_to_move = sizeof(uint32_t);
+
+      // Instead of allocating a new temp, simply reuse one of the registers being used
+      // for argument passing.
+      RegStorage temp = TargetReg(kArg3, kNotWide);
+
+      // Now load the argument VR and store to the outs.
+      Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
+      Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
+    }
+
+    current_src_offset += bytes_to_move;
+    current_dest_offset += bytes_to_move;
+    count -= (bytes_to_move >> 2);
+  }
+  DCHECK_EQ(count, 0);
+  return count;
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 6898b50..3b58698 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -54,14 +54,16 @@
 }
 
 bool X86Mir2Lir::InexpensiveConstantInt(int32_t value) {
+  UNUSED(value);
   return true;
 }
 
 bool X86Mir2Lir::InexpensiveConstantFloat(int32_t value) {
-  return false;
+  return value == 0;
 }
 
 bool X86Mir2Lir::InexpensiveConstantLong(int64_t value) {
+  UNUSED(value);
   return true;
 }
 
@@ -228,7 +230,7 @@
         // TODO: there are several instances of this check.  A utility function perhaps?
         // TODO: Similar to Arm's reg < 8 check.  Perhaps add attribute checks to RegStorage?
         // Use shifts instead of a byte operand if the source can't be byte accessed.
-        if (r_src2.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
+        if (r_src2.GetRegNum() >= rs_rX86_SP_32.GetRegNum()) {
           NewLIR2(is64Bit ? kX86Mov64RR : kX86Mov32RR, r_dest_src1.GetReg(), r_src2.GetReg());
           NewLIR2(is64Bit ? kX86Sal64RI : kX86Sal32RI, r_dest_src1.GetReg(), is64Bit ? 56 : 24);
           return NewLIR2(is64Bit ? kX86Sar64RI : kX86Sar32RI, r_dest_src1.GetReg(),
@@ -383,7 +385,7 @@
   }
   LIR *l = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), offset);
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rX86_SP);
+    DCHECK_EQ(r_base, cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32);
     AnnotateDalvikRegAccess(l, offset >> 2, true /* is_load */, false /* is_64bit */);
   }
   return l;
@@ -409,7 +411,7 @@
       LOG(FATAL) << "Bad case in OpMemReg " << op;
       break;
   }
-  LIR *l = NewLIR3(opcode, rs_rX86_SP.GetReg(), displacement, r_value);
+  LIR *l = NewLIR3(opcode, rs_rX86_SP_32.GetReg(), displacement, r_value);
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
     AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, is64Bit /* is_64bit */);
     AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, is64Bit /* is_64bit */);
@@ -435,7 +437,7 @@
       LOG(FATAL) << "Bad case in OpRegMem " << op;
       break;
   }
-  LIR *l = NewLIR3(opcode, r_dest.GetReg(), rs_rX86_SP.GetReg(), displacement);
+  LIR *l = NewLIR3(opcode, r_dest.GetReg(), rs_rX86_SP_32.GetReg(), displacement);
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
     AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, is64Bit /* is_64bit */);
   }
@@ -486,6 +488,7 @@
       case kOpAdc:
       case kOpAnd:
       case kOpXor:
+      case kOpMul:
         break;
       default:
         LOG(FATAL) << "Bad case in OpRegRegReg " << op;
@@ -512,7 +515,7 @@
                      r_src.GetReg() /* index */, value /* scale */, 0 /* disp */);
     } else if (op == kOpAdd) {  // lea add special case
       return NewLIR5(r_dest.Is64Bit() ? kX86Lea64RA : kX86Lea32RA, r_dest.GetReg(),
-                     r_src.GetReg() /* base */, rs_rX86_SP.GetReg()/*r4sib_no_index*/ /* index */,
+                     r_src.GetReg() /* base */, rs_rX86_SP_32.GetReg()/*r4sib_no_index*/ /* index */,
                      0 /* scale */, value /* disp */);
     }
     OpRegCopy(r_dest, r_src);
@@ -567,32 +570,36 @@
     if (is_fp) {
       DCHECK(r_dest.IsDouble());
       if (value == 0) {
-        return NewLIR2(kX86XorpsRR, low_reg_val, low_reg_val);
-      } else if (base_of_code_ != nullptr) {
+        return NewLIR2(kX86XorpdRR, low_reg_val, low_reg_val);
+      } else if (base_of_code_ != nullptr || cu_->target64) {
         // We will load the value from the literal area.
         LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi);
         if (data_target == NULL) {
           data_target = AddWideData(&literal_list_, val_lo, val_hi);
         }
 
-        // Address the start of the method
-        RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
-        if (rl_method.wide) {
-          rl_method = LoadValueWide(rl_method, kCoreReg);
-        } else {
-          rl_method = LoadValue(rl_method, kCoreReg);
-        }
-
         // Load the proper value from the literal area.
-        // We don't know the proper offset for the value, so pick one that will force
-        // 4 byte offset.  We will fix this up in the assembler later to have the right
-        // value.
+        // We don't know the proper offset for the value, so pick one that
+        // will force 4 byte offset.  We will fix this up in the assembler
+        // later to have the right value.
         ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
-        res = LoadBaseDisp(rl_method.reg, 256 /* bogus */, RegStorage::FloatSolo64(low_reg_val),
-                           kDouble, kNotVolatile);
+        if (cu_->target64) {
+          res = NewLIR3(kX86MovsdRM, low_reg_val, kRIPReg, 256 /* bogus */);
+        } else {
+          // Address the start of the method.
+          RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+          if (rl_method.wide) {
+            rl_method = LoadValueWide(rl_method, kCoreReg);
+          } else {
+            rl_method = LoadValue(rl_method, kCoreReg);
+          }
+
+          res = LoadBaseDisp(rl_method.reg, 256 /* bogus */, RegStorage::FloatSolo64(low_reg_val),
+                             kDouble, kNotVolatile);
+          store_method_addr_used_ = true;
+        }
         res->target = data_target;
         res->flags.fixup = kFixupLoad;
-        store_method_addr_used_ = true;
       } else {
         if (r_dest.IsPair()) {
           if (val_lo == 0) {
@@ -657,7 +664,8 @@
         CHECK_EQ(is_array, false);
         CHECK_EQ(r_dest.IsFloat(), false);
         break;
-      }  // else fall-through to k32 case
+      }
+      FALLTHROUGH_INTENDED;  // else fall-through to k32 case
     case k32:
     case kSingle:
     case kReference:  // TODO: update for reference decompression on 64-bit targets.
@@ -702,7 +710,7 @@
       }
     }
     if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-      DCHECK(r_base == rs_rX86_SP);
+      DCHECK_EQ(r_base, cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32);
       AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
                               true /* is_load */, is64bit);
       if (pair) {
@@ -791,7 +799,7 @@
   switch (size) {
     case k64:
       consider_non_temporal = true;
-      // Fall through!
+      FALLTHROUGH_INTENDED;
     case kDouble:
       if (r_src.IsFloat()) {
         opcode = is_array ? kX86MovsdAR : kX86MovsdMR;
@@ -810,7 +818,8 @@
         CHECK_EQ(r_src.IsFloat(), false);
         consider_non_temporal = true;
         break;
-      }  // else fall-through to k32 case
+      }
+      FALLTHROUGH_INTENDED;  // else fall-through to k32 case
     case k32:
     case kSingle:
     case kReference:
@@ -866,7 +875,7 @@
       store2 = NewLIR3(opcode, r_base.GetReg(), displacement + HIWORD_OFFSET, r_src.GetHighReg());
     }
     if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-      DCHECK(r_base == rs_rX86_SP);
+      DCHECK_EQ(r_base, cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32);
       AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
                               false /* is_load */, is64bit);
       if (pair) {
@@ -932,13 +941,14 @@
 
 LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
                                    int offset, int check_value, LIR* target, LIR** compare) {
-    LIR* inst = NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base_reg.GetReg(),
-            offset, check_value);
-    if (compare != nullptr) {
-        *compare = inst;
-    }
-    LIR* branch = OpCondBranch(cond, target);
-    return branch;
+  UNUSED(temp_reg);  // Comparison performed directly with memory.
+  LIR* inst = NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base_reg.GetReg(),
+      offset, check_value);
+  if (compare != nullptr) {
+    *compare = inst;
+  }
+  LIR* branch = OpCondBranch(cond, target);
+  return branch;
 }
 
 void X86Mir2Lir::AnalyzeMIR() {
@@ -954,22 +964,24 @@
     curr_bb = iter.Next();
   }
 
-  // Did we need a pointer to the method code?
+  // Did we need a pointer to the method code?  Not in 64 bit mode.
+  base_of_code_ = nullptr;
+
+  // store_method_addr_ must be false for x86_64, since RIP addressing is used.
+  CHECK(!(cu_->target64 && store_method_addr_));
   if (store_method_addr_) {
-    base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempBackend, cu_->target64 == true);
+    base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempBackend, false);
     DCHECK(base_of_code_ != nullptr);
-  } else {
-    base_of_code_ = nullptr;
   }
 }
 
-void X86Mir2Lir::AnalyzeBB(BasicBlock * bb) {
+void X86Mir2Lir::AnalyzeBB(BasicBlock* bb) {
   if (bb->block_type == kDead) {
     // Ignore dead blocks
     return;
   }
 
-  for (MIR *mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+  for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
     int opcode = mir->dalvikInsn.opcode;
     if (MIR::DecodedInstruction::IsPseudoMirOp(opcode)) {
       AnalyzeExtendedMIR(opcode, bb, mir);
@@ -980,7 +992,7 @@
 }
 
 
-void X86Mir2Lir::AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir) {
+void X86Mir2Lir::AnalyzeExtendedMIR(int opcode, BasicBlock* bb, MIR* mir) {
   switch (opcode) {
     // Instructions referencing doubles.
     case kMirOpFusedCmplDouble:
@@ -988,28 +1000,32 @@
       AnalyzeFPInstruction(opcode, bb, mir);
       break;
     case kMirOpConstVector:
-      store_method_addr_ = true;
+      if (!cu_->target64) {
+        store_method_addr_ = true;
+      }
       break;
     case kMirOpPackedMultiply:
     case kMirOpPackedShiftLeft:
     case kMirOpPackedSignedShiftRight:
-    case kMirOpPackedUnsignedShiftRight: {
-      // Byte emulation requires constants from the literal pool.
-      OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
-      if (opsize == kSignedByte || opsize == kUnsignedByte) {
-        store_method_addr_ = true;
+    case kMirOpPackedUnsignedShiftRight:
+      if (!cu_->target64) {
+        // Byte emulation requires constants from the literal pool.
+        OpSize opsize = static_cast<OpSize>(mir->dalvikInsn.vC >> 16);
+        if (opsize == kSignedByte || opsize == kUnsignedByte) {
+          store_method_addr_ = true;
+        }
       }
       break;
-    }
     default:
       // Ignore the rest.
       break;
   }
 }
 
-void X86Mir2Lir::AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir) {
+void X86Mir2Lir::AnalyzeMIR(int opcode, BasicBlock* bb, MIR* mir) {
   // Looking for
   // - Do we need a pointer to the code (used for packed switches and double lits)?
+  // 64 bit uses RIP addressing instead.
 
   switch (opcode) {
     // Instructions referencing doubles.
@@ -1032,7 +1048,9 @@
     // Packed switches and array fills need a pointer to the base of the method.
     case Instruction::FILL_ARRAY_DATA:
     case Instruction::PACKED_SWITCH:
-      store_method_addr_ = true;
+      if (!cu_->target64) {
+        store_method_addr_ = true;
+      }
       break;
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE:
@@ -1044,7 +1062,8 @@
   }
 }
 
-void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) {
+void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock* bb, MIR* mir) {
+  UNUSED(bb);
   // Look at all the uses, and see if they are double constants.
   uint64_t attrs = MIRGraph::GetDataFlowAttributes(static_cast<Instruction::Code>(opcode));
   int next_sreg = 0;
@@ -1078,7 +1097,7 @@
   }
 }
 
-RegLocation X86Mir2Lir::UpdateLocTyped(RegLocation loc, int reg_class) {
+RegLocation X86Mir2Lir::UpdateLocTyped(RegLocation loc) {
   loc = UpdateLoc(loc);
   if ((loc.location == kLocPhysReg) && (loc.fp != loc.reg.IsFloat())) {
     if (GetRegInfo(loc.reg)->IsTemp()) {
@@ -1092,7 +1111,7 @@
   return loc;
 }
 
-RegLocation X86Mir2Lir::UpdateLocWideTyped(RegLocation loc, int reg_class) {
+RegLocation X86Mir2Lir::UpdateLocWideTyped(RegLocation loc) {
   loc = UpdateLocWide(loc);
   if ((loc.location == kLocPhysReg) && (loc.fp != loc.reg.IsFloat())) {
     if (GetRegInfo(loc.reg)->IsTemp()) {
@@ -1106,8 +1125,10 @@
   return loc;
 }
 
-void X86Mir2Lir::AnalyzeInvokeStatic(int opcode, BasicBlock * bb, MIR *mir) {
-  // For now this is only actual for x86-32.
+void X86Mir2Lir::AnalyzeInvokeStatic(int opcode, BasicBlock* bb, MIR* mir) {
+  UNUSED(opcode, bb);
+
+  // 64 bit RIP addressing doesn't need store_method_addr_ set.
   if (cu_->target64) {
     return;
   }
@@ -1130,6 +1151,7 @@
 }
 
 LIR* X86Mir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
+  UNUSED(r_tgt);  // Call to absolute memory location doesn't need a temporary target register.
   if (cu_->target64) {
     return OpThreadMem(op, GetThreadOffset<8>(trampoline));
   } else {
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 22a2f30..3e0a852 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -217,6 +217,9 @@
   xr14 = RegStorage::k128BitSolo | 14,
   xr15 = RegStorage::k128BitSolo | 15,
 
+  // Special value for RIP 64 bit addressing.
+  kRIPReg = 255,
+
   // TODO: as needed, add 256, 512 and 1024-bit xmm views.
 };
 
@@ -234,7 +237,7 @@
 constexpr RegStorage rs_rBX = rs_r3;
 constexpr RegStorage rs_rX86_SP_64(RegStorage::kValid | r4sp_64);
 constexpr RegStorage rs_rX86_SP_32(RegStorage::kValid | r4sp_32);
-extern RegStorage rs_rX86_SP;
+static_assert(rs_rX86_SP_64.GetRegNum() == rs_rX86_SP_32.GetRegNum(), "Unexpected mismatch");
 constexpr RegStorage rs_r5(RegStorage::kValid | r5);
 constexpr RegStorage rs_r5q(RegStorage::kValid | r5q);
 constexpr RegStorage rs_rBP = rs_r5;
@@ -313,43 +316,8 @@
 constexpr RegStorage rs_xr14(RegStorage::kValid | xr14);
 constexpr RegStorage rs_xr15(RegStorage::kValid | xr15);
 
-extern X86NativeRegisterPool rX86_ARG0;
-extern X86NativeRegisterPool rX86_ARG1;
-extern X86NativeRegisterPool rX86_ARG2;
-extern X86NativeRegisterPool rX86_ARG3;
-extern X86NativeRegisterPool rX86_ARG4;
-extern X86NativeRegisterPool rX86_ARG5;
-extern X86NativeRegisterPool rX86_FARG0;
-extern X86NativeRegisterPool rX86_FARG1;
-extern X86NativeRegisterPool rX86_FARG2;
-extern X86NativeRegisterPool rX86_FARG3;
-extern X86NativeRegisterPool rX86_FARG4;
-extern X86NativeRegisterPool rX86_FARG5;
-extern X86NativeRegisterPool rX86_FARG6;
-extern X86NativeRegisterPool rX86_FARG7;
-extern X86NativeRegisterPool rX86_RET0;
-extern X86NativeRegisterPool rX86_RET1;
-extern X86NativeRegisterPool rX86_INVOKE_TGT;
-extern X86NativeRegisterPool rX86_COUNT;
-
-extern RegStorage rs_rX86_ARG0;
-extern RegStorage rs_rX86_ARG1;
-extern RegStorage rs_rX86_ARG2;
-extern RegStorage rs_rX86_ARG3;
-extern RegStorage rs_rX86_ARG4;
-extern RegStorage rs_rX86_ARG5;
-extern RegStorage rs_rX86_FARG0;
-extern RegStorage rs_rX86_FARG1;
-extern RegStorage rs_rX86_FARG2;
-extern RegStorage rs_rX86_FARG3;
-extern RegStorage rs_rX86_FARG4;
-extern RegStorage rs_rX86_FARG5;
-extern RegStorage rs_rX86_FARG6;
-extern RegStorage rs_rX86_FARG7;
-extern RegStorage rs_rX86_RET0;
-extern RegStorage rs_rX86_RET1;
-extern RegStorage rs_rX86_INVOKE_TGT;
-extern RegStorage rs_rX86_COUNT;
+constexpr RegStorage rs_rX86_RET0 = rs_rAX;
+constexpr RegStorage rs_rX86_RET1 = rs_rDX;
 
 // RegisterLocation templates return values (r_V0, or r_V0/r_V1).
 const RegLocation x86_loc_c_return
@@ -674,6 +642,7 @@
   kX86RepneScasw,       // repne scasw
   kX86Last
 };
+std::ostream& operator<<(std::ostream& os, const X86OpCode& rhs);
 
 /* Instruction assembly field_loc kind */
 enum X86EncodingKind {
diff --git a/compiler/dex/reg_storage.h b/compiler/dex/reg_storage.h
index 706933a..46ed011 100644
--- a/compiler/dex/reg_storage.h
+++ b/compiler/dex/reg_storage.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_DEX_REG_STORAGE_H_
 
 #include "base/logging.h"
+#include "base/value_object.h"
 #include "compiler_enums.h"  // For WideKind
 
 namespace art {
@@ -72,7 +73,7 @@
  * records.
  */
 
-class RegStorage {
+class RegStorage : public ValueObject {
  public:
   enum RegStorageKind {
     kValidMask     = 0x8000,
@@ -112,7 +113,7 @@
   }
   constexpr RegStorage(RegStorageKind rs_kind, int low_reg, int high_reg)
       : reg_(
-          DCHECK_CONSTEXPR(rs_kind == k64BitPair, << rs_kind, 0u)
+          DCHECK_CONSTEXPR(rs_kind == k64BitPair, << static_cast<int>(rs_kind), 0u)
           DCHECK_CONSTEXPR((low_reg & kFloatingPoint) == (high_reg & kFloatingPoint),
                            << low_reg << ", " << high_reg, 0u)
           DCHECK_CONSTEXPR((high_reg & kRegNumMask) <= kHighRegNumMask,
@@ -331,14 +332,16 @@
       case k256BitSolo: return 32;
       case k512BitSolo: return 64;
       case k1024BitSolo: return 128;
-      default: LOG(FATAL) << "Unexpected shape";
+      default: LOG(FATAL) << "Unexpected shape"; UNREACHABLE();
     }
-    return 0;
   }
 
  private:
   uint16_t reg_;
 };
+static inline std::ostream& operator<<(std::ostream& o, const RegStorage& rhs) {
+  return o << rhs.GetRawBits();  // TODO: better output.
+}
 
 }  // namespace art
 
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index 3cc573b..3905649 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()) {
@@ -102,15 +103,16 @@
 
   num_reachable_blocks_ = dfs_order_.size();
 
-  if (num_reachable_blocks_ != num_blocks_) {
-    // Hide all unreachable blocks.
+  if (num_reachable_blocks_ != GetNumBlocks()) {
+    // Kill all unreachable blocks.
     AllNodesIterator iter(this);
     for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
       if (!bb->visited) {
-        bb->Hide(cu_);
+        bb->Kill(this);
       }
     }
   }
+  dfs_orders_up_to_date_ = true;
 }
 
 /*
@@ -124,7 +126,7 @@
 
   for (uint32_t idx : bb->data_flow_info->def_v->Indexes()) {
     /* Block bb defines register idx */
-    def_block_matrix_[idx]->SetBit(bb->id);
+    temp_.ssa.def_block_matrix[idx]->SetBit(bb->id);
   }
   return true;
 }
@@ -132,15 +134,17 @@
 void MIRGraph::ComputeDefBlockMatrix() {
   int num_registers = GetNumOfCodeAndTempVRs();
   /* Allocate num_registers bit vector pointers */
-  def_block_matrix_ = static_cast<ArenaBitVector**>
-      (arena_->Alloc(sizeof(ArenaBitVector *) * num_registers,
-                     kArenaAllocDFInfo));
+  DCHECK(temp_scoped_alloc_ != nullptr);
+  DCHECK(temp_.ssa.def_block_matrix == nullptr);
+  temp_.ssa.def_block_matrix = static_cast<ArenaBitVector**>(
+      temp_scoped_alloc_->Alloc(sizeof(ArenaBitVector*) * num_registers, kArenaAllocDFInfo));
   int i;
 
   /* Initialize num_register vectors with num_blocks bits each */
   for (i = 0; i < num_registers; i++) {
-    def_block_matrix_[i] =
-        new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapBMatrix);
+    temp_.ssa.def_block_matrix[i] = new (temp_scoped_alloc_.get()) ArenaBitVector(
+        arena_, GetNumBlocks(), false, kBitMapBMatrix);
+    temp_.ssa.def_block_matrix[i]->ClearAllBits();
   }
 
   AllNodesIterator iter(this);
@@ -159,7 +163,7 @@
   int num_regs = GetNumOfCodeVRs();
   int in_reg = GetFirstInVR();
   for (; in_reg < num_regs; in_reg++) {
-    def_block_matrix_[in_reg]->SetBit(GetEntryBlock()->id);
+    temp_.ssa.def_block_matrix[in_reg]->SetBit(GetEntryBlock()->id);
   }
 }
 
@@ -169,9 +173,9 @@
   dom_post_order_traversal_.reserve(num_reachable_blocks_);
 
   ClearAllVisitedFlags();
-  DCHECK(temp_scoped_alloc_.get() != nullptr);
+  ScopedArenaAllocator allocator(&cu_->arena_stack);
   ScopedArenaVector<std::pair<BasicBlock*, ArenaBitVector::IndexIterator>> work_stack(
-      temp_scoped_alloc_->Adapter());
+      allocator.Adapter());
   bb->visited = true;
   work_stack.push_back(std::make_pair(bb, bb->i_dominated->Indexes().begin()));
   while (!work_stack.empty()) {
@@ -193,12 +197,6 @@
         dom_post_order_traversal_.push_back(curr_bb->id);
       }
       work_stack.pop_back();
-
-      /* hacky loop detection */
-      if ((curr_bb->taken != NullBasicBlockId) && curr_bb->dominators->IsBitSet(curr_bb->taken)) {
-        curr_bb->nesting_depth++;
-        attributes_ |= METHOD_HAS_LOOP;
-      }
     }
   }
 }
@@ -404,6 +402,8 @@
   for (BasicBlock* bb = iter5.Next(); bb != NULL; bb = iter5.Next()) {
     ComputeDominanceFrontier(bb);
   }
+
+  domination_up_to_date_ = true;
 }
 
 /*
@@ -431,32 +431,32 @@
  * insert a phi node if the variable is live-in to the block.
  */
 bool MIRGraph::ComputeBlockLiveIns(BasicBlock* bb) {
-  DCHECK_EQ(temp_bit_vector_size_, cu_->mir_graph.get()->GetNumOfCodeAndTempVRs());
-  ArenaBitVector* temp_dalvik_register_v = temp_bit_vector_;
+  DCHECK_EQ(temp_.ssa.num_vregs, cu_->mir_graph.get()->GetNumOfCodeAndTempVRs());
+  ArenaBitVector* temp_live_vregs = temp_.ssa.work_live_vregs;
 
   if (bb->data_flow_info == NULL) {
     return false;
   }
-  temp_dalvik_register_v->Copy(bb->data_flow_info->live_in_v);
+  temp_live_vregs->Copy(bb->data_flow_info->live_in_v);
   BasicBlock* bb_taken = GetBasicBlock(bb->taken);
   BasicBlock* bb_fall_through = GetBasicBlock(bb->fall_through);
   if (bb_taken && bb_taken->data_flow_info)
-    ComputeSuccLineIn(temp_dalvik_register_v, bb_taken->data_flow_info->live_in_v,
+    ComputeSuccLineIn(temp_live_vregs, bb_taken->data_flow_info->live_in_v,
                       bb->data_flow_info->def_v);
   if (bb_fall_through && bb_fall_through->data_flow_info)
-    ComputeSuccLineIn(temp_dalvik_register_v, bb_fall_through->data_flow_info->live_in_v,
+    ComputeSuccLineIn(temp_live_vregs, bb_fall_through->data_flow_info->live_in_v,
                       bb->data_flow_info->def_v);
   if (bb->successor_block_list_type != kNotUsed) {
     for (SuccessorBlockInfo* successor_block_info : bb->successor_blocks) {
       BasicBlock* succ_bb = GetBasicBlock(successor_block_info->block);
       if (succ_bb->data_flow_info) {
-        ComputeSuccLineIn(temp_dalvik_register_v, succ_bb->data_flow_info->live_in_v,
+        ComputeSuccLineIn(temp_live_vregs, succ_bb->data_flow_info->live_in_v,
                           bb->data_flow_info->def_v);
       }
     }
   }
-  if (!temp_dalvik_register_v->Equal(bb->data_flow_info->live_in_v)) {
-    bb->data_flow_info->live_in_v->Copy(temp_dalvik_register_v);
+  if (!temp_live_vregs->Equal(bb->data_flow_info->live_in_v)) {
+    bb->data_flow_info->live_in_v->Copy(temp_live_vregs);
     return true;
   }
   return false;
@@ -478,7 +478,7 @@
 
   /* Iterate through each Dalvik register */
   for (dalvik_reg = GetNumOfCodeAndTempVRs() - 1; dalvik_reg >= 0; dalvik_reg--) {
-    input_blocks->Copy(def_block_matrix_[dalvik_reg]);
+    input_blocks->Copy(temp_.ssa.def_block_matrix[dalvik_reg]);
     phi_blocks->ClearAllBits();
     do {
       // TUNING: When we repeat this, we could skip indexes from the previous pass.
@@ -535,8 +535,7 @@
     for (BasicBlockId pred_id : bb->predecessors) {
       BasicBlock* pred_bb = GetBasicBlock(pred_id);
       DCHECK(pred_bb != nullptr);
-      int ssa_reg = pred_bb->data_flow_info->vreg_to_ssa_map_exit[v_reg];
-      uses[idx] = ssa_reg;
+      uses[idx] = pred_bb->data_flow_info->vreg_to_ssa_map_exit[v_reg];
       incoming[idx] = pred_id;
       idx++;
     }
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index a8e6b3c..4daed67 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -57,8 +57,8 @@
 
   const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
   if (verified_method == nullptr) {
-    DCHECK(method_verifier->HasFailures());
-    return false;
+    // Do not report an error to the verifier. We'll just punt this later.
+    return true;
   }
 
   WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
@@ -84,6 +84,15 @@
   return (it != verified_methods_.end()) ? it->second : nullptr;
 }
 
+void VerificationResults::RemoveVerifiedMethod(MethodReference ref) {
+  WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+  auto it = verified_methods_.find(ref);
+  if (it != verified_methods_.end()) {
+    delete it->second;
+    verified_methods_.erase(it);
+  }
+}
+
 void VerificationResults::AddRejectedClass(ClassReference ref) {
   {
     WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
@@ -97,16 +106,8 @@
   return (rejected_classes_.find(ref) != rejected_classes_.end());
 }
 
-bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref,
+bool VerificationResults::IsCandidateForCompilation(MethodReference&,
                                                     const uint32_t access_flags) {
-#ifdef ART_SEA_IR_MODE
-  bool use_sea = compiler_options_->GetSeaIrMode();
-  use_sea = use_sea && (std::string::npos != PrettyMethod(
-                        method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
-  if (use_sea) {
-    return true;
-  }
-#endif
   if (!compiler_options_->IsCompilationEnabled()) {
     return false;
   }
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 0e7923f..7fc2a23 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -48,6 +48,7 @@
 
     const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
         LOCKS_EXCLUDED(verified_methods_lock_);
+    void RemoveVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_);
 
     void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
     bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 9f0a696..93e9a51 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -49,7 +49,6 @@
   if (compile) {
     /* Generate a register map. */
     if (!verified_method->GenerateGcMap(method_verifier)) {
-      CHECK(method_verifier->HasFailures());
       return nullptr;  // Not a real failure, but a failure to encode.
     }
     if (kIsDebugBuild) {
@@ -82,33 +81,33 @@
   size_t num_entries, ref_bitmap_bits, pc_bits;
   ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
   // There's a single byte to encode the size of each bitmap.
-  if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) {
-    // TODO: either a better GC map format or per method failures
-    method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
-        << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
+  if (ref_bitmap_bits >= kBitsPerByte * 8192 /* 13-bit size */) {
+    LOG(WARNING) << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers: "
+                 << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+                                 *method_verifier->GetMethodReference().dex_file);
     return false;
   }
-  size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
+  size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
   // There are 2 bytes to encode the number of entries.
   if (num_entries >= 65536) {
-    // TODO: Either a better GC map format or per method failures.
-    method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
-        << "Cannot encode GC map for method with " << num_entries << " entries";
+    LOG(WARNING) << "Cannot encode GC map for method with " << num_entries << " entries: "
+                 << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+                                 *method_verifier->GetMethodReference().dex_file);
     return false;
   }
   size_t pc_bytes;
   verifier::RegisterMapFormat format;
-  if (pc_bits <= 8) {
+  if (pc_bits <= kBitsPerByte) {
     format = verifier::kRegMapFormatCompact8;
     pc_bytes = 1;
-  } else if (pc_bits <= 16) {
+  } else if (pc_bits <= kBitsPerByte * 2) {
     format = verifier::kRegMapFormatCompact16;
     pc_bytes = 2;
   } else {
-    // TODO: Either a better GC map format or per method failures.
-    method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
-        << "Cannot encode GC map for method with "
-        << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
+    LOG(WARNING) << "Cannot encode GC map for method with "
+                 << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2): "
+                 << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+                                 *method_verifier->GetMethodReference().dex_file);
     return false;
   }
   size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
@@ -152,16 +151,16 @@
       verifier::RegisterLine* line = method_verifier->GetRegLine(i);
       for (size_t j = 0; j < code_item->registers_size_; j++) {
         if (line->GetRegisterType(method_verifier, j).IsNonZeroReferenceTypes()) {
-          DCHECK_LT(j / 8, map.RegWidth());
-          DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
-        } else if ((j / 8) < map.RegWidth()) {
-          DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
+          DCHECK_LT(j / kBitsPerByte, map.RegWidth());
+          DCHECK_EQ((reg_bitmap[j / kBitsPerByte] >> (j % kBitsPerByte)) & 1, 1);
+        } else if ((j / kBitsPerByte) < map.RegWidth()) {
+          DCHECK_EQ((reg_bitmap[j / kBitsPerByte] >> (j % kBitsPerByte)) & 1, 0);
         } else {
           // If a register doesn't contain a reference then the bitmap may be shorter than the line.
         }
       }
     } else {
-      DCHECK(reg_bitmap == NULL);
+      DCHECK(i >= 65536 || reg_bitmap == NULL);
     }
   }
 }
@@ -190,6 +189,31 @@
   *log2_max_gc_pc = i;
 }
 
+void VerifiedMethod::GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier) {
+  if (method_verifier->HasFailures()) {
+    return;
+  }
+  const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+  const uint16_t* insns = code_item->insns_;
+  const Instruction* inst = Instruction::At(insns);
+  const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
+  for (; inst < end; inst = inst->Next()) {
+    const bool is_virtual_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK;
+    const bool is_range_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK;
+    if (is_virtual_quick || is_range_quick) {
+      uint32_t dex_pc = inst->GetDexPc(insns);
+      verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+      mirror::ArtMethod* method = method_verifier->GetQuickInvokedMethod(inst, line,
+                                                                         is_range_quick);
+      CHECK(method != nullptr);
+      // The verifier must know what the type of the object was or else we would have gotten a
+      // failure. Put the dex method index in the dequicken map since we need this to get number of
+      // arguments in the compiler.
+      dequicken_map_.Put(dex_pc, method->ToMethodReference());
+    }
+  }
+}
+
 void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) {
   // It is risky to rely on reg_types for sharpening in cases of soft
   // verification, we might end up sharpening to a wrong implementation. Just abort.
@@ -203,10 +227,10 @@
   const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
 
   for (; inst < end; inst = inst->Next()) {
-    bool is_virtual   = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
-        (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE);
-    bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
-        (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+    const bool is_virtual = inst->Opcode() == Instruction::INVOKE_VIRTUAL ||
+        inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE;
+    const bool is_interface = inst->Opcode() == Instruction::INVOKE_INTERFACE ||
+        inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE;
 
     if (!is_interface && !is_virtual) {
       continue;
@@ -214,8 +238,8 @@
     // Get reg type for register holding the reference to the object that will be dispatched upon.
     uint32_t dex_pc = inst->GetDexPc(insns);
     verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
-    bool is_range = (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE) ||
-        (inst->Opcode() ==  Instruction::INVOKE_INTERFACE_RANGE);
+    const bool is_range = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
+        inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE;
     const verifier::RegType&
         reg_type(line->GetRegisterType(method_verifier,
                                        is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
@@ -241,14 +265,14 @@
       continue;
     }
     // Find the concrete method.
-    mirror::ArtMethod* concrete_method = NULL;
+    mirror::ArtMethod* concrete_method = nullptr;
     if (is_interface) {
       concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method);
     }
     if (is_virtual) {
       concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
     }
-    if (concrete_method == NULL || concrete_method->IsAbstract()) {
+    if (concrete_method == nullptr || concrete_method->IsAbstract()) {
       // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
       continue;
     }
@@ -256,10 +280,7 @@
         concrete_method->GetDeclaringClass()->IsFinal()) {
       // If we knew exactly the class being dispatched upon, or if the target method cannot be
       // overridden record the target to be used in the compiler driver.
-      MethodReference concrete_ref(
-          concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
-          concrete_method->GetDexMethodIndex());
-      devirt_map_.Put(dex_pc, concrete_ref);
+      devirt_map_.Put(dex_pc, concrete_method->ToMethodReference());
     }
   }
 }
@@ -282,6 +303,10 @@
     Instruction::Code code = inst->Opcode();
     if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
       uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+      if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) {
+        // Do not attempt to quicken this instruction, it's unreachable anyway.
+        continue;
+      }
       const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
       bool is_safe_cast = false;
       if (code == Instruction::CHECK_CAST) {
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index 257e70c..fe9dfd1 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -85,12 +85,19 @@
   void GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Generate dequickening map into dequicken_map_.
+  void GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Generate safe case set into safe_cast_set_.
   void GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   std::vector<uint8_t> dex_gc_map_;
   DevirtualizationMap devirt_map_;
+  // Dequicken map is required for having the compiler compiled quickened invokes. The quicken map
+  // enables us to get the dex method index so that we can get the required argument count.
+  DevirtualizationMap dequicken_map_;
   SafeCastSet safe_cast_set_;
 };
 
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index bdfab13..62c4089 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -276,8 +276,7 @@
       }
       int num_uses = mir->dalvikInsn.vA;
       // If this is a non-static invoke, mark implicit "this"
-      if (((mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC) &&
-          (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) {
+      if (!IsInstructionInvokeStatic(mir->dalvikInsn.opcode)) {
         reg_location_[uses[next]].defined = true;
         reg_location_[uses[next]].ref = true;
         type_mismatch |= reg_location_[uses[next]].wide;
@@ -378,7 +377,20 @@
         changed |= SetWide(defs[1]);
         changed |= SetHigh(defs[1]);
       }
+
+      bool has_ins = (GetNumOfInVRs() > 0);
+
       for (int i = 0; i < ssa_rep->num_uses; i++) {
+        if (has_ins && IsInVReg(uses[i])) {
+          // NB: The SSA name for the first def of an in-reg will be the same as
+          // the reg's actual name.
+          if (!reg_location_[uses[i]].fp && defined_fp) {
+            // If we were about to infer that this first def of an in-reg is a float
+            // when it wasn't previously (because float/int is set during SSA initialization),
+            // do not allow this to happen.
+            continue;
+          }
+        }
         changed |= SetFp(uses[i], defined_fp);
         changed |= SetCore(uses[i], defined_core);
         changed |= SetRef(uses[i], defined_ref);
@@ -430,7 +442,7 @@
   for (int i = 0; i < GetNumSSARegs(); i++) {
     loc[i] = fresh_loc;
     loc[i].s_reg_low = i;
-    loc[i].is_const = is_constant_v_->IsBitSet(i);
+    loc[i].is_const = false;  // Constants will be marked by constant propagation pass later.
     loc[i].wide = false;
   }
 
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 4d5d253..3a91b08 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -21,7 +21,6 @@
 
 #include "dex/compiler_ir.h"
 #include "dex_compilation_unit.h"
-#include "field_helper.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class_loader.h"
@@ -93,6 +92,10 @@
   return field->IsVolatile();
 }
 
+inline MemberOffset CompilerDriver::GetFieldOffset(mirror::ArtField* field) {
+  return field->GetOffset();
+}
+
 inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
     mirror::DexCache* dex_cache, mirror::Class* referrer_class,
     mirror::ArtField* resolved_field, uint16_t field_idx) {
@@ -107,16 +110,12 @@
 
 inline std::pair<bool, bool> CompilerDriver::IsFastStaticField(
     mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-    mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset,
-    uint32_t* storage_index, bool* is_referrers_class, bool* is_initialized) {
+    mirror::ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) {
   DCHECK(resolved_field->IsStatic());
   if (LIKELY(referrer_class != nullptr)) {
     mirror::Class* fields_class = resolved_field->GetDeclaringClass();
     if (fields_class == referrer_class) {
-      *field_offset = resolved_field->GetOffset();
       *storage_index = fields_class->GetDexTypeIndex();
-      *is_referrers_class = true;  // implies no worrying about class initialization
-      *is_initialized = true;
       return std::make_pair(true, true);
     }
     if (referrer_class->CanAccessResolvedField(fields_class, resolved_field,
@@ -134,10 +133,9 @@
       } else {
         // Search dex file for localized ssb index, may fail if field's class is a parent
         // of the class mentioned in the dex file and there is no dex cache entry.
-        StackHandleScope<1> hs(Thread::Current());
+        std::string temp;
         const DexFile::StringId* string_id =
-            dex_file->FindStringId(
-                FieldHelper(hs.NewHandle(resolved_field)).GetDeclaringClassDescriptor());
+            dex_file->FindStringId(resolved_field->GetDeclaringClass()->GetDescriptor(&temp));
         if (string_id != nullptr) {
           const DexFile::TypeId* type_id =
              dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
@@ -148,23 +146,30 @@
         }
       }
       if (storage_idx != DexFile::kDexNoIndex) {
-        *field_offset = resolved_field->GetOffset();
         *storage_index = storage_idx;
-        *is_referrers_class = false;
-        *is_initialized = fields_class->IsInitialized() &&
-            CanAssumeTypeIsPresentInDexCache(*dex_file, storage_idx);
         return std::make_pair(true, !resolved_field->IsFinal());
       }
     }
   }
   // Conservative defaults.
-  *field_offset = MemberOffset(0u);
   *storage_index = DexFile::kDexNoIndex;
-  *is_referrers_class = false;
-  *is_initialized = false;
   return std::make_pair(false, false);
 }
 
+inline bool CompilerDriver::IsStaticFieldInReferrerClass(mirror::Class* referrer_class,
+                                                         mirror::ArtField* resolved_field) {
+  DCHECK(resolved_field->IsStatic());
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  return referrer_class == fields_class;
+}
+
+inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class,
+                                                           mirror::ArtField* resolved_field) {
+  DCHECK(resolved_field->IsStatic());
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  return fields_class == referrer_class || fields_class->IsInitialized();
+}
+
 inline mirror::ArtMethod* CompilerDriver::ResolveMethod(
     ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
@@ -233,7 +238,8 @@
   bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) &&
       (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
       resolved_method->GetMethodIndex() < methods_class->GetVTableLength() &&
-      (methods_class->GetVTableEntry(resolved_method->GetMethodIndex()) == resolved_method);
+      (methods_class->GetVTableEntry(resolved_method->GetMethodIndex()) == resolved_method) &&
+      !resolved_method->IsAbstract();
 
   if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) {
     // Sharpen a virtual call into a direct call. The method_idx is into referrer's
@@ -243,8 +249,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 +285,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,19 +307,24 @@
 
   // 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;
 }
 
-inline bool CompilerDriver::NeedsClassInitialization(mirror::Class* referrer_class,
-                                                     mirror::ArtMethod* resolved_method) {
+inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class,
+                                                      mirror::ArtMethod* resolved_method) {
   if (!resolved_method->IsStatic()) {
-    return false;
+    return true;
   }
   mirror::Class* methods_class = resolved_method->GetDeclaringClass();
-  // NOTE: Unlike in IsFastStaticField(), we don't check CanAssumeTypeIsPresentInDexCache() here.
-  return methods_class != referrer_class && !methods_class->IsInitialized();
+  return methods_class == referrer_class || methods_class->IsInitialized();
 }
 
 }  // namespace art
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index cdb816d..7451bd5 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -19,9 +19,14 @@
 #define ATRACE_TAG ATRACE_TAG_DALVIK
 #include <utils/Trace.h>
 
+#include <unordered_set>
 #include <vector>
 #include <unistd.h>
 
+#ifndef __APPLE__
+#include <malloc.h>  // For mallinfo
+#endif
+
 #include "base/stl_util.h"
 #include "base/timing_logger.h"
 #include "class_linker.h"
@@ -53,9 +58,11 @@
 #include "ScopedLocalRef.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
+#include "thread_list.h"
 #include "thread_pool.h"
 #include "trampolines/trampoline_compiler.h"
 #include "transaction.h"
+#include "utils/swap_space.h"
 #include "verifier/method_verifier.h"
 #include "verifier/method_verifier-inl.h"
 
@@ -329,11 +336,15 @@
                                DexFileToMethodInlinerMap* method_inliner_map,
                                Compiler::Kind compiler_kind,
                                InstructionSet instruction_set,
-                               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)
-    : profile_present_(false), compiler_options_(compiler_options),
+                               const InstructionSetFeatures* instruction_set_features,
+                               bool image, std::set<std::string>* image_classes,
+                               std::set<std::string>* compiled_classes, size_t thread_count,
+                               bool dump_stats, bool dump_passes,
+                               const std::string& dump_cfg_file_name, CumulativeLogger* timer,
+                               int swap_fd, const std::string& profile_file)
+    : swap_space_(swap_fd == -1 ? nullptr : new SwapSpace(swap_fd, 10 * MB)),
+      swap_space_allocator_(new SwapAllocator<void>(swap_space_.get())),
+      profile_present_(false), compiler_options_(compiler_options),
       verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
       compiler_(Compiler::Create(this, compiler_kind)),
@@ -342,33 +353,29 @@
       freezing_constructor_lock_("freezing constructor lock"),
       compiled_classes_lock_("compiled classes lock"),
       compiled_methods_lock_("compiled method lock"),
-      compiled_methods_(),
+      compiled_methods_(MethodTable::key_compare()),
       non_relative_linker_patch_count_(0u),
       image_(image),
       image_classes_(image_classes),
+      classes_to_compile_(compiled_classes),
       thread_count_(thread_count),
-      start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
       dump_passes_(dump_passes),
+      dump_cfg_file_name_(dump_cfg_file_name),
       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"),
-      dedupe_mapping_table_("dedupe mapping table"),
-      dedupe_vmap_table_("dedupe vmap table"),
-      dedupe_gc_map_("dedupe gc map"),
-      dedupe_cfi_info_("dedupe cfi info") {
+      support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64),
+      dedupe_code_("dedupe code", *swap_space_allocator_),
+      dedupe_src_mapping_table_("dedupe source mapping table", *swap_space_allocator_),
+      dedupe_mapping_table_("dedupe mapping table", *swap_space_allocator_),
+      dedupe_vmap_table_("dedupe vmap table", *swap_space_allocator_),
+      dedupe_gc_map_("dedupe gc map", *swap_space_allocator_),
+      dedupe_cfi_info_("dedupe cfi info", *swap_space_allocator_) {
   DCHECK(compiler_options_ != nullptr);
   DCHECK(verification_results_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
 
-  CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, nullptr), "compiler tls key");
-
   dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
 
   compiler_->Init();
@@ -391,31 +398,28 @@
   }
 }
 
-std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t>& code) {
+SwapVector<uint8_t>* CompilerDriver::DeduplicateCode(const ArrayRef<const uint8_t>& code) {
   return dedupe_code_.Add(Thread::Current(), code);
 }
 
-SrcMap* CompilerDriver::DeduplicateSrcMappingTable(const SrcMap& src_map) {
+SwapSrcMap* CompilerDriver::DeduplicateSrcMappingTable(const ArrayRef<SrcMapElem>& src_map) {
   return dedupe_src_mapping_table_.Add(Thread::Current(), src_map);
 }
 
-std::vector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const std::vector<uint8_t>& code) {
+SwapVector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const ArrayRef<const uint8_t>& code) {
   return dedupe_mapping_table_.Add(Thread::Current(), code);
 }
 
-std::vector<uint8_t>* CompilerDriver::DeduplicateVMapTable(const std::vector<uint8_t>& code) {
+SwapVector<uint8_t>* CompilerDriver::DeduplicateVMapTable(const ArrayRef<const uint8_t>& code) {
   return dedupe_vmap_table_.Add(Thread::Current(), code);
 }
 
-std::vector<uint8_t>* CompilerDriver::DeduplicateGCMap(const std::vector<uint8_t>& code) {
+SwapVector<uint8_t>* CompilerDriver::DeduplicateGCMap(const ArrayRef<const uint8_t>& code) {
   return dedupe_gc_map_.Add(Thread::Current(), code);
 }
 
-std::vector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info) {
-  if (cfi_info == nullptr) {
-    return nullptr;
-  }
-  return dedupe_cfi_info_.Add(Thread::Current(), *cfi_info);
+SwapVector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info) {
+  return dedupe_cfi_info_.Add(Thread::Current(), cfi_info);
 }
 
 CompilerDriver::~CompilerDriver() {
@@ -426,22 +430,13 @@
   }
   {
     MutexLock mu(self, compiled_methods_lock_);
-    STLDeleteValues(&compiled_methods_);
+    for (auto& pair : compiled_methods_) {
+      CompiledMethod::ReleaseSwapAllocatedCompiledMethod(this, pair.second);
+    }
   }
-  CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
   compiler_->UnInit();
 }
 
-CompilerTls* CompilerDriver::GetTls() {
-  // Lazily create thread-local storage
-  CompilerTls* res = static_cast<CompilerTls*>(pthread_getspecific(tls_key_));
-  if (res == nullptr) {
-    res = compiler_->CreateNewCompilerTls();
-    CHECK_PTHREAD_CALL(pthread_setspecific, (tls_key_, res), "compiler tls");
-  }
-  return res;
-}
-
 #define CREATE_TRAMPOLINE(type, abi, offset) \
     if (Is64BitInstructionSet(instruction_set_)) { \
       return CreateTrampoline64(instruction_set_, abi, \
@@ -463,18 +458,6 @@
   CREATE_TRAMPOLINE(JNI, kJniAbi, pDlsymLookup)
 }
 
-const std::vector<uint8_t>* CompilerDriver::CreatePortableImtConflictTrampoline() const {
-  CREATE_TRAMPOLINE(PORTABLE, kPortableAbi, pPortableImtConflictTrampoline)
-}
-
-const std::vector<uint8_t>* CompilerDriver::CreatePortableResolutionTrampoline() const {
-  CREATE_TRAMPOLINE(PORTABLE, kPortableAbi, pPortableResolutionTrampoline)
-}
-
-const std::vector<uint8_t>* CompilerDriver::CreatePortableToInterpreterBridge() const {
-  CREATE_TRAMPOLINE(PORTABLE, kPortableAbi, pPortableToInterpreterBridge)
-}
-
 const std::vector<uint8_t>* CompilerDriver::CreateQuickGenericJniTrampoline() const {
   CREATE_TRAMPOLINE(QUICK, kQuickAbi, pQuickGenericJniTrampoline)
 }
@@ -497,6 +480,7 @@
                                 TimingLogger* timings) {
   DCHECK(!Runtime::Current()->IsStarted());
   std::unique_ptr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
+  VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
   PreCompile(class_loader, dex_files, thread_pool.get(), timings);
   Compile(class_loader, dex_files, thread_pool.get(), timings);
   if (dump_stats_) {
@@ -574,7 +558,7 @@
                                                                class_def);
   }
   CompileMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, jclass_loader,
-                *dex_file, dex_to_dex_compilation_level);
+                *dex_file, dex_to_dex_compilation_level, true);
 
   self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
 
@@ -593,20 +577,25 @@
 void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                                 ThreadPool* thread_pool, TimingLogger* timings) {
   LoadImageClasses(timings);
+  VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
 
   Resolve(class_loader, dex_files, thread_pool, timings);
+  VLOG(compiler) << "Resolve: " << GetMemoryUsageString(false);
 
   if (!compiler_options_->IsVerificationEnabled()) {
-    LOG(INFO) << "Verify none mode specified, skipping verification.";
+    VLOG(compiler) << "Verify none mode specified, skipping verification.";
     SetVerified(class_loader, dex_files, thread_pool, timings);
     return;
   }
 
   Verify(class_loader, dex_files, thread_pool, timings);
+  VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
 
   InitializeClasses(class_loader, dex_files, thread_pool, timings);
+  VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
 
   UpdateImageClasses(timings);
+  VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
 }
 
 bool CompilerDriver::IsImageClass(const char* descriptor) const {
@@ -617,17 +606,28 @@
   }
 }
 
-static void ResolveExceptionsForMethod(MutableMethodHelper* mh,
+bool CompilerDriver::IsClassToCompile(const char* descriptor) const {
+  if (!IsImage()) {
+    return true;
+  } else {
+    if (classes_to_compile_ == nullptr) {
+      return true;
+    }
+    return classes_to_compile_->find(descriptor) != classes_to_compile_->end();
+  }
+}
+
+static void ResolveExceptionsForMethod(MutableHandle<mirror::ArtMethod> method_handle,
     std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = mh->GetMethod()->GetCodeItem();
+  const DexFile::CodeItem* code_item = method_handle->GetCodeItem();
   if (code_item == nullptr) {
     return;  // native or abstract method
   }
   if (code_item->tries_size_ == 0) {
     return;  // nothing to process
   }
-  const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+  const uint8_t* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
   size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
   for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
     int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
@@ -640,10 +640,10 @@
       uint16_t encoded_catch_handler_handlers_type_idx =
           DecodeUnsignedLeb128(&encoded_catch_handler_list);
       // Add to set of types to resolve if not already in the dex cache resolved types
-      if (!mh->GetMethod()->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
+      if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
         exceptions_to_resolve.insert(
             std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
-                                                mh->GetMethod()->GetDexFile()));
+                                                method_handle->GetDexFile()));
       }
       // ignore address associated with catch handler
       DecodeUnsignedLeb128(&encoded_catch_handler_list);
@@ -660,14 +660,14 @@
   std::set<std::pair<uint16_t, const DexFile*>>* exceptions_to_resolve =
       reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*>>*>(arg);
   StackHandleScope<1> hs(Thread::Current());
-  MutableMethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableHandle<mirror::ArtMethod> method_handle(hs.NewHandle<mirror::ArtMethod>(nullptr));
   for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
-    mh.ChangeMethod(c->GetVirtualMethod(i));
-    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+    method_handle.Assign(c->GetVirtualMethod(i));
+    ResolveExceptionsForMethod(method_handle, *exceptions_to_resolve);
   }
   for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
-    mh.ChangeMethod(c->GetDirectMethod(i));
-    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+    method_handle.Assign(c->GetDirectMethod(i));
+    ResolveExceptionsForMethod(method_handle, *exceptions_to_resolve);
   }
   return true;
 }
@@ -722,9 +722,9 @@
     for (const std::pair<uint16_t, const DexFile*>& exception_type : unresolved_exception_types) {
       uint16_t exception_type_idx = exception_type.first;
       const DexFile* dex_file = exception_type.second;
-      StackHandleScope<2> hs(self);
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(*dex_file)));
-      Handle<mirror::Class> klass(hs.NewHandle(
+      StackHandleScope<2> hs2(self);
+      Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->FindDexCache(*dex_file)));
+      Handle<mirror::Class> klass(hs2.NewHandle(
           class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
                                     NullHandle<mirror::ClassLoader>())));
       if (klass.Get() == nullptr) {
@@ -761,35 +761,155 @@
     }
     VLOG(compiler) << "Adding " << descriptor << " to image classes";
     for (size_t i = 0; i < klass->NumDirectInterfaces(); ++i) {
-      StackHandleScope<1> hs(self);
-      MaybeAddToImageClasses(hs.NewHandle(mirror::Class::GetDirectInterface(self, klass, i)),
+      StackHandleScope<1> hs2(self);
+      MaybeAddToImageClasses(hs2.NewHandle(mirror::Class::GetDirectInterface(self, klass, i)),
                              image_classes);
     }
     if (klass->IsArrayClass()) {
-      StackHandleScope<1> hs(self);
-      MaybeAddToImageClasses(hs.NewHandle(klass->GetComponentType()), image_classes);
+      StackHandleScope<1> hs2(self);
+      MaybeAddToImageClasses(hs2.NewHandle(klass->GetComponentType()), image_classes);
     }
     klass.Assign(klass->GetSuperClass());
   }
 }
 
-void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
-  DCHECK(object != nullptr);
-  DCHECK(arg != nullptr);
-  CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
-  StackHandleScope<1> hs(Thread::Current());
-  MaybeAddToImageClasses(hs.NewHandle(object->GetClass()), compiler_driver->image_classes_.get());
-}
+// Keeps all the data for the update together. Also doubles as the reference visitor.
+// Note: we can use object pointers because we suspend all threads.
+class ClinitImageUpdate {
+ public:
+  static ClinitImageUpdate* Create(std::set<std::string>* image_class_descriptors, Thread* self,
+                                   ClassLinker* linker, std::string* error_msg) {
+    std::unique_ptr<ClinitImageUpdate> res(new ClinitImageUpdate(image_class_descriptors, self,
+                                                                 linker));
+    if (res->art_method_class_ == nullptr) {
+      *error_msg = "Could not find ArtMethod class.";
+      return nullptr;
+    } else if (res->dex_cache_class_ == nullptr) {
+      *error_msg = "Could not find DexCache class.";
+      return nullptr;
+    }
+
+    return res.release();
+  }
+
+  ~ClinitImageUpdate() {
+    // Allow others to suspend again.
+    self_->EndAssertNoThreadSuspension(old_cause_);
+  }
+
+  // Visitor for VisitReferences.
+  void operator()(mirror::Object* object, MemberOffset field_offset, bool /* is_static */) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::Object* ref = object->GetFieldObject<mirror::Object>(field_offset);
+    if (ref != nullptr) {
+      VisitClinitClassesObject(ref);
+    }
+  }
+
+  // java.lang.Reference visitor for VisitReferences.
+  void operator()(mirror::Class* /* klass */, mirror::Reference* /* ref */) const {
+  }
+
+  void Walk() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // Use the initial classes as roots for a search.
+    for (mirror::Class* klass_root : image_classes_) {
+      VisitClinitClassesObject(klass_root);
+    }
+  }
+
+ private:
+  ClinitImageUpdate(std::set<std::string>* image_class_descriptors, Thread* self,
+                    ClassLinker* linker)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+      image_class_descriptors_(image_class_descriptors), self_(self) {
+    CHECK(linker != nullptr);
+    CHECK(image_class_descriptors != nullptr);
+
+    // Make sure nobody interferes with us.
+    old_cause_ = self->StartAssertNoThreadSuspension("Boot image closure");
+
+    // Find the interesting classes.
+    art_method_class_ = linker->LookupClass(self, "Ljava/lang/reflect/ArtMethod;",
+        ComputeModifiedUtf8Hash("Ljava/lang/reflect/ArtMethod;"), nullptr);
+    dex_cache_class_ = linker->LookupClass(self, "Ljava/lang/DexCache;",
+        ComputeModifiedUtf8Hash("Ljava/lang/DexCache;"), nullptr);
+
+    // Find all the already-marked classes.
+    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    linker->VisitClasses(FindImageClasses, this);
+  }
+
+  static bool FindImageClasses(mirror::Class* klass, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ClinitImageUpdate* data = reinterpret_cast<ClinitImageUpdate*>(arg);
+    std::string temp;
+    const char* name = klass->GetDescriptor(&temp);
+    if (data->image_class_descriptors_->find(name) != data->image_class_descriptors_->end()) {
+      data->image_classes_.push_back(klass);
+    }
+
+    return true;
+  }
+
+  void VisitClinitClassesObject(mirror::Object* object) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(object != nullptr);
+    if (marked_objects_.find(object) != marked_objects_.end()) {
+      // Already processed.
+      return;
+    }
+
+    // Mark it.
+    marked_objects_.insert(object);
+
+    if (object->IsClass()) {
+      // If it is a class, add it.
+      StackHandleScope<1> hs(self_);
+      MaybeAddToImageClasses(hs.NewHandle(object->AsClass()), image_class_descriptors_);
+    } else {
+      // Else visit the object's class.
+      VisitClinitClassesObject(object->GetClass());
+    }
+
+    // If it is not a dex cache or an ArtMethod, visit all references.
+    mirror::Class* klass = object->GetClass();
+    if (klass != art_method_class_ && klass != dex_cache_class_) {
+      object->VisitReferences<false /* visit class */>(*this, *this);
+    }
+  }
+
+  mutable std::unordered_set<mirror::Object*> marked_objects_;
+  std::set<std::string>* const image_class_descriptors_;
+  std::vector<mirror::Class*> image_classes_;
+  const mirror::Class* art_method_class_;
+  const mirror::Class* dex_cache_class_;
+  Thread* const self_;
+  const char* old_cause_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClinitImageUpdate);
+};
 
 void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
   if (IsImage()) {
     TimingLogger::ScopedTiming t("UpdateImageClasses", timings);
-    // Update image_classes_ with classes for objects created by <clinit> methods.
-    gc::Heap* heap = Runtime::Current()->GetHeap();
-    // TODO: Image spaces only?
-    ScopedObjectAccess soa(Thread::Current());
-    WriterMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
-    heap->VisitObjects(FindClinitImageClassesCallback, this);
+
+    Runtime* current = Runtime::Current();
+
+    // Suspend all threads.
+    current->GetThreadList()->SuspendAll();
+
+    std::string error_msg;
+    std::unique_ptr<ClinitImageUpdate> update(ClinitImageUpdate::Create(image_classes_.get(),
+                                                                        Thread::Current(),
+                                                                        current->GetClassLinker(),
+                                                                        &error_msg));
+    CHECK(update.get() != nullptr) << error_msg;  // TODO: Soft failure?
+
+    // Do the marking.
+    update->Walk();
+
+    // Resume threads.
+    current->GetThreadList()->ResumeAll();
   }
 }
 
@@ -920,6 +1040,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();
@@ -1071,7 +1195,8 @@
 bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
                                             bool is_put, MemberOffset* field_offset,
                                             uint32_t* storage_index, bool* is_referrers_class,
-                                            bool* is_volatile, bool* is_initialized) {
+                                            bool* is_volatile, bool* is_initialized,
+                                            Primitive::Type* type) {
   ScopedObjectAccess soa(Thread::Current());
   // Try to resolve the field and compiling method's class.
   mirror::ArtField* resolved_field;
@@ -1094,17 +1219,25 @@
   if (resolved_field != nullptr && referrer_class != nullptr) {
     *is_volatile = IsFieldVolatile(resolved_field);
     std::pair<bool, bool> fast_path = IsFastStaticField(
-        dex_cache, referrer_class, resolved_field, field_idx, field_offset,
-        storage_index, is_referrers_class, is_initialized);
+        dex_cache, referrer_class, resolved_field, field_idx, storage_index);
     result = is_put ? fast_path.second : fast_path.first;
   }
-  if (!result) {
+  if (result) {
+    *field_offset = GetFieldOffset(resolved_field);
+    *is_referrers_class = IsStaticFieldInReferrerClass(referrer_class, resolved_field);
+    // *is_referrers_class == true implies no worrying about class initialization.
+    *is_initialized = (*is_referrers_class) ||
+        (IsStaticFieldsClassInitialized(referrer_class, resolved_field) &&
+         CanAssumeTypeIsPresentInDexCache(*mUnit->GetDexFile(), *storage_index));
+    *type = resolved_field->GetTypeAsPrimitiveType();
+  } else {
     // Conservative defaults.
     *is_volatile = true;
     *field_offset = MemberOffset(static_cast<size_t>(-1));
     *storage_index = -1;
     *is_referrers_class = false;
     *is_initialized = false;
+    *type = Primitive::kPrimVoid;
   }
   ProcessedStaticField(result, *is_referrers_class);
   return result;
@@ -1112,7 +1245,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,23 +1257,16 @@
   // 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 ||
                                   GetCompilerOptions().GetIncludePatchInformation());
-  if (compiler_->IsPortable()) {
-    if (sharp_type != kStatic && sharp_type != kDirect) {
-      return;
-    }
-    use_dex_cache = true;
-  } else {
-    if (sharp_type != kStatic && sharp_type != kDirect) {
-      return;
-    }
-    // TODO: support patching on all architectures.
-    use_dex_cache = force_relocations && !support_boot_image_fixup_;
+  if (sharp_type != kStatic && sharp_type != kDirect) {
+    return;
   }
+  // TODO: support patching on all architectures.
+  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) {
     if (!method_code_in_boot) {
@@ -1172,11 +1298,10 @@
     target_method->dex_method_index = method->GetDexMethodIndex();
   } else {
     if (no_guarantee_of_dex_cache_entry) {
-      StackHandleScope<1> hs(Thread::Current());
-      MethodHelper mh(hs.NewHandle(method));
       // See if the method is also declared in this dex cache.
-      uint32_t dex_method_idx = mh.FindDexMethodIndexInOtherDexFile(
-          *target_method->dex_file, target_method->dex_method_index);
+      uint32_t dex_method_idx =
+          method->FindDexMethodIndexInOtherDexFile(*target_method->dex_file,
+                                                   target_method->dex_method_index);
       if (dex_method_idx != DexFile::kDexNoIndex) {
         target_method->dex_method_index = dex_method_idx;
       } else {
@@ -1252,8 +1377,7 @@
   if (resolved_method != nullptr) {
     *vtable_idx = GetResolvedMethodVTableIndex(resolved_method, orig_invoke_type);
 
-    if (enable_devirtualization) {
-      DCHECK(mUnit->GetVerifiedMethod() != nullptr);
+    if (enable_devirtualization && mUnit->GetVerifiedMethod() != nullptr) {
       const MethodReference* devirt_target = mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
 
       stats_flags = IsFastInvoke(
@@ -1505,7 +1629,7 @@
   // Note the class_data pointer advances through the headers,
   // static fields, instance fields, direct methods, and virtual
   // methods.
-  const byte* class_data = dex_file.GetClassData(class_def);
+  const uint8_t* class_data = dex_file.GetClassData(class_def);
   if (class_data == nullptr) {
     // Empty class such as a marker interface.
     requires_constructor_barrier = false;
@@ -1798,6 +1922,12 @@
               mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
               VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
                   << exception->Dump();
+              std::ostream* file_log = manager->GetCompiler()->
+                  GetCompilerOptions().GetInitFailureOutput();
+              if (file_log != nullptr) {
+                *file_log << descriptor << "\n";
+                *file_log << exception->Dump() << "\n";
+              }
               soa.Self()->ClearException();
               transaction.Abort();
               CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
@@ -1853,6 +1983,7 @@
     CHECK(dex_file != nullptr);
     CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
+  VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
 }
 
 void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) {
@@ -1882,7 +2013,7 @@
   if (manager->GetCompiler()->verification_results_->IsClassRejected(ref)) {
     return;
   }
-  const byte* class_data = dex_file.GetClassData(class_def);
+  const uint8_t* class_data = dex_file.GetClassData(class_def);
   if (class_data == nullptr) {
     // empty class, probably a marker interface
     return;
@@ -1907,6 +2038,10 @@
     it.Next();
   }
   CompilerDriver* driver = manager->GetCompiler();
+
+  bool compilation_enabled = driver->IsClassToCompile(
+      dex_file.StringByTypeIdx(class_def.class_idx_));
+
   // Compile direct methods
   int64_t previous_direct_method_idx = -1;
   while (it.HasNextDirectMethod()) {
@@ -1920,7 +2055,8 @@
     previous_direct_method_idx = method_idx;
     driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                           it.GetMethodInvokeType(class_def), class_def_index,
-                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
+                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
+                          compilation_enabled);
     it.Next();
   }
   // Compile virtual methods
@@ -1936,7 +2072,8 @@
     previous_virtual_method_idx = method_idx;
     driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                           it.GetMethodInvokeType(class_def), class_def_index,
-                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
+                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
+                          compilation_enabled);
     it.Next();
   }
   DCHECK(!it.HasNext());
@@ -1951,27 +2088,49 @@
   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 kMips:
+    case kMips64:
+    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,
                                    const DexFile& dex_file,
-                                   DexToDexCompilationLevel dex_to_dex_compilation_level) {
+                                   DexToDexCompilationLevel dex_to_dex_compilation_level,
+                                   bool compilation_enabled) {
   CompiledMethod* compiled_method = nullptr;
   uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
+  MethodReference method_ref(&dex_file, method_idx);
 
   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);
+    bool has_verified_method = verification_results_->GetVerifiedMethod(method_ref) != nullptr;
+    bool compile = compilation_enabled &&
+                   // Basic checks, e.g., not <clinit>.
+                   verification_results_->IsCandidateForCompilation(method_ref, access_flags) &&
+                   // Did not fail to create VerifiedMethod metadata.
+                   has_verified_method;
     if (compile) {
       // NOTE: if compiler declines to compile this method, it will return nullptr.
       compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
@@ -1979,10 +2138,12 @@
     }
     if (compiled_method == nullptr && dex_to_dex_compilation_level != kDontDexToDexCompile) {
       // TODO: add a command-line option to disable DEX-to-DEX compilation ?
+      // Do not optimize if a VerifiedMethod is missing. SafeCast elision, for example, relies on
+      // it.
       (*dex_to_dex_compiler_)(*this, code_item, access_flags,
                               invoke_type, class_def_idx,
                               method_idx, class_loader, dex_file,
-                              dex_to_dex_compilation_level);
+                              has_verified_method ? dex_to_dex_compilation_level : kRequired);
     }
   }
   if (kTimeCompileMethod) {
@@ -2002,16 +2163,22 @@
         ++non_relative_linker_patch_count;
       }
     }
-    MethodReference ref(&dex_file, method_idx);
-    DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
+    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);
+
+    DCHECK(GetCompiledMethod(method_ref) == nullptr) << PrettyMethod(method_idx, dex_file);
     {
       MutexLock mu(self, compiled_methods_lock_);
-      compiled_methods_.Put(ref, compiled_method);
+      compiled_methods_.Put(method_ref, compiled_method);
       non_relative_linker_patch_count_ += non_relative_linker_patch_count;
     }
-    DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(method_ref) != nullptr) << PrettyMethod(method_idx, dex_file);
   }
 
+  // Done compiling, delete the verified method to reduce native memory usage.
+  verification_results_->RemoveVerifiedMethod(method_ref);
+
   if (self->IsExceptionPending()) {
     ScopedObjectAccess soa(self);
     LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
@@ -2161,4 +2328,31 @@
   }
   return !compile;
 }
+
+std::string CompilerDriver::GetMemoryUsageString(bool extended) const {
+  std::ostringstream oss;
+  const ArenaPool* arena_pool = GetArenaPool();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  oss << "arena alloc=" << PrettySize(arena_pool->GetBytesAllocated());
+  oss << " java alloc=" << PrettySize(heap->GetBytesAllocated());
+#ifdef HAVE_MALLOC_H
+  struct mallinfo info = mallinfo();
+  const size_t allocated_space = static_cast<size_t>(info.uordblks);
+  const size_t free_space = static_cast<size_t>(info.fordblks);
+  oss << " native alloc=" << PrettySize(allocated_space) << " free="
+      << PrettySize(free_space);
+#endif
+  if (swap_space_.get() != nullptr) {
+    oss << " swap=" << PrettySize(swap_space_->GetSize());
+  }
+  if (extended) {
+    oss << "\nCode dedupe: " << dedupe_code_.DumpStats();
+    oss << "\nMapping table dedupe: " << dedupe_mapping_table_.DumpStats();
+    oss << "\nVmap table dedupe: " << dedupe_vmap_table_.DumpStats();
+    oss << "\nGC map dedupe: " << dedupe_gc_map_.DumpStats();
+    oss << "\nCFI info dedupe: " << dedupe_cfi_info_.DumpStats();
+  }
+  return oss.str();
+}
+
 }  // namespace art
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c445683..a86043c 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/mutex.h"
 #include "base/timing_logger.h"
 #include "class_reference.h"
@@ -28,7 +29,6 @@
 #include "compiler.h"
 #include "dex_file.h"
 #include "driver/compiler_options.h"
-#include "instruction_set.h"
 #include "invoke_type.h"
 #include "method_reference.h"
 #include "mirror/class.h"  // For mirror::Class::Status.
@@ -39,6 +39,9 @@
 #include "thread_pool.h"
 #include "utils/arena_allocator.h"
 #include "utils/dedupe_set.h"
+#include "utils/swap_space.h"
+#include "utils.h"
+#include "dex/verified_method.h"
 
 namespace art {
 
@@ -51,6 +54,7 @@
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
 struct InlineIGetIPutData;
+class InstructionSetFeatures;
 class OatWriter;
 class ParallelCompilationManager;
 class ScopedObjectAccess;
@@ -64,8 +68,6 @@
   kInterpreterAbi,
   // ABI of calls to a method's native code, only used for native methods.
   kJniAbi,
-  // ABI of calls to a method's portable code entry point.
-  kPortableAbi,
   // ABI of calls to a method's quick code entry point.
   kQuickAbi
 };
@@ -75,6 +77,9 @@
   kRequired,              // Dex-to-dex compilation required for correctness.
   kOptimize               // Perform required transformation and peep-hole optimizations.
 };
+std::ostream& operator<<(std::ostream& os, const DexToDexCompilationLevel& rhs);
+
+static constexpr bool kUseMurmur3Hash = true;
 
 class CompilerDriver {
  public:
@@ -88,10 +93,13 @@
                           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,
+                          std::set<std::string>* compiled_classes,
                           size_t thread_count, bool dump_stats, bool dump_passes,
-                          CumulativeLogger* timer, std::string profile_file = "");
+                          const std::string& dump_cfg_file_name,
+                          CumulativeLogger* timer, int swap_fd,
+                          const std::string& profile_file);
 
   ~CompilerDriver();
 
@@ -115,7 +123,7 @@
     return instruction_set_;
   }
 
-  InstructionSetFeatures GetInstructionSetFeatures() const {
+  const InstructionSetFeatures* GetInstructionSetFeatures() const {
     return instruction_set_features_;
   }
 
@@ -140,8 +148,6 @@
     return image_classes_.get();
   }
 
-  CompilerTls* GetTls();
-
   // Generate the trampolines that are invoked by unresolved direct methods.
   const std::vector<uint8_t>* CreateInterpreterToInterpreterBridge() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -149,12 +155,6 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const std::vector<uint8_t>* CreateJniDlsymLookup() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const std::vector<uint8_t>* CreatePortableImtConflictTrampoline() const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const std::vector<uint8_t>* CreatePortableResolutionTrampoline() const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const std::vector<uint8_t>* CreatePortableToInterpreterBridge() const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const std::vector<uint8_t>* CreateQuickGenericJniTrampoline() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const std::vector<uint8_t>* CreateQuickImtConflictTrampoline() const
@@ -233,6 +233,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsFieldVolatile(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  MemberOffset GetFieldOffset(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset.
   std::pair<bool, bool> IsFastInstanceField(
@@ -240,13 +241,20 @@
       mirror::ArtField* resolved_field, uint16_t field_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Can we fast-path an SGET/SPUT access to a static field? If yes, compute the field offset,
-  // the type index of the declaring class in the referrer's dex file and whether the declaring
-  // class is the referrer's class or at least can be assumed to be initialized.
+  // Can we fast-path an SGET/SPUT access to a static field? If yes, compute the type index
+  // of the declaring class in the referrer's dex file.
   std::pair<bool, bool> IsFastStaticField(
       mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-      mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset,
-      uint32_t* storage_index, bool* is_referrers_class, bool* is_initialized)
+      mirror::ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Is static field's in referrer's class?
+  bool IsStaticFieldInReferrerClass(mirror::Class* referrer_class, mirror::ArtField* resolved_field)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Is static field's class initialized?
+  bool IsStaticFieldsClassInitialized(mirror::Class* referrer_class,
+                                      mirror::ArtField* resolved_field)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a method. Returns nullptr on failure, including incompatible class change.
@@ -277,8 +285,10 @@
       uintptr_t* direct_code, uintptr_t* direct_method)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Does invokation of the resolved method need class initialization?
-  bool NeedsClassInitialization(mirror::Class* referrer_class, mirror::ArtMethod* resolved_method)
+  // Is method's class initialized for an invoke?
+  // For static invokes to determine whether we need to consider potential call to <clinit>().
+  // For non-static invokes, assuming a non-null reference, the class is always initialized.
+  bool IsMethodsClassInitialized(mirror::Class* referrer_class, mirror::ArtMethod* resolved_method)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void ProcessedInstanceField(bool resolved);
@@ -301,7 +311,8 @@
   // field is within the referrer (which can avoid checking class initialization).
   bool ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
                               MemberOffset* field_offset, uint32_t* storage_index,
-                              bool* is_referrers_class, bool* is_volatile, bool* is_initialized)
+                              bool* is_referrers_class, bool* is_volatile, bool* is_initialized,
+                              Primitive::Type* type)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable
@@ -326,6 +337,12 @@
   ArenaPool* GetArenaPool() {
     return &arena_pool_;
   }
+  const ArenaPool* GetArenaPool() const {
+    return &arena_pool_;
+  }
+  SwapAllocator<void>& GetSwapSpaceAllocator() {
+    return *swap_space_allocator_.get();
+  }
 
   bool WriteElf(const std::string& android_root,
                 bool is_host,
@@ -355,6 +372,10 @@
     return dump_passes_;
   }
 
+  const std::string& GetDumpCfgFileName() const {
+    return dump_cfg_file_name_;
+  }
+
   CumulativeLogger* GetTimingsLogger() const {
     return timings_logger_;
   }
@@ -362,22 +383,25 @@
   // Checks if class specified by type_idx is one of the image_classes_
   bool IsImageClass(const char* descriptor) const;
 
+  // Checks if the provided class should be compiled, i.e., is in classes_to_compile_.
+  bool IsClassToCompile(const char* descriptor) const;
+
   void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
       LOCKS_EXCLUDED(compiled_classes_lock_);
 
-  std::vector<uint8_t>* DeduplicateCode(const std::vector<uint8_t>& code);
-  SrcMap* DeduplicateSrcMappingTable(const SrcMap& src_map);
-  std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
-  std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
-  std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
-  std::vector<uint8_t>* DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info);
-
-  ProfileFile profile_file_;
-  bool profile_present_;
+  SwapVector<uint8_t>* DeduplicateCode(const ArrayRef<const uint8_t>& code);
+  SwapSrcMap* DeduplicateSrcMappingTable(const ArrayRef<SrcMapElem>& src_map);
+  SwapVector<uint8_t>* DeduplicateMappingTable(const ArrayRef<const uint8_t>& code);
+  SwapVector<uint8_t>* DeduplicateVMapTable(const ArrayRef<const uint8_t>& code);
+  SwapVector<uint8_t>* DeduplicateGCMap(const ArrayRef<const uint8_t>& code);
+  SwapVector<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info);
 
   // Should the compiler run on this method given profile information?
   bool SkipCompilation(const std::string& method_name);
 
+  // Get memory usage during compilation.
+  std::string GetMemoryUsageString(bool extended) const;
+
  private:
   // These flags are internal to CompilerDriver for collecting INVOKE resolution statistics.
   // The only external contract is that unresolved method has flags 0 and resolved non-0.
@@ -400,11 +424,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_);
@@ -462,12 +487,21 @@
   void 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, const DexFile& dex_file,
-                     DexToDexCompilationLevel dex_to_dex_compilation_level)
+                     DexToDexCompilationLevel dex_to_dex_compilation_level,
+                     bool compilation_enabled)
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
   static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  // Swap pool and allocator used for native allocations. May be file-backed. Needs to be first
+  // as other fields rely on this.
+  std::unique_ptr<SwapSpace> swap_space_;
+  std::unique_ptr<SwapAllocator<void> > swap_space_allocator_;
+
+  ProfileFile profile_file_;
+  bool profile_present_;
+
   const CompilerOptions* const compiler_options_;
   VerificationResults* const verification_results_;
   DexFileToMethodInlinerMap* const method_inliner_map_;
@@ -475,7 +509,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;
@@ -501,22 +535,25 @@
   // included in the image.
   std::unique_ptr<std::set<std::string>> image_classes_;
 
+  // If image_ is true, specifies the classes that will be compiled in
+  // the image. Note if classes_to_compile_ is nullptr, all classes are
+  // included in the image.
+  std::unique_ptr<std::set<std::string>> classes_to_compile_;
+
   size_t thread_count_;
-  uint64_t start_ns_;
 
   class AOTCompilationStats;
   std::unique_ptr<AOTCompilationStats> stats_;
 
   bool dump_stats_;
   const bool dump_passes_;
+  const std::string& dump_cfg_file_name_;
 
   CumulativeLogger* const timings_logger_;
 
   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,
@@ -527,62 +564,98 @@
 
   void* compiler_context_;
 
-  pthread_key_t tls_key_;
-
   // 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.
-  template <typename ByteArray>
+  template <typename ContentType>
   class DedupeHashFunc {
    public:
-    size_t operator()(const ByteArray& array) const {
-      // For small arrays compute a hash using every byte.
-      static const size_t kSmallArrayThreshold = 16;
-      size_t hash = 0x811c9dc5;
-      if (array.size() <= kSmallArrayThreshold) {
-        for (auto b : array) {
-          hash = (hash * 16777619) ^ static_cast<uint8_t>(b);
+    size_t operator()(const ArrayRef<ContentType>& array) const {
+      const uint8_t* data = reinterpret_cast<const uint8_t*>(array.data());
+      static_assert(IsPowerOfTwo(sizeof(ContentType)),
+          "ContentType is not power of two, don't know whether array layout is as assumed");
+      uint32_t len = sizeof(ContentType) * array.size();
+      if (kUseMurmur3Hash) {
+        static constexpr uint32_t c1 = 0xcc9e2d51;
+        static constexpr uint32_t c2 = 0x1b873593;
+        static constexpr uint32_t r1 = 15;
+        static constexpr uint32_t r2 = 13;
+        static constexpr uint32_t m = 5;
+        static constexpr uint32_t n = 0xe6546b64;
+
+        uint32_t hash = 0;
+
+        const int nblocks = len / 4;
+        typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
+        const unaligned_uint32_t *blocks = reinterpret_cast<const uint32_t*>(data);
+        int i;
+        for (i = 0; i < nblocks; i++) {
+          uint32_t k = blocks[i];
+          k *= c1;
+          k = (k << r1) | (k >> (32 - r1));
+          k *= c2;
+
+          hash ^= k;
+          hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
         }
+
+        const uint8_t *tail = reinterpret_cast<const uint8_t*>(data + nblocks * 4);
+        uint32_t k1 = 0;
+
+        switch (len & 3) {
+          case 3:
+            k1 ^= tail[2] << 16;
+            FALLTHROUGH_INTENDED;
+          case 2:
+            k1 ^= tail[1] << 8;
+            FALLTHROUGH_INTENDED;
+          case 1:
+            k1 ^= tail[0];
+
+            k1 *= c1;
+            k1 = (k1 << r1) | (k1 >> (32 - r1));
+            k1 *= c2;
+            hash ^= k1;
+        }
+
+        hash ^= len;
+        hash ^= (hash >> 16);
+        hash *= 0x85ebca6b;
+        hash ^= (hash >> 13);
+        hash *= 0xc2b2ae35;
+        hash ^= (hash >> 16);
+
+        return hash;
       } else {
-        // For larger arrays use the 2 bytes at 6 bytes (the location of a push registers
-        // instruction field for quick generated code on ARM) and then select a number of other
-        // values at random.
-        static const size_t kRandomHashCount = 16;
-        for (size_t i = 0; i < 2; ++i) {
-          uint8_t b = static_cast<uint8_t>(array[i + 6]);
-          hash = (hash * 16777619) ^ b;
+        size_t hash = 0x811c9dc5;
+        for (uint32_t i = 0; i < len; ++i) {
+          hash = (hash * 16777619) ^ data[i];
         }
-        for (size_t i = 2; i < kRandomHashCount; ++i) {
-          size_t r = i * 1103515245 + 12345;
-          uint8_t b = static_cast<uint8_t>(array[r % array.size()]);
-          hash = (hash * 16777619) ^ b;
-        }
+        hash += hash << 13;
+        hash ^= hash >> 7;
+        hash += hash << 3;
+        hash ^= hash >> 17;
+        hash += hash << 5;
+        return hash;
       }
-      hash += hash << 13;
-      hash ^= hash >> 7;
-      hash += hash << 3;
-      hash ^= hash >> 17;
-      hash += hash << 5;
-      return hash;
     }
   };
 
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_code_;
-  DedupeSet<SrcMap, size_t, DedupeHashFunc<SrcMap>, 4> dedupe_src_mapping_table_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_mapping_table_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_vmap_table_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_gc_map_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_cfi_info_;
+  DedupeSet<ArrayRef<const uint8_t>,
+            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_code_;
+  DedupeSet<ArrayRef<SrcMapElem>,
+            SwapSrcMap, size_t, DedupeHashFunc<SrcMapElem>, 4> dedupe_src_mapping_table_;
+  DedupeSet<ArrayRef<const uint8_t>,
+            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_mapping_table_;
+  DedupeSet<ArrayRef<const uint8_t>,
+            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_vmap_table_;
+  DedupeSet<ArrayRef<const uint8_t>,
+            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_gc_map_;
+  DedupeSet<ArrayRef<const uint8_t>,
+            SwapVector<uint8_t>, size_t, DedupeHashFunc<const uint8_t>, 4> dedupe_cfi_info_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 9ae9bd4..a02e25e 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -86,11 +86,11 @@
           hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
       mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader);
       CHECK(c != NULL);
-      for (size_t i = 0; i < c->NumDirectMethods(); i++) {
-        MakeExecutable(c->GetDirectMethod(i));
+      for (size_t j = 0; j < c->NumDirectMethods(); j++) {
+        MakeExecutable(c->GetDirectMethod(j));
       }
-      for (size_t i = 0; i < c->NumVirtualMethods(); i++) {
-        MakeExecutable(c->GetVirtualMethod(i));
+      for (size_t j = 0; j < c->NumVirtualMethods(); j++) {
+        MakeExecutable(c->GetVirtualMethod(j));
       }
     }
   }
@@ -106,40 +106,37 @@
 
   // All libcore references should resolve
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* dex = java_lang_dex_file_;
-  mirror::DexCache* dex_cache = class_linker_->FindDexCache(*dex);
-  EXPECT_EQ(dex->NumStringIds(), dex_cache->NumStrings());
+  ASSERT_TRUE(java_lang_dex_file_ != NULL);
+  const DexFile& dex = *java_lang_dex_file_;
+  mirror::DexCache* dex_cache = class_linker_->FindDexCache(dex);
+  EXPECT_EQ(dex.NumStringIds(), dex_cache->NumStrings());
   for (size_t i = 0; i < dex_cache->NumStrings(); i++) {
     const mirror::String* string = dex_cache->GetResolvedString(i);
     EXPECT_TRUE(string != NULL) << "string_idx=" << i;
   }
-  EXPECT_EQ(dex->NumTypeIds(), dex_cache->NumResolvedTypes());
+  EXPECT_EQ(dex.NumTypeIds(), dex_cache->NumResolvedTypes());
   for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
     mirror::Class* type = dex_cache->GetResolvedType(i);
     EXPECT_TRUE(type != NULL) << "type_idx=" << i
-                              << " " << dex->GetTypeDescriptor(dex->GetTypeId(i));
+                              << " " << dex.GetTypeDescriptor(dex.GetTypeId(i));
   }
-  EXPECT_EQ(dex->NumMethodIds(), dex_cache->NumResolvedMethods());
+  EXPECT_EQ(dex.NumMethodIds(), dex_cache->NumResolvedMethods());
   for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
     mirror::ArtMethod* method = dex_cache->GetResolvedMethod(i);
     EXPECT_TRUE(method != NULL) << "method_idx=" << i
-                                << " " << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i))
-                                << " " << dex->GetMethodName(dex->GetMethodId(i));
+                                << " " << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i))
+                                << " " << dex.GetMethodName(dex.GetMethodId(i));
     EXPECT_TRUE(method->GetEntryPointFromQuickCompiledCode() != NULL) << "method_idx=" << i
                                            << " "
-                                           << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i))
-                                           << " " << dex->GetMethodName(dex->GetMethodId(i));
-    EXPECT_TRUE(method->GetEntryPointFromPortableCompiledCode() != NULL) << "method_idx=" << i
-                                           << " "
-                                           << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i))
-                                           << " " << dex->GetMethodName(dex->GetMethodId(i));
+                                           << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i))
+                                           << " " << dex.GetMethodName(dex.GetMethodId(i));
   }
-  EXPECT_EQ(dex->NumFieldIds(), dex_cache->NumResolvedFields());
+  EXPECT_EQ(dex.NumFieldIds(), dex_cache->NumResolvedFields());
   for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
     mirror::ArtField* field = dex_cache->GetResolvedField(i);
     EXPECT_TRUE(field != NULL) << "field_idx=" << i
-                               << " " << dex->GetFieldDeclaringClassDescriptor(dex->GetFieldId(i))
-                               << " " << dex->GetFieldName(dex->GetFieldId(i));
+                               << " " << dex.GetFieldDeclaringClassDescriptor(dex.GetFieldId(i))
+                               << " " << dex.GetFieldName(dex.GetFieldId(i));
   }
 
   // TODO check Class::IsVerified for all classes
@@ -148,7 +145,6 @@
 }
 
 TEST_F(CompilerDriverTest, AbstractMethodErrorStub) {
-  TEST_DISABLED_FOR_PORTABLE();
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
   jobject class_loader;
   {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index eb3de97..97699e5 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -17,9 +17,16 @@
 #ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
 #define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
 
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "globals.h"
+
 namespace art {
 
-class CompilerOptions {
+class CompilerOptions FINAL {
  public:
   enum CompilerFilter {
     kVerifyNone,          // Skip verification and compile nothing except JNI stubs.
@@ -28,7 +35,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 +66,11 @@
     include_debug_symbols_(kDefaultIncludeDebugSymbols),
     implicit_null_checks_(false),
     implicit_so_checks_(false),
-    implicit_suspend_checks_(false)
-#ifdef ART_SEA_IR_MODE
-    , sea_ir_mode_(false)
-#endif
-    {}
+    implicit_suspend_checks_(false),
+    compile_pic_(false),
+    verbose_methods_(nullptr),
+    init_failure_output_(nullptr) {
+  }
 
   CompilerOptions(CompilerFilter compiler_filter,
                   size_t huge_method_threshold,
@@ -77,10 +84,10 @@
                   bool include_debug_symbols,
                   bool implicit_null_checks,
                   bool implicit_so_checks,
-                  bool implicit_suspend_checks
-#ifdef ART_SEA_IR_MODE
-                  , bool sea_ir_mode
-#endif
+                  bool implicit_suspend_checks,
+                  bool compile_pic,
+                  const std::vector<std::string>* verbose_methods,
+                  std::ostream* init_failure_output
                   ) :  // NOLINT(whitespace/parens)
     compiler_filter_(compiler_filter),
     huge_method_threshold_(huge_method_threshold),
@@ -94,11 +101,11 @@
     include_debug_symbols_(include_debug_symbols),
     implicit_null_checks_(implicit_null_checks),
     implicit_so_checks_(implicit_so_checks),
-    implicit_suspend_checks_(implicit_suspend_checks)
-#ifdef ART_SEA_IR_MODE
-    , sea_ir_mode_(sea_ir_mode)
-#endif
-    {}
+    implicit_suspend_checks_(implicit_suspend_checks),
+    compile_pic_(compile_pic),
+    verbose_methods_(verbose_methods),
+    init_failure_output_(init_failure_output) {
+  }
 
   CompilerFilter GetCompilerFilter() const {
     return compiler_filter_;
@@ -165,30 +172,14 @@
     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();
-#endif
-
   bool GetGenerateGDBInformation() const {
     return generate_gdb_information_;
   }
@@ -197,25 +188,54 @@
     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;
+  }
+
+  std::ostream* GetInitFailureOutput() const {
+    return init_failure_output_;
+  }
+
  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_;
-#ifdef ART_SEA_IR_MODE
-  bool sea_ir_mode_;
-#endif
+  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_;
+
+  // Vector of methods to have verbose output enabled for.
+  const std::vector<std::string>* const verbose_methods_;
+
+  // Log initialization of initialization failures to this stream if not null.
+  std::ostream* const init_failure_output_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
 };
+std::ostream& operator<<(std::ostream& os, const CompilerOptions::CompilerFilter& rhs);
 
 }  // namespace art
 
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 84f5799..03ae489 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -102,6 +102,10 @@
     return verified_method_;
   }
 
+  void ClearVerifiedMethod() {
+    verified_method_ = nullptr;
+  }
+
   const std::string& GetSymbol();
 
  private:
@@ -117,7 +121,7 @@
   const uint16_t class_def_idx_;
   const uint32_t dex_method_idx_;
   const uint32_t access_flags_;
-  const VerifiedMethod* const verified_method_;
+  const VerifiedMethod* verified_method_;
 
   std::string symbol_;
 };
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 3be2478..94268de 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -17,20 +17,22 @@
 #ifndef ART_COMPILER_ELF_BUILDER_H_
 #define ART_COMPILER_ELF_BUILDER_H_
 
+#include "arch/instruction_set.h"
 #include "base/stl_util.h"
+#include "base/value_object.h"
 #include "buffered_output_stream.h"
 #include "elf_utils.h"
 #include "file_output_stream.h"
-#include "instruction_set.h"
 
 namespace art {
 
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Shdr>
-class ElfSectionBuilder {
+class ElfSectionBuilder : public ValueObject {
  public:
   ElfSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
                     const ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> *link, Elf_Word info,
-                    Elf_Word align, Elf_Word entsize) : name_(sec_name), link_(link) {
+                    Elf_Word align, Elf_Word entsize)
+      : section_index_(0), name_(sec_name), link_(link) {
     memset(&section_, 0, sizeof(section_));
     section_.sh_type = type;
     section_.sh_flags = flags;
@@ -39,23 +41,41 @@
     section_.sh_entsize = entsize;
   }
 
-  virtual ~ElfSectionBuilder() {}
+  ~ElfSectionBuilder() {}
 
-  Elf_Shdr section_;
-  Elf_Word section_index_ = 0;
-
-  Elf_Word GetLink() {
-    return (link_) ? link_->section_index_ : 0;
+  Elf_Word GetLink() const {
+    return (link_ != nullptr) ? link_->section_index_ : 0;
   }
 
-  const std::string name_;
+  const Elf_Shdr* GetSection() const {
+    return &section_;
+  }
 
- protected:
-  const ElfSectionBuilder* link_;
+  Elf_Shdr* GetSection() {
+    return &section_;
+  }
+
+  Elf_Word GetSectionIndex() const {
+    return section_index_;
+  }
+
+  void SetSectionIndex(Elf_Word section_index) {
+    section_index_ = section_index;
+  }
+
+  const std::string& GetName() const {
+    return name_;
+  }
+
+ private:
+  Elf_Shdr section_;
+  Elf_Word section_index_;
+  const std::string name_;
+  const ElfSectionBuilder* const link_;
 };
 
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Dyn, typename Elf_Shdr>
-class ElfDynamicBuilder : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
+class ElfDynamicBuilder FINAL : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
  public:
   void AddDynamicTag(Elf_Sword tag, Elf_Word d_un) {
     if (tag == DT_NULL) {
@@ -65,7 +85,7 @@
   }
 
   void AddDynamicTag(Elf_Sword tag, Elf_Word d_un,
-                     ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* section) {
+                     const ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* section) {
     if (tag == DT_NULL) {
       return;
     }
@@ -78,7 +98,7 @@
                                                      link, 0, kPageSize, sizeof(Elf_Dyn)) {}
   ~ElfDynamicBuilder() {}
 
-  Elf_Word GetSize() {
+  Elf_Word GetSize() const {
     // Add 1 for the DT_NULL, 1 for DT_STRSZ, and 1 for DT_SONAME. All of
     // these must be added when we actually put the file together because
     // their values are very dependent on state.
@@ -89,13 +109,13 @@
   // table and soname_off should be the offset of the soname in .dynstr.
   // Since niether can be found prior to final layout we will wait until here
   // to add them.
-  std::vector<Elf_Dyn> GetDynamics(Elf_Word strsz, Elf_Word soname) {
+  std::vector<Elf_Dyn> GetDynamics(Elf_Word strsz, Elf_Word soname) const {
     std::vector<Elf_Dyn> ret;
     for (auto it = dynamics_.cbegin(); it != dynamics_.cend(); ++it) {
-      if (it->section_) {
+      if (it->section_ != nullptr) {
         // We are adding an address relative to a section.
         ret.push_back(
-            {it->tag_, {it->off_ + it->section_->section_.sh_addr}});
+            {it->tag_, {it->off_ + it->section_->GetSection()->sh_addr}});
       } else {
         ret.push_back({it->tag_, {it->off_}});
       }
@@ -106,9 +126,9 @@
     return ret;
   }
 
- protected:
+ private:
   struct ElfDynamicState {
-    ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* section_;
+    const ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* section_;
     Elf_Sword tag_;
     Elf_Word off_;
   };
@@ -116,39 +136,50 @@
 };
 
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Shdr>
-class ElfRawSectionBuilder : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
+class ElfRawSectionBuilder FINAL : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
  public:
   ElfRawSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
                        const ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* link, Elf_Word info,
                        Elf_Word align, Elf_Word entsize)
     : ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>(sec_name, type, flags, link, info, align,
-                                                       entsize) {}
-  ~ElfRawSectionBuilder() {}
-  std::vector<uint8_t>* GetBuffer() { return &buf_; }
-  void SetBuffer(std::vector<uint8_t>&& buf) { buf_ = buf; }
+                                                       entsize) {
+  }
 
- protected:
+  ~ElfRawSectionBuilder() {}
+
+  std::vector<uint8_t>* GetBuffer() {
+    return &buf_;
+  }
+
+  void SetBuffer(const std::vector<uint8_t>& buf) {
+    buf_ = buf;
+  }
+
+ private:
   std::vector<uint8_t> buf_;
 };
 
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Shdr>
-class ElfOatSectionBuilder : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
+class ElfOatSectionBuilder FINAL : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
  public:
   ElfOatSectionBuilder(const std::string& sec_name, Elf_Word size, Elf_Word offset,
                        Elf_Word type, Elf_Word flags)
     : ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>(sec_name, type, flags, nullptr, 0, kPageSize,
-                                                       0), offset_(offset), size_(size) {}
+                                                       0),
+      offset_(offset), size_(size) {
+  }
+
   ~ElfOatSectionBuilder() {}
 
-  Elf_Word GetOffset() {
+  Elf_Word GetOffset() const {
     return offset_;
   }
 
-  Elf_Word GetSize() {
+  Elf_Word GetSize() const {
     return size_;
   }
 
- protected:
+ private:
   // Offset of the content within the file.
   Elf_Word offset_;
   // Size of the content within the file.
@@ -175,7 +206,7 @@
 
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Sym,
           typename Elf_Shdr>
-class ElfSymtabBuilder : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
+class ElfSymtabBuilder FINAL : public ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> {
  public:
   // Add a symbol with given name to this symtab. The symbol refers to
   // 'relative_addr' within the given section and has the given attributes.
@@ -202,10 +233,12 @@
                                                      strtab_(str_name,
                                                              str_type,
                                                              ((alloc) ? SHF_ALLOC : 0U),
-                                                             nullptr, 0, 1, 1) {}
+                                                             nullptr, 0, 1, 1) {
+  }
+
   ~ElfSymtabBuilder() {}
 
-  std::vector<Elf_Word> GenerateHashContents() {
+  std::vector<Elf_Word> GenerateHashContents() const {
     // Here is how The ELF hash table works.
     // There are 3 arrays to worry about.
     // * The symbol table where the symbol information is.
@@ -295,7 +328,7 @@
       tab += it->name_;
       tab += '\0';
     }
-    strtab_.section_.sh_size = tab.size();
+    strtab_.GetSection()->sh_size = tab.size();
     return tab;
   }
 
@@ -311,13 +344,13 @@
       memset(&sym, 0, sizeof(sym));
       sym.st_name = it->name_idx_;
       if (it->is_relative_) {
-        sym.st_value = it->addr_ + it->section_->section_.sh_offset;
+        sym.st_value = it->addr_ + it->section_->GetSection()->sh_offset;
       } else {
         sym.st_value = it->addr_;
       }
       sym.st_size = it->size_;
       sym.st_other = it->other_;
-      sym.st_shndx = it->section_->section_index_;
+      sym.st_shndx = it->section_->GetSectionIndex();
       sym.st_info = it->info_;
 
       ret.push_back(sym);
@@ -325,7 +358,7 @@
     return ret;
   }
 
-  Elf_Word GetSize() {
+  Elf_Word GetSize() const {
     // 1 is for the implicit NULL symbol.
     return symbols_.size() + 1;
   }
@@ -334,7 +367,7 @@
     return &strtab_;
   }
 
- protected:
+ private:
   struct ElfSymbolState {
     const std::string name_;
     const ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* section_;
@@ -377,18 +410,26 @@
  protected:
   explicit ElfFilePiece(Elf_Word offset) : offset_(offset) {}
 
-  virtual std::string GetDescription() = 0;
+  Elf_Word GetOffset() const {
+    return offset_;
+  }
+
+  virtual const char* GetDescription() const = 0;
   virtual bool DoActualWrite(File* elf_file) = 0;
 
-  Elf_Word offset_;
+ private:
+  const Elf_Word offset_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElfFilePiece);
 };
 
 template <typename Elf_Word>
-class ElfFileMemoryPiece : public ElfFilePiece<Elf_Word> {
+class ElfFileMemoryPiece FINAL : public ElfFilePiece<Elf_Word> {
  public:
   ElfFileMemoryPiece(const std::string& name, Elf_Word offset, const void* data, Elf_Word size)
       : ElfFilePiece<Elf_Word>(offset), dbg_name_(name), data_(data), size_(size) {}
 
+ protected:
   bool DoActualWrite(File* elf_file) OVERRIDE {
     DCHECK(data_ != nullptr || size_ == 0U) << dbg_name_ << " " << size_;
 
@@ -400,8 +441,8 @@
     return true;
   }
 
-  std::string GetDescription() OVERRIDE {
-    return dbg_name_;
+  const char* GetDescription() const OVERRIDE {
+    return dbg_name_.c_str();
   }
 
  private:
@@ -418,13 +459,14 @@
 };
 
 template <typename Elf_Word>
-class ElfFileRodataPiece : public ElfFilePiece<Elf_Word> {
+class ElfFileRodataPiece FINAL : public ElfFilePiece<Elf_Word> {
  public:
   ElfFileRodataPiece(Elf_Word offset, CodeOutput* output) : ElfFilePiece<Elf_Word>(offset),
       output_(output) {}
 
+ protected:
   bool DoActualWrite(File* elf_file) OVERRIDE {
-    output_->SetCodeOffset(this->offset_);
+    output_->SetCodeOffset(this->GetOffset());
     std::unique_ptr<BufferedOutputStream> output_stream(
         new BufferedOutputStream(new FileOutputStream(elf_file)));
     if (!output_->Write(output_stream.get())) {
@@ -435,33 +477,38 @@
     return true;
   }
 
-  std::string GetDescription() OVERRIDE {
+  const char* GetDescription() const OVERRIDE {
     return ".rodata";
   }
 
  private:
-  CodeOutput* output_;
+  CodeOutput* const output_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElfFileRodataPiece);
 };
 
 template <typename Elf_Word>
-class ElfFileOatTextPiece : public ElfFilePiece<Elf_Word> {
+class ElfFileOatTextPiece FINAL : public ElfFilePiece<Elf_Word> {
  public:
   ElfFileOatTextPiece(Elf_Word offset, CodeOutput* output) : ElfFilePiece<Elf_Word>(offset),
       output_(output) {}
 
-  bool DoActualWrite(File* elf_file) OVERRIDE {
+ protected:
+  bool DoActualWrite(File* elf_file ATTRIBUTE_UNUSED) OVERRIDE {
     // All data is written by the ElfFileRodataPiece right now, as the oat writer writes in one
     // piece. This is for future flexibility.
     UNUSED(output_);
     return true;
   }
 
-  std::string GetDescription() OVERRIDE {
+  const char* GetDescription() const OVERRIDE {
     return ".text";
   }
 
  private:
-  CodeOutput* output_;
+  CodeOutput* const output_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElfFileOatTextPiece);
 };
 
 template <typename Elf_Word>
@@ -513,6 +560,14 @@
   }
   ~ElfBuilder() {}
 
+  const ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>& GetTextBuilder() const {
+    return text_builder_;
+  }
+
+  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr>* GetSymtabBuilder() {
+    return &symtab_builder_;
+  }
+
   bool Init() {
     // The basic layout of the elf file. Order may be different in final output.
     // +-------------------------+
@@ -676,34 +731,40 @@
     section_index_ = 1;
 
     // setup .dynsym
-    section_ptrs_.push_back(&dynsym_builder_.section_);
+    section_ptrs_.push_back(dynsym_builder_.GetSection());
     AssignSectionStr(&dynsym_builder_, &shstrtab_);
-    dynsym_builder_.section_index_ = section_index_++;
+    dynsym_builder_.SetSectionIndex(section_index_);
+    section_index_++;
 
     // Setup .dynstr
-    section_ptrs_.push_back(&dynsym_builder_.GetStrTab()->section_);
+    section_ptrs_.push_back(dynsym_builder_.GetStrTab()->GetSection());
     AssignSectionStr(dynsym_builder_.GetStrTab(), &shstrtab_);
-    dynsym_builder_.GetStrTab()->section_index_ = section_index_++;
+    dynsym_builder_.GetStrTab()->SetSectionIndex(section_index_);
+    section_index_++;
 
     // Setup .hash
-    section_ptrs_.push_back(&hash_builder_.section_);
+    section_ptrs_.push_back(hash_builder_.GetSection());
     AssignSectionStr(&hash_builder_, &shstrtab_);
-    hash_builder_.section_index_ = section_index_++;
+    hash_builder_.SetSectionIndex(section_index_);
+    section_index_++;
 
     // Setup .rodata
-    section_ptrs_.push_back(&rodata_builder_.section_);
+    section_ptrs_.push_back(rodata_builder_.GetSection());
     AssignSectionStr(&rodata_builder_, &shstrtab_);
-    rodata_builder_.section_index_ = section_index_++;
+    rodata_builder_.SetSectionIndex(section_index_);
+    section_index_++;
 
     // Setup .text
-    section_ptrs_.push_back(&text_builder_.section_);
+    section_ptrs_.push_back(text_builder_.GetSection());
     AssignSectionStr(&text_builder_, &shstrtab_);
-    text_builder_.section_index_ = section_index_++;
+    text_builder_.SetSectionIndex(section_index_);
+    section_index_++;
 
     // Setup .dynamic
-    section_ptrs_.push_back(&dynamic_builder_.section_);
+    section_ptrs_.push_back(dynamic_builder_.GetSection());
     AssignSectionStr(&dynamic_builder_, &shstrtab_);
-    dynamic_builder_.section_index_ = section_index_++;
+    dynamic_builder_.SetSectionIndex(section_index_);
+    section_index_++;
 
     // Fill in the hash section.
     hash_ = dynsym_builder_.GenerateHashContents();
@@ -718,64 +779,67 @@
     // Get the layout in the sections.
     //
     // Get the layout of the dynsym section.
-    dynsym_builder_.section_.sh_offset = RoundUp(base_offset, dynsym_builder_.section_.sh_addralign);
-    dynsym_builder_.section_.sh_addr = dynsym_builder_.section_.sh_offset;
-    dynsym_builder_.section_.sh_size = dynsym_builder_.GetSize() * sizeof(Elf_Sym);
-    dynsym_builder_.section_.sh_link = dynsym_builder_.GetLink();
+    dynsym_builder_.GetSection()->sh_offset =
+        RoundUp(base_offset, dynsym_builder_.GetSection()->sh_addralign);
+    dynsym_builder_.GetSection()->sh_addr = dynsym_builder_.GetSection()->sh_offset;
+    dynsym_builder_.GetSection()->sh_size = dynsym_builder_.GetSize() * sizeof(Elf_Sym);
+    dynsym_builder_.GetSection()->sh_link = dynsym_builder_.GetLink();
 
     // Get the layout of the dynstr section.
-    dynsym_builder_.GetStrTab()->section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                                 (dynsym_builder_.GetStrTab()->section_,
-                                                  dynsym_builder_.section_);
-    dynsym_builder_.GetStrTab()->section_.sh_addr = dynsym_builder_.GetStrTab()->section_.sh_offset;
-    dynsym_builder_.GetStrTab()->section_.sh_size = dynstr_.size();
-    dynsym_builder_.GetStrTab()->section_.sh_link = dynsym_builder_.GetStrTab()->GetLink();
+    dynsym_builder_.GetStrTab()->GetSection()->sh_offset =
+        NextOffset<Elf_Word, Elf_Shdr>(*dynsym_builder_.GetStrTab()->GetSection(),
+                                       *dynsym_builder_.GetSection());
+    dynsym_builder_.GetStrTab()->GetSection()->sh_addr =
+        dynsym_builder_.GetStrTab()->GetSection()->sh_offset;
+    dynsym_builder_.GetStrTab()->GetSection()->sh_size = dynstr_.size();
+    dynsym_builder_.GetStrTab()->GetSection()->sh_link = dynsym_builder_.GetStrTab()->GetLink();
 
     // Get the layout of the hash section
-    hash_builder_.section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                       (hash_builder_.section_,
-                                        dynsym_builder_.GetStrTab()->section_);
-    hash_builder_.section_.sh_addr = hash_builder_.section_.sh_offset;
-    hash_builder_.section_.sh_size = hash_.size() * sizeof(Elf_Word);
-    hash_builder_.section_.sh_link = hash_builder_.GetLink();
+    hash_builder_.GetSection()->sh_offset =
+        NextOffset<Elf_Word, Elf_Shdr>(*hash_builder_.GetSection(),
+                                       *dynsym_builder_.GetStrTab()->GetSection());
+    hash_builder_.GetSection()->sh_addr = hash_builder_.GetSection()->sh_offset;
+    hash_builder_.GetSection()->sh_size = hash_.size() * sizeof(Elf_Word);
+    hash_builder_.GetSection()->sh_link = hash_builder_.GetLink();
 
     // Get the layout of the rodata section.
-    rodata_builder_.section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                         (rodata_builder_.section_,
-                                          hash_builder_.section_);
-    rodata_builder_.section_.sh_addr = rodata_builder_.section_.sh_offset;
-    rodata_builder_.section_.sh_size = rodata_builder_.GetSize();
-    rodata_builder_.section_.sh_link = rodata_builder_.GetLink();
+    rodata_builder_.GetSection()->sh_offset =
+        NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(),
+                                       *hash_builder_.GetSection());
+    rodata_builder_.GetSection()->sh_addr = rodata_builder_.GetSection()->sh_offset;
+    rodata_builder_.GetSection()->sh_size = rodata_builder_.GetSize();
+    rodata_builder_.GetSection()->sh_link = rodata_builder_.GetLink();
 
     // Get the layout of the text section.
-    text_builder_.section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                       (text_builder_.section_, rodata_builder_.section_);
-    text_builder_.section_.sh_addr = text_builder_.section_.sh_offset;
-    text_builder_.section_.sh_size = text_builder_.GetSize();
-    text_builder_.section_.sh_link = text_builder_.GetLink();
-    CHECK_ALIGNED(rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size, kPageSize);
+    text_builder_.GetSection()->sh_offset =
+        NextOffset<Elf_Word, Elf_Shdr>(*text_builder_.GetSection(),
+                                       *rodata_builder_.GetSection());
+    text_builder_.GetSection()->sh_addr = text_builder_.GetSection()->sh_offset;
+    text_builder_.GetSection()->sh_size = text_builder_.GetSize();
+    text_builder_.GetSection()->sh_link = text_builder_.GetLink();
+    CHECK_ALIGNED(rodata_builder_.GetSection()->sh_offset +
+                  rodata_builder_.GetSection()->sh_size, kPageSize);
 
     // Get the layout of the dynamic section.
-    dynamic_builder_.section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                          (dynamic_builder_.section_,
-                                           text_builder_.section_);
-    dynamic_builder_.section_.sh_addr = dynamic_builder_.section_.sh_offset;
-    dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf_Dyn);
-    dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink();
+    dynamic_builder_.GetSection()->sh_offset =
+        NextOffset<Elf_Word, Elf_Shdr>(*dynamic_builder_.GetSection(), *text_builder_.GetSection());
+    dynamic_builder_.GetSection()->sh_addr = dynamic_builder_.GetSection()->sh_offset;
+    dynamic_builder_.GetSection()->sh_size = dynamic_builder_.GetSize() * sizeof(Elf_Dyn);
+    dynamic_builder_.GetSection()->sh_link = dynamic_builder_.GetLink();
 
     if (debug_logging_) {
-      LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
-                << " dynsym size=" << dynsym_builder_.section_.sh_size;
-      LOG(INFO) << "dynstr off=" << dynsym_builder_.GetStrTab()->section_.sh_offset
-                << " dynstr size=" << dynsym_builder_.GetStrTab()->section_.sh_size;
-      LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
-                << " hash size=" << hash_builder_.section_.sh_size;
-      LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
-                << " rodata size=" << rodata_builder_.section_.sh_size;
-      LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
-                << " text size=" << text_builder_.section_.sh_size;
-      LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
-                << " dynamic size=" << dynamic_builder_.section_.sh_size;
+      LOG(INFO) << "dynsym off=" << dynsym_builder_.GetSection()->sh_offset
+                << " dynsym size=" << dynsym_builder_.GetSection()->sh_size;
+      LOG(INFO) << "dynstr off=" << dynsym_builder_.GetStrTab()->GetSection()->sh_offset
+                << " dynstr size=" << dynsym_builder_.GetStrTab()->GetSection()->sh_size;
+      LOG(INFO) << "hash off=" << hash_builder_.GetSection()->sh_offset
+                << " hash size=" << hash_builder_.GetSection()->sh_size;
+      LOG(INFO) << "rodata off=" << rodata_builder_.GetSection()->sh_offset
+                << " rodata size=" << rodata_builder_.GetSection()->sh_size;
+      LOG(INFO) << "text off=" << text_builder_.GetSection()->sh_offset
+                << " text size=" << text_builder_.GetSection()->sh_size;
+      LOG(INFO) << "dynamic off=" << dynamic_builder_.GetSection()->sh_offset
+                << " dynamic size=" << dynamic_builder_.GetSection()->sh_size;
     }
 
     return true;
@@ -783,19 +847,21 @@
 
   bool Write() {
     std::vector<ElfFilePiece<Elf_Word>*> pieces;
-    Elf_Shdr prev = dynamic_builder_.section_;
+    Elf_Shdr* prev = dynamic_builder_.GetSection();
     std::string strtab;
 
     if (IncludingDebugSymbols()) {
       // Setup .symtab
-      section_ptrs_.push_back(&symtab_builder_.section_);
+      section_ptrs_.push_back(symtab_builder_.GetSection());
       AssignSectionStr(&symtab_builder_, &shstrtab_);
-      symtab_builder_.section_index_ = section_index_++;
+      symtab_builder_.SetSectionIndex(section_index_);
+      section_index_++;
 
       // Setup .strtab
-      section_ptrs_.push_back(&symtab_builder_.GetStrTab()->section_);
+      section_ptrs_.push_back(symtab_builder_.GetStrTab()->GetSection());
       AssignSectionStr(symtab_builder_.GetStrTab(), &shstrtab_);
-      symtab_builder_.GetStrTab()->section_index_ = section_index_++;
+      symtab_builder_.GetStrTab()->SetSectionIndex(section_index_);
+      section_index_++;
 
       strtab = symtab_builder_.GenerateStrtab();
       if (debug_logging_) {
@@ -810,15 +876,17 @@
     for (ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> *builder = other_builders_.data(),
          *end = builder + other_builders_.size();
          builder != end; ++builder) {
-      section_ptrs_.push_back(&builder->section_);
+      section_ptrs_.push_back(builder->GetSection());
       AssignSectionStr(builder, &shstrtab_);
-      builder->section_index_ = section_index_++;
+      builder->SetSectionIndex(section_index_);
+      section_index_++;
     }
 
     // Setup shstrtab
-    section_ptrs_.push_back(&shstrtab_builder_.section_);
+    section_ptrs_.push_back(shstrtab_builder_.GetSection());
     AssignSectionStr(&shstrtab_builder_, &shstrtab_);
-    shstrtab_builder_.section_index_ = section_index_++;
+    shstrtab_builder_.SetSectionIndex(section_index_);
+    section_index_++;
 
     if (debug_logging_) {
       LOG(INFO) << ".shstrtab size    (bytes)   =" << shstrtab_.size()
@@ -829,71 +897,71 @@
 
     if (IncludingDebugSymbols()) {
       // Get the layout of the symtab section.
-      symtab_builder_.section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                           (symtab_builder_.section_,
-                                            dynamic_builder_.section_);
-      symtab_builder_.section_.sh_addr = 0;
+      symtab_builder_.GetSection()->sh_offset =
+          NextOffset<Elf_Word, Elf_Shdr>(*symtab_builder_.GetSection(),
+                                         *dynamic_builder_.GetSection());
+      symtab_builder_.GetSection()->sh_addr = 0;
       // Add to leave space for the null symbol.
-      symtab_builder_.section_.sh_size = symtab_builder_.GetSize() * sizeof(Elf_Sym);
-      symtab_builder_.section_.sh_link = symtab_builder_.GetLink();
+      symtab_builder_.GetSection()->sh_size = symtab_builder_.GetSize() * sizeof(Elf_Sym);
+      symtab_builder_.GetSection()->sh_link = symtab_builder_.GetLink();
 
       // Get the layout of the dynstr section.
-      symtab_builder_.GetStrTab()->section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                                   (symtab_builder_.GetStrTab()->section_,
-                                                    symtab_builder_.section_);
-      symtab_builder_.GetStrTab()->section_.sh_addr = 0;
-      symtab_builder_.GetStrTab()->section_.sh_size = strtab.size();
-      symtab_builder_.GetStrTab()->section_.sh_link = symtab_builder_.GetStrTab()->GetLink();
+      symtab_builder_.GetStrTab()->GetSection()->sh_offset =
+          NextOffset<Elf_Word, Elf_Shdr>(*symtab_builder_.GetStrTab()->GetSection(),
+                                         *symtab_builder_.GetSection());
+      symtab_builder_.GetStrTab()->GetSection()->sh_addr = 0;
+      symtab_builder_.GetStrTab()->GetSection()->sh_size = strtab.size();
+      symtab_builder_.GetStrTab()->GetSection()->sh_link = symtab_builder_.GetStrTab()->GetLink();
 
-      prev = symtab_builder_.GetStrTab()->section_;
+      prev = symtab_builder_.GetStrTab()->GetSection();
       if (debug_logging_) {
-        LOG(INFO) << "symtab off=" << symtab_builder_.section_.sh_offset
-                  << " symtab size=" << symtab_builder_.section_.sh_size;
-        LOG(INFO) << "strtab off=" << symtab_builder_.GetStrTab()->section_.sh_offset
-                  << " strtab size=" << symtab_builder_.GetStrTab()->section_.sh_size;
+        LOG(INFO) << "symtab off=" << symtab_builder_.GetSection()->sh_offset
+                  << " symtab size=" << symtab_builder_.GetSection()->sh_size;
+        LOG(INFO) << "strtab off=" << symtab_builder_.GetStrTab()->GetSection()->sh_offset
+                  << " strtab size=" << symtab_builder_.GetStrTab()->GetSection()->sh_size;
       }
     }
 
     // Get the layout of the extra sections. (This will deal with the debug
     // sections if they are there)
     for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
-      it->section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>(it->section_, prev);
-      it->section_.sh_addr = 0;
-      it->section_.sh_size = it->GetBuffer()->size();
-      it->section_.sh_link = it->GetLink();
+      it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
+      it->GetSection()->sh_addr = 0;
+      it->GetSection()->sh_size = it->GetBuffer()->size();
+      it->GetSection()->sh_link = it->GetLink();
 
       // We postpone adding an ElfFilePiece to keep the order in "pieces."
 
-      prev = it->section_;
+      prev = it->GetSection();
       if (debug_logging_) {
-        LOG(INFO) << it->name_ << " off=" << it->section_.sh_offset
-                  << " size=" << it->section_.sh_size;
+        LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset
+                  << " size=" << it->GetSection()->sh_size;
       }
     }
 
     // Get the layout of the shstrtab section
-    shstrtab_builder_.section_.sh_offset = NextOffset<Elf_Word, Elf_Shdr>
-                                           (shstrtab_builder_.section_, prev);
-    shstrtab_builder_.section_.sh_addr = 0;
-    shstrtab_builder_.section_.sh_size = shstrtab_.size();
-    shstrtab_builder_.section_.sh_link = shstrtab_builder_.GetLink();
+    shstrtab_builder_.GetSection()->sh_offset =
+        NextOffset<Elf_Word, Elf_Shdr>(*shstrtab_builder_.GetSection(), *prev);
+    shstrtab_builder_.GetSection()->sh_addr = 0;
+    shstrtab_builder_.GetSection()->sh_size = shstrtab_.size();
+    shstrtab_builder_.GetSection()->sh_link = shstrtab_builder_.GetLink();
     if (debug_logging_) {
-        LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset
-                  << " shstrtab size=" << shstrtab_builder_.section_.sh_size;
+        LOG(INFO) << "shstrtab off=" << shstrtab_builder_.GetSection()->sh_offset
+                  << " shstrtab size=" << shstrtab_builder_.GetSection()->sh_size;
     }
 
     // The section list comes after come after.
     Elf_Word sections_offset = RoundUp(
-        shstrtab_builder_.section_.sh_offset + shstrtab_builder_.section_.sh_size,
+        shstrtab_builder_.GetSection()->sh_offset + shstrtab_builder_.GetSection()->sh_size,
         sizeof(Elf_Word));
 
     // Setup the actual symbol arrays.
     std::vector<Elf_Sym> dynsym = dynsym_builder_.GenerateSymtab();
-    CHECK_EQ(dynsym.size() * sizeof(Elf_Sym), dynsym_builder_.section_.sh_size);
+    CHECK_EQ(dynsym.size() * sizeof(Elf_Sym), dynsym_builder_.GetSection()->sh_size);
     std::vector<Elf_Sym> symtab;
     if (IncludingDebugSymbols()) {
       symtab = symtab_builder_.GenerateSymtab();
-      CHECK_EQ(symtab.size() * sizeof(Elf_Sym), symtab_builder_.section_.sh_size);
+      CHECK_EQ(symtab.size() * sizeof(Elf_Sym), symtab_builder_.GetSection()->sh_size);
     }
 
     // Setup the dynamic section.
@@ -901,43 +969,44 @@
     // and the soname_offset.
     std::vector<Elf_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(),
                                                                   dynstr_soname_offset_);
-    CHECK_EQ(dynamic.size() * sizeof(Elf_Dyn), dynamic_builder_.section_.sh_size);
+    CHECK_EQ(dynamic.size() * sizeof(Elf_Dyn), dynamic_builder_.GetSection()->sh_size);
 
     // Finish setup of the program headers now that we know the layout of the
     // whole file.
-    Elf_Word load_r_size = rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size;
+    Elf_Word load_r_size =
+        rodata_builder_.GetSection()->sh_offset + rodata_builder_.GetSection()->sh_size;
     program_headers_[PH_LOAD_R__].p_filesz = load_r_size;
     program_headers_[PH_LOAD_R__].p_memsz =  load_r_size;
-    program_headers_[PH_LOAD_R__].p_align =  rodata_builder_.section_.sh_addralign;
+    program_headers_[PH_LOAD_R__].p_align =  rodata_builder_.GetSection()->sh_addralign;
 
-    Elf_Word load_rx_size = text_builder_.section_.sh_size;
-    program_headers_[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
-    program_headers_[PH_LOAD_R_X].p_vaddr  = text_builder_.section_.sh_offset;
-    program_headers_[PH_LOAD_R_X].p_paddr  = text_builder_.section_.sh_offset;
+    Elf_Word load_rx_size = text_builder_.GetSection()->sh_size;
+    program_headers_[PH_LOAD_R_X].p_offset = text_builder_.GetSection()->sh_offset;
+    program_headers_[PH_LOAD_R_X].p_vaddr  = text_builder_.GetSection()->sh_offset;
+    program_headers_[PH_LOAD_R_X].p_paddr  = text_builder_.GetSection()->sh_offset;
     program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size;
     program_headers_[PH_LOAD_R_X].p_memsz  = load_rx_size;
-    program_headers_[PH_LOAD_R_X].p_align  = text_builder_.section_.sh_addralign;
+    program_headers_[PH_LOAD_R_X].p_align  = text_builder_.GetSection()->sh_addralign;
 
-    program_headers_[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
-    program_headers_[PH_LOAD_RW_].p_vaddr  = dynamic_builder_.section_.sh_offset;
-    program_headers_[PH_LOAD_RW_].p_paddr  = dynamic_builder_.section_.sh_offset;
-    program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
-    program_headers_[PH_LOAD_RW_].p_memsz  = dynamic_builder_.section_.sh_size;
-    program_headers_[PH_LOAD_RW_].p_align  = dynamic_builder_.section_.sh_addralign;
+    program_headers_[PH_LOAD_RW_].p_offset = dynamic_builder_.GetSection()->sh_offset;
+    program_headers_[PH_LOAD_RW_].p_vaddr  = dynamic_builder_.GetSection()->sh_offset;
+    program_headers_[PH_LOAD_RW_].p_paddr  = dynamic_builder_.GetSection()->sh_offset;
+    program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.GetSection()->sh_size;
+    program_headers_[PH_LOAD_RW_].p_memsz  = dynamic_builder_.GetSection()->sh_size;
+    program_headers_[PH_LOAD_RW_].p_align  = dynamic_builder_.GetSection()->sh_addralign;
 
-    program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
-    program_headers_[PH_DYNAMIC].p_vaddr  = dynamic_builder_.section_.sh_offset;
-    program_headers_[PH_DYNAMIC].p_paddr  = dynamic_builder_.section_.sh_offset;
-    program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
-    program_headers_[PH_DYNAMIC].p_memsz  = dynamic_builder_.section_.sh_size;
-    program_headers_[PH_DYNAMIC].p_align  = dynamic_builder_.section_.sh_addralign;
+    program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.GetSection()->sh_offset;
+    program_headers_[PH_DYNAMIC].p_vaddr  = dynamic_builder_.GetSection()->sh_offset;
+    program_headers_[PH_DYNAMIC].p_paddr  = dynamic_builder_.GetSection()->sh_offset;
+    program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.GetSection()->sh_size;
+    program_headers_[PH_DYNAMIC].p_memsz  = dynamic_builder_.GetSection()->sh_size;
+    program_headers_[PH_DYNAMIC].p_align  = dynamic_builder_.GetSection()->sh_addralign;
 
     // Finish setup of the Ehdr values.
     elf_header_.e_phoff = PHDR_OFFSET;
     elf_header_.e_shoff = sections_offset;
     elf_header_.e_phnum = PH_NUM;
     elf_header_.e_shnum = section_ptrs_.size();
-    elf_header_.e_shstrndx = shstrtab_builder_.section_index_;
+    elf_header_.e_shstrndx = shstrtab_builder_.GetSectionIndex();
 
     // Add the rest of the pieces to the list.
     pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Elf Header", 0, &elf_header_,
@@ -945,33 +1014,33 @@
     pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers", PHDR_OFFSET,
                                                       &program_headers_, sizeof(program_headers_)));
     pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynamic",
-                                                      dynamic_builder_.section_.sh_offset,
+                                                      dynamic_builder_.GetSection()->sh_offset,
                                                       dynamic.data(),
-                                                      dynamic_builder_.section_.sh_size));
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynsym", dynsym_builder_.section_.sh_offset,
+                                                      dynamic_builder_.GetSection()->sh_size));
+    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynsym", dynsym_builder_.GetSection()->sh_offset,
                                                       dynsym.data(),
                                                       dynsym.size() * sizeof(Elf_Sym)));
     pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynstr",
-                                                    dynsym_builder_.GetStrTab()->section_.sh_offset,
+                                                    dynsym_builder_.GetStrTab()->GetSection()->sh_offset,
                                                     dynstr_.c_str(), dynstr_.size()));
-    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".hash", hash_builder_.section_.sh_offset,
+    pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".hash", hash_builder_.GetSection()->sh_offset,
                                                       hash_.data(),
                                                       hash_.size() * sizeof(Elf_Word)));
-    pieces.push_back(new ElfFileRodataPiece<Elf_Word>(rodata_builder_.section_.sh_offset,
+    pieces.push_back(new ElfFileRodataPiece<Elf_Word>(rodata_builder_.GetSection()->sh_offset,
                                                       oat_writer_));
-    pieces.push_back(new ElfFileOatTextPiece<Elf_Word>(text_builder_.section_.sh_offset,
+    pieces.push_back(new ElfFileOatTextPiece<Elf_Word>(text_builder_.GetSection()->sh_offset,
                                                        oat_writer_));
     if (IncludingDebugSymbols()) {
       pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".symtab",
-                                                        symtab_builder_.section_.sh_offset,
+                                                        symtab_builder_.GetSection()->sh_offset,
                                                         symtab.data(),
                                                         symtab.size() * sizeof(Elf_Sym)));
       pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".strtab",
-                                                    symtab_builder_.GetStrTab()->section_.sh_offset,
+                                                    symtab_builder_.GetStrTab()->GetSection()->sh_offset,
                                                     strtab.c_str(), strtab.size()));
     }
     pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".shstrtab",
-                                                      shstrtab_builder_.section_.sh_offset,
+                                                      shstrtab_builder_.GetSection()->sh_offset,
                                                       &shstrtab_[0], shstrtab_.size()));
     for (uint32_t i = 0; i < section_ptrs_.size(); ++i) {
       // Just add all the sections in induvidually since they are all over the
@@ -983,7 +1052,7 @@
 
     // Postponed debug info.
     for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
-      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(it->name_, it->section_.sh_offset,
+      pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(it->GetName(), it->GetSection()->sh_offset,
                                                         it->GetBuffer()->data(),
                                                         it->GetBuffer()->size()));
     }
@@ -1006,47 +1075,6 @@
   }
 
  private:
-  CodeOutput* oat_writer_;
-  File* elf_file_;
-  const bool add_symbols_;
-  const bool debug_logging_;
-
-  bool fatal_error_ = false;
-
-  // What phdr is.
-  static const uint32_t PHDR_OFFSET = sizeof(Elf_Ehdr);
-  enum : uint8_t {
-    PH_PHDR     = 0,
-        PH_LOAD_R__ = 1,
-        PH_LOAD_R_X = 2,
-        PH_LOAD_RW_ = 3,
-        PH_DYNAMIC  = 4,
-        PH_NUM      = 5,
-  };
-  static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM;
-  Elf_Phdr program_headers_[PH_NUM];
-
-  Elf_Ehdr elf_header_;
-
-  Elf_Shdr null_hdr_;
-  std::string shstrtab_;
-  uint32_t section_index_;
-  std::string dynstr_;
-  uint32_t dynstr_soname_offset_;
-  std::vector<Elf_Shdr*> section_ptrs_;
-  std::vector<Elf_Word> hash_;
-
- public:
-  ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> text_builder_;
-  ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> rodata_builder_;
-  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr> dynsym_builder_;
-  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr> symtab_builder_;
-  ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> hash_builder_;
-  ElfDynamicBuilder<Elf_Word, Elf_Sword, Elf_Dyn, Elf_Shdr> dynamic_builder_;
-  ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> shstrtab_builder_;
-  std::vector<ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>> other_builders_;
-
- private:
   void SetISA(InstructionSet isa) {
     switch (isa) {
       case kArm:
@@ -1080,6 +1108,14 @@
                                EF_MIPS_ARCH_32R2);
         break;
       }
+      case kMips64: {
+        elf_header_.e_machine = EM_MIPS;
+        elf_header_.e_flags = (EF_MIPS_NOREORDER |
+                               EF_MIPS_PIC       |
+                               EF_MIPS_CPIC      |
+                               EF_MIPS_ARCH_64R6);
+        break;
+      }
       default: {
         fatal_error_ = true;
         LOG(FATAL) << "Unknown instruction set: " << isa;
@@ -1094,7 +1130,8 @@
     elf_header_.e_ident[EI_MAG1]       = ELFMAG1;
     elf_header_.e_ident[EI_MAG2]       = ELFMAG2;
     elf_header_.e_ident[EI_MAG3]       = ELFMAG3;
-    elf_header_.e_ident[EI_CLASS]      = ELFCLASS32;
+    elf_header_.e_ident[EI_CLASS]      = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
+                                         ? ELFCLASS32 : ELFCLASS64;;
     elf_header_.e_ident[EI_DATA]       = ELFDATA2LSB;
     elf_header_.e_ident[EI_VERSION]    = EV_CURRENT;
     elf_header_.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
@@ -1140,14 +1177,14 @@
                               true, 4, STB_GLOBAL, STT_OBJECT);
   }
 
-  void AssignSectionStr(ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> *builder,
+  void AssignSectionStr(ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* builder,
                         std::string* strtab) {
-    builder->section_.sh_name = strtab->size();
-    *strtab += builder->name_;
+    builder->GetSection()->sh_name = strtab->size();
+    *strtab += builder->GetName();
     *strtab += '\0';
     if (debug_logging_) {
-      LOG(INFO) << "adding section name \"" << builder->name_ << "\" "
-                << "to shstrtab at offset " << builder->section_.sh_name;
+      LOG(INFO) << "adding section name \"" << builder->GetName() << "\" "
+                << "to shstrtab at offset " << builder->GetSection()->sh_name;
     }
   }
 
@@ -1162,7 +1199,51 @@
     return true;
   }
 
-  bool IncludingDebugSymbols() { return add_symbols_ && symtab_builder_.GetSize() > 1; }
+  bool IncludingDebugSymbols() const {
+    return add_symbols_ && symtab_builder_.GetSize() > 1;
+  }
+
+  CodeOutput* const oat_writer_;
+  File* const elf_file_;
+  const bool add_symbols_;
+  const bool debug_logging_;
+
+  bool fatal_error_ = false;
+
+  // What phdr is.
+  static const uint32_t PHDR_OFFSET = sizeof(Elf_Ehdr);
+  enum : uint8_t {
+    PH_PHDR     = 0,
+        PH_LOAD_R__ = 1,
+        PH_LOAD_R_X = 2,
+        PH_LOAD_RW_ = 3,
+        PH_DYNAMIC  = 4,
+        PH_NUM      = 5,
+  };
+  static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM;
+  Elf_Phdr program_headers_[PH_NUM];
+
+  Elf_Ehdr elf_header_;
+
+  Elf_Shdr null_hdr_;
+  std::string shstrtab_;
+  // The index of the current section being built. The first being 1.
+  uint32_t section_index_;
+  std::string dynstr_;
+  uint32_t dynstr_soname_offset_;
+  std::vector<const Elf_Shdr*> section_ptrs_;
+  std::vector<Elf_Word> hash_;
+
+  ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> text_builder_;
+  ElfOatSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> rodata_builder_;
+  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr> dynsym_builder_;
+  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr> symtab_builder_;
+  ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> hash_builder_;
+  ElfDynamicBuilder<Elf_Word, Elf_Sword, Elf_Dyn, Elf_Shdr> dynamic_builder_;
+  ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> shstrtab_builder_;
+  std::vector<ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>> other_builders_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
 };
 
 }  // namespace art
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
deleted file mode 100644
index 0d34879..0000000
--- a/compiler/elf_fixup.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "elf_fixup.h"
-
-#include <inttypes.h>
-#include <memory>
-
-#include "base/logging.h"
-#include "base/stringprintf.h"
-#include "elf_file.h"
-#include "elf_writer.h"
-
-namespace art {
-
-static const bool DEBUG_FIXUP = false;
-
-bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) {
-  std::string error_msg;
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
-  CHECK(elf_file.get() != nullptr) << error_msg;
-
-  // Lookup "oatdata" symbol address.
-  Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
-  Elf32_Off base_address = oat_data_begin - oatdata_address;
-
-  if (!FixupDynamic(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup .dynamic in " << file->GetPath();
-    return false;
-  }
-  if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup section headers in " << file->GetPath();
-    return false;
-  }
-  if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup program headers in " << file->GetPath();
-    return false;
-  }
-  if (!FixupSymbols(*elf_file.get(), base_address, true)) {
-    LOG(WARNING) << "Failed to fixup .dynsym in " << file->GetPath();
-    return false;
-  }
-  if (!FixupSymbols(*elf_file.get(), base_address, false)) {
-    LOG(WARNING) << "Failed to fixup .symtab in " << file->GetPath();
-    return false;
-  }
-  if (!FixupRelocations(*elf_file.get(), base_address)) {
-    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file->GetPath();
-    return false;
-  }
-  if (!elf_file->FixupDebugSections(base_address)) {
-    LOG(WARNING) << "Failed to fixup debug sections in " << file->GetPath();
-    return false;
-  }
-  return true;
-}
-
-
-bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) {
-  for (Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) {
-    Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i);
-    Elf32_Word d_tag = elf_dyn.d_tag;
-    if (IsDynamicSectionPointer(d_tag, elf_file.GetHeader().e_machine)) {
-      uint32_t d_ptr = elf_dyn.d_un.d_ptr;
-      if (DEBUG_FIXUP) {
-        LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                  elf_file.GetFile().GetPath().c_str(), i,
-                                  d_ptr, d_ptr + base_address);
-      }
-      d_ptr += base_address;
-      elf_dyn.d_un.d_ptr = d_ptr;
-    }
-  }
-  return true;
-}
-
-bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) {
-  for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
-    CHECK(sh != nullptr);
-    // 0 implies that the section will not exist in the memory of the process
-    if (sh->sh_addr == 0) {
-      continue;
-    }
-    if (DEBUG_FIXUP) {
-      LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                elf_file.GetFile().GetPath().c_str(), i,
-                                sh->sh_addr, sh->sh_addr + base_address);
-    }
-    sh->sh_addr += base_address;
-  }
-  return true;
-}
-
-bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) {
-  // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now.
-  for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* ph = elf_file.GetProgramHeader(i);
-    CHECK(ph != nullptr);
-    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
-    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
-            << elf_file.GetFile().GetPath() << " i=" << i;
-    if (DEBUG_FIXUP) {
-      LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                elf_file.GetFile().GetPath().c_str(), i,
-                                ph->p_vaddr, ph->p_vaddr + base_address);
-    }
-    ph->p_vaddr += base_address;
-    ph->p_paddr += base_address;
-    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
-            << elf_file.GetFile().GetPath() << " i=" << i;
-  }
-  return true;
-}
-
-bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) {
-  Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
-  // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
-  Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
-  if (symbol_section == nullptr) {
-    // file is missing optional .symtab
-    CHECK(!dynamic) << elf_file.GetFile().GetPath();
-    return true;
-  }
-  for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) {
-    Elf32_Sym* symbol = elf_file.GetSymbol(section_type, i);
-    CHECK(symbol != nullptr);
-    if (symbol->st_value != 0) {
-      if (DEBUG_FIXUP) {
-        LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                  elf_file.GetFile().GetPath().c_str(), i,
-                                  symbol->st_value, symbol->st_value + base_address);
-      }
-      symbol->st_value += base_address;
-    }
-  }
-  return true;
-}
-
-bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) {
-  for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
-    CHECK(sh != nullptr);
-    if (sh->sh_type == SHT_REL) {
-      for (uint32_t i = 0; i < elf_file.GetRelNum(*sh); i++) {
-        Elf32_Rel& rel = elf_file.GetRel(*sh, i);
-        if (DEBUG_FIXUP) {
-          LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                    elf_file.GetFile().GetPath().c_str(), i,
-                                    rel.r_offset, rel.r_offset + base_address);
-        }
-        rel.r_offset += base_address;
-      }
-    } else if (sh->sh_type == SHT_RELA) {
-      for (uint32_t i = 0; i < elf_file.GetRelaNum(*sh); i++) {
-        Elf32_Rela& rela = elf_file.GetRela(*sh, i);
-        if (DEBUG_FIXUP) {
-          LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR,
-                                    elf_file.GetFile().GetPath().c_str(), i,
-                                    rela.r_offset, rela.r_offset + base_address);
-        }
-        rela.r_offset += base_address;
-      }
-    }
-  }
-  return true;
-}
-
-}  // namespace art
diff --git a/compiler/elf_fixup.h b/compiler/elf_fixup.h
deleted file mode 100644
index 1abf06b..0000000
--- a/compiler/elf_fixup.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_ELF_FIXUP_H_
-#define ART_COMPILER_ELF_FIXUP_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "os.h"
-
-namespace art {
-
-class ElfFile;
-
-class ElfFixup {
- public:
-  // Fixup an ELF file so that that oat header will be loaded at oat_begin.
-  // Returns true on success, false on failure.
-  static bool Fixup(File* file, uintptr_t oat_data_begin);
-
- private:
-  // Fixup .dynamic d_ptr values for the expected base_address.
-  static bool FixupDynamic(ElfFile& elf_file, uintptr_t base_address);
-
-  // Fixup Elf32_Shdr p_vaddr to load at the desired address.
-  static bool FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address);
-
-  // Fixup Elf32_Phdr p_vaddr to load at the desired address.
-  static bool FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address);
-
-  // Fixup symbol table
-  static bool FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic);
-
-  // Fixup dynamic relocations
-  static bool FixupRelocations(ElfFile& elf_file, uintptr_t base_address);
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfFixup);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_FIXUP_H_
diff --git a/compiler/elf_stripper.cc b/compiler/elf_stripper.cc
deleted file mode 100644
index 457d8a0..0000000
--- a/compiler/elf_stripper.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "elf_stripper.h"
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <memory>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/stringprintf.h"
-#include "elf_file.h"
-#include "elf_utils.h"
-#include "utils.h"
-
-namespace art {
-
-bool ElfStripper::Strip(File* file, std::string* error_msg) {
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg));
-  if (elf_file.get() == nullptr) {
-    return false;
-  }
-
-  // ELF files produced by MCLinker look roughly like this
-  //
-  // +------------+
-  // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first
-  // +------------+
-  // | Elf32_Phdr | program headers
-  // | Elf32_Phdr |
-  // | ...        |
-  // | Elf32_Phdr |
-  // +------------+
-  // | section    | mixture of needed and unneeded sections
-  // +------------+
-  // | section    |
-  // +------------+
-  // | ...        |
-  // +------------+
-  // | section    |
-  // +------------+
-  // | Elf32_Shdr | section headers
-  // | Elf32_Shdr |
-  // | ...        | contains offset to section start
-  // | Elf32_Shdr |
-  // +------------+
-  //
-  // To strip:
-  // - leave the Elf32_Ehdr and Elf32_Phdr values in place.
-  // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep
-  // - move the sections are keeping up to fill in gaps of sections we want to strip
-  // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr
-  // - truncate rest of file
-  //
-
-  std::vector<Elf32_Shdr> section_headers;
-  std::vector<Elf32_Word> section_headers_original_indexes;
-  section_headers.reserve(elf_file->GetSectionHeaderNum());
-
-
-  Elf32_Shdr* string_section = elf_file->GetSectionNameStringSection();
-  CHECK(string_section != nullptr);
-  for (Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* sh = elf_file->GetSectionHeader(i);
-    CHECK(sh != nullptr);
-    const char* name = elf_file->GetString(*string_section, sh->sh_name);
-    if (name == nullptr) {
-      CHECK_EQ(0U, i);
-      section_headers.push_back(*sh);
-      section_headers_original_indexes.push_back(0);
-      continue;
-    }
-    if (StartsWith(name, ".debug")
-        || (strcmp(name, ".strtab") == 0)
-        || (strcmp(name, ".symtab") == 0)) {
-      continue;
-    }
-    section_headers.push_back(*sh);
-    section_headers_original_indexes.push_back(i);
-  }
-  CHECK_NE(0U, section_headers.size());
-  CHECK_EQ(section_headers.size(), section_headers_original_indexes.size());
-
-  // section 0 is the NULL section, sections start at offset of first section
-  CHECK(elf_file->GetSectionHeader(1) != nullptr);
-  Elf32_Off offset = elf_file->GetSectionHeader(1)->sh_offset;
-  for (size_t i = 1; i < section_headers.size(); i++) {
-    Elf32_Shdr& new_sh = section_headers[i];
-    Elf32_Shdr* old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]);
-    CHECK(old_sh != nullptr);
-    CHECK_EQ(new_sh.sh_name, old_sh->sh_name);
-    if (old_sh->sh_addralign > 1) {
-      offset = RoundUp(offset, old_sh->sh_addralign);
-    }
-    if (old_sh->sh_offset == offset) {
-      // already in place
-      offset += old_sh->sh_size;
-      continue;
-    }
-    // shift section earlier
-    memmove(elf_file->Begin() + offset,
-            elf_file->Begin() + old_sh->sh_offset,
-            old_sh->sh_size);
-    new_sh.sh_offset = offset;
-    offset += old_sh->sh_size;
-  }
-
-  Elf32_Off shoff = offset;
-  size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf32_Shdr);
-  memcpy(elf_file->Begin() + offset, &section_headers[0], section_headers_size_in_bytes);
-  offset += section_headers_size_in_bytes;
-
-  elf_file->GetHeader().e_shnum = section_headers.size();
-  elf_file->GetHeader().e_shoff = shoff;
-  int result = ftruncate(file->Fd(), offset);
-  if (result != 0) {
-    *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s",
-                              file->GetPath().c_str(), strerror(errno));
-    return false;
-  }
-  return true;
-}
-
-}  // namespace art
diff --git a/compiler/elf_stripper.h b/compiler/elf_stripper.h
deleted file mode 100644
index f1a1d46..0000000
--- a/compiler/elf_stripper.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_ELF_STRIPPER_H_
-#define ART_COMPILER_ELF_STRIPPER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "os.h"
-
-namespace art {
-
-class ElfStripper {
- public:
-  // Strip an ELF file of unneeded debugging information.
-  // Returns true on success, false on failure.
-  static bool Strip(File* file, std::string* error_msg);
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfStripper);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_STRIPPER_H_
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 55ee18e..47402f3 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -30,8 +30,8 @@
 
 namespace art {
 
-uint32_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
-  Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
+uintptr_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
+  uintptr_t oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
                                                            "oatdata",
                                                            false);
   CHECK_NE(0U, oatdata_address);
@@ -51,4 +51,16 @@
   CHECK_NE(0U, oat_data_offset);
 }
 
+bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
+  std::string error_msg;
+  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
+  CHECK(elf_file.get() != nullptr) << error_msg;
+
+  // Lookup "oatdata" symbol address.
+  uintptr_t oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
+  uintptr_t base_address = oat_data_begin - oatdata_address;
+
+  return elf_file->Fixup(base_address);
+}
+
 }  // namespace art
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 03b965a..033c1f8 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -42,7 +42,9 @@
                                    size_t& oat_data_offset);
 
   // Returns runtime oat_data runtime address for an opened ElfFile.
-  static uint32_t GetOatDataAddress(ElfFile* elf_file);
+  static uintptr_t GetOatDataAddress(ElfFile* elf_file);
+
+  static bool Fixup(File* file, uintptr_t oat_data_begin);
 
  protected:
   ElfWriter(const CompilerDriver& driver, File* elf_file)
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
deleted file mode 100644
index f017641..0000000
--- a/compiler/elf_writer_mclinker.cc
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "elf_writer_mclinker.h"
-
-#include <llvm/Support/ELF.h>
-#include <llvm/Support/TargetSelect.h>
-
-#include <mcld/Environment.h>
-#include <mcld/IRBuilder.h>
-#include <mcld/Linker.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/LinkerScript.h>
-#include <mcld/MC/ZOption.h>
-#include <mcld/Module.h>
-#include <mcld/Support/Path.h>
-#include <mcld/Support/TargetSelect.h>
-
-#include "base/unix_file/fd_file.h"
-#include "class_linker.h"
-#include "dex_method_iterator.h"
-#include "driver/compiler_driver.h"
-#include "elf_file.h"
-#include "globals.h"
-#include "mirror/art_method.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-#include "oat_writer.h"
-#include "scoped_thread_state_change.h"
-#include "vector_output_stream.h"
-
-namespace art {
-
-ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
-  : ElfWriter(driver, elf_file), oat_input_(nullptr) {
-}
-
-ElfWriterMclinker::~ElfWriterMclinker() {
-}
-
-bool ElfWriterMclinker::Create(File* elf_file,
-                               OatWriter* oat_writer,
-                               const std::vector<const DexFile*>& dex_files,
-                               const std::string& android_root,
-                               bool is_host,
-                               const CompilerDriver& driver) {
-  ElfWriterMclinker elf_writer(driver, elf_file);
-  return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
-}
-
-bool ElfWriterMclinker::Write(OatWriter* oat_writer,
-                              const std::vector<const DexFile*>& dex_files,
-                              const std::string& android_root,
-                              bool is_host) {
-  std::vector<uint8_t> oat_contents;
-  oat_contents.reserve(oat_writer->GetSize());
-
-  Init();
-  mcld::LDSection* oat_section = AddOatInput(oat_writer, &oat_contents);
-  if (kUsePortableCompiler) {
-    AddMethodInputs(dex_files);
-    AddRuntimeInputs(android_root, is_host);
-  }
-
-  // link inputs
-  if (!linker_->link(*module_.get(), *ir_builder_.get())) {
-    LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
-    return false;
-  }
-
-  // Fill oat_contents.
-  VectorOutputStream output_stream("oat contents", oat_contents);
-  oat_writer->SetOatDataOffset(oat_section->offset());
-  CHECK(oat_writer->Write(&output_stream));
-  CHECK_EQ(oat_writer->GetSize(), oat_contents.size());
-
-  // emit linked output
-  // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd.
-  int fd = dup(elf_file_->Fd());
-  if (fd == -1) {
-    PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!linker_->emit(*module_.get(), fd)) {
-    LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
-    return false;
-  }
-  mcld::Finalize();
-  LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
-
-  oat_contents.clear();
-  if (kUsePortableCompiler) {
-    FixupOatMethodOffsets(dex_files);
-  }
-  return true;
-}
-
-static void InitializeLLVM() {
-  // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
-  if (kIsTargetBuild) {
-    llvm::InitializeNativeTarget();
-    // TODO: odd that there is no InitializeNativeTargetMC?
-  } else {
-    llvm::InitializeAllTargets();
-    llvm::InitializeAllTargetMCs();
-  }
-}
-
-void ElfWriterMclinker::Init() {
-  std::string target_triple;
-  std::string target_cpu;
-  std::string target_attr;
-  CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
-                                             &target_triple,
-                                             &target_cpu,
-                                             &target_attr);
-
-  // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
-  //
-  // TODO: LinkerTest uses mcld::Initialize(), but it does an
-  // llvm::InitializeAllTargets, which we don't want. Basically we
-  // want mcld::InitializeNative, but it doesn't exist yet, so we
-  // inline the minimal we need here.
-  InitializeLLVM();
-  mcld::InitializeAllTargets();
-  mcld::InitializeAllLinkers();
-  mcld::InitializeAllEmulations();
-  mcld::InitializeAllDiagnostics();
-
-  linker_config_.reset(new mcld::LinkerConfig(target_triple));
-  CHECK(linker_config_.get() != NULL);
-  linker_config_->setCodeGenType(mcld::LinkerConfig::DynObj);
-  linker_config_->options().setSOName(elf_file_->GetPath());
-
-  // error on undefined symbols.
-  // TODO: should this just be set if kIsDebugBuild?
-  linker_config_->options().setNoUndefined(true);
-
-  if (compiler_driver_->GetInstructionSet() == kMips) {
-     // MCLinker defaults MIPS section alignment to 0x10000, not
-     // 0x1000.  The ABI says this is because the max page size is
-     // general is 64k but that isn't true on Android.
-     mcld::ZOption z_option;
-     z_option.setKind(mcld::ZOption::MaxPageSize);
-     z_option.setPageSize(kPageSize);
-     linker_config_->options().addZOption(z_option);
-  }
-
-  // TODO: Wire up mcld DiagnosticEngine to LOG?
-  linker_config_->options().setColor(false);
-  if (false) {
-    // enables some tracing of input file processing
-    linker_config_->options().setTrace(true);
-  }
-
-  // Based on alone::Linker::config
-  linker_script_.reset(new mcld::LinkerScript());
-  module_.reset(new mcld::Module(linker_config_->options().soname(), *linker_script_.get()));
-  CHECK(module_.get() != NULL);
-  ir_builder_.reset(new mcld::IRBuilder(*module_.get(), *linker_config_.get()));
-  CHECK(ir_builder_.get() != NULL);
-  linker_.reset(new mcld::Linker());
-  CHECK(linker_.get() != NULL);
-  linker_->emulate(*linker_script_.get(), *linker_config_.get());
-}
-
-mcld::LDSection* ElfWriterMclinker::AddOatInput(OatWriter* oat_writer,
-                                                std::vector<uint8_t>* oat_contents) {
-  // NOTE: oat_contents has sufficient reserved space but it doesn't contain the data yet.
-  const char* oat_data_start = reinterpret_cast<const char*>(&(*oat_contents)[0]);
-  const size_t oat_data_length = oat_writer->GetOatHeader().GetExecutableOffset();
-  const char* oat_code_start = oat_data_start + oat_data_length;
-  const size_t oat_code_length = oat_writer->GetSize() - oat_data_length;
-
-  // TODO: ownership of oat_input?
-  oat_input_ = ir_builder_->CreateInput("oat contents",
-                                        mcld::sys::fs::Path("oat contents path"),
-                                        mcld::Input::Object);
-  CHECK(oat_input_ != NULL);
-
-  // TODO: ownership of null_section?
-  mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_,
-                                                               "",
-                                                               mcld::LDFileFormat::Null,
-                                                               SHT_NULL,
-                                                               0);
-  CHECK(null_section != NULL);
-
-  // TODO: we should split readonly data from readonly executable
-  // code like .oat does.  We need to control section layout with
-  // linker script like functionality to guarantee references
-  // between sections maintain relative position which isn't
-  // possible right now with the mclinker APIs.
-  CHECK(oat_code_start != NULL);
-
-  // we need to ensure that oatdata is page aligned so when we
-  // fixup the segment load addresses, they remain page aligned.
-  uint32_t alignment = kPageSize;
-
-  // TODO: ownership of text_section?
-  mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_,
-                                                               ".text",
-                                                               SHT_PROGBITS,
-                                                               SHF_EXECINSTR | SHF_ALLOC,
-                                                               alignment);
-  CHECK(text_section != NULL);
-
-  mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section);
-  CHECK(text_sectiondata != NULL);
-
-  // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
-  mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start),
-                                                            oat_writer->GetSize());
-  CHECK(text_fragment != NULL);
-  ir_builder_->AppendFragment(*text_fragment, *text_sectiondata);
-
-  ir_builder_->AddSymbol(*oat_input_,
-                         "oatdata",
-                         mcld::ResolveInfo::Object,
-                         mcld::ResolveInfo::Define,
-                         mcld::ResolveInfo::Global,
-                         oat_data_length,  // size
-                         0,                // offset
-                         text_section);
-
-  ir_builder_->AddSymbol(*oat_input_,
-                         "oatexec",
-                         mcld::ResolveInfo::Function,
-                         mcld::ResolveInfo::Define,
-                         mcld::ResolveInfo::Global,
-                         oat_code_length,  // size
-                         oat_data_length,  // offset
-                         text_section);
-
-  ir_builder_->AddSymbol(*oat_input_,
-                         "oatlastword",
-                         mcld::ResolveInfo::Object,
-                         mcld::ResolveInfo::Define,
-                         mcld::ResolveInfo::Global,
-                         0,                // size
-                         // subtract a word so symbol is within section
-                         (oat_data_length + oat_code_length) - sizeof(uint32_t),  // offset
-                         text_section);
-
-  return text_section;
-}
-
-void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
-  DCHECK(oat_input_ != NULL);
-
-  DexMethodIterator it(dex_files);
-  while (it.HasNext()) {
-    const DexFile& dex_file = it.GetDexFile();
-    uint32_t method_idx = it.GetMemberIndex();
-    const CompiledMethod* compiled_method =
-      compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
-    if (compiled_method != NULL) {
-      AddCompiledCodeInput(*compiled_method);
-    }
-    it.Next();
-  }
-  added_symbols_.clear();
-}
-
-void ElfWriterMclinker::AddCompiledCodeInput(const CompiledCode& compiled_code) {
-  // Check if we've seen this compiled code before. If so skip
-  // it. This can happen for reused code such as invoke stubs.
-  const std::string& symbol = compiled_code.GetSymbol();
-  SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol);
-  if (it != added_symbols_.end()) {
-    return;
-  }
-  added_symbols_.Put(&symbol, &symbol);
-
-  // Add input to supply code for symbol
-  const std::vector<uint8_t>* code = compiled_code.GetPortableCode();
-  // TODO: ownership of code_input?
-  // TODO: why does IRBuilder::ReadInput take a non-const pointer?
-  mcld::Input* code_input = ir_builder_->ReadInput(symbol,
-                                                   const_cast<uint8_t*>(&(*code)[0]),
-                                                   code->size());
-  CHECK(code_input != NULL);
-}
-
-void ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool is_host) {
-  std::string libart_so(android_root);
-  libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so";
-  // TODO: ownership of libart_so_input?
-  mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so);
-  CHECK(libart_so_input != NULL);
-
-  std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6");
-
-  std::string compiler_runtime_lib;
-  if (is_host) {
-    compiler_runtime_lib += host_prebuilt_dir;
-    compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a";
-  } else {
-    compiler_runtime_lib += android_root;
-    compiler_runtime_lib += "/lib/libcompiler_rt.a";
-  }
-  // TODO: ownership of compiler_runtime_lib_input?
-  mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib,
-                                                                   compiler_runtime_lib);
-  CHECK(compiler_runtime_lib_input != NULL);
-
-  std::string libc_lib;
-  if (is_host) {
-    libc_lib += host_prebuilt_dir;
-    libc_lib += "/sysroot/usr/lib/libc.so.6";
-  } else {
-    libc_lib += android_root;
-    libc_lib += "/lib/libc.so";
-  }
-  // TODO: ownership of libc_lib_input?
-  mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib);
-  CHECK(libc_lib_input_input != NULL);
-
-  std::string libm_lib;
-  if (is_host) {
-    libm_lib += host_prebuilt_dir;
-    libm_lib += "/sysroot/usr/lib/libm.so";
-  } else {
-    libm_lib += android_root;
-    libm_lib += "/lib/libm.so";
-  }
-  // TODO: ownership of libm_lib_input?
-  mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
-  CHECK(libm_lib_input_input != NULL);
-}
-
-void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
-  std::string error_msg;
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
-  CHECK(elf_file.get() != NULL) << elf_file_->GetPath() << ": " << error_msg;
-
-  uint32_t oatdata_address = GetOatDataAddress(elf_file.get());
-  DexMethodIterator it(dex_files);
-  while (it.HasNext()) {
-    const DexFile& dex_file = it.GetDexFile();
-    uint32_t method_idx = it.GetMemberIndex();
-    InvokeType invoke_type = it.GetInvokeType();
-    mirror::ArtMethod* method = NULL;
-    if (compiler_driver_->IsImage()) {
-      ClassLinker* linker = Runtime::Current()->GetClassLinker();
-      // Unchecked as we hold mutator_lock_ on entry.
-      ScopedObjectAccessUnchecked soa(Thread::Current());
-      StackHandleScope<1> hs(soa.Self());
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(dex_file)));
-      method = linker->ResolveMethod(dex_file, method_idx, dex_cache,
-                                     NullHandle<mirror::ClassLoader>(),
-                                     NullHandle<mirror::ArtMethod>(), invoke_type);
-      CHECK(method != NULL);
-    }
-    const CompiledMethod* compiled_method =
-      compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
-    if (compiled_method != NULL) {
-      uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method);
-      // Don't overwrite static method trampoline
-      if (method != NULL &&
-          (!method->IsStatic() ||
-           method->IsConstructor() ||
-           method->GetDeclaringClass()->IsInitialized())) {
-        method->SetPortableOatCodeOffset(offset);
-      }
-    }
-    it.Next();
-  }
-  symbol_to_compiled_code_offset_.clear();
-}
-
-uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
-                                                    Elf32_Addr oatdata_address,
-                                                    const CompiledCode& compiled_code) {
-  const std::string& symbol = compiled_code.GetSymbol();
-  SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol);
-  if (it != symbol_to_compiled_code_offset_.end()) {
-    return it->second;
-  }
-
-  Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(SHT_SYMTAB,
-                                                                symbol,
-                                                                true);
-  CHECK_NE(0U, compiled_code_address) << symbol;
-  CHECK_LT(oatdata_address, compiled_code_address) << symbol;
-  uint32_t compiled_code_offset = compiled_code_address - oatdata_address;
-  symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset);
-
-  const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset();
-  for (uint32_t i = 0; i < offsets.size(); i++) {
-    uint32_t oatdata_offset = oatdata_address + offsets[i];
-    uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset);
-    *addr = compiled_code_offset;
-  }
-  return compiled_code_offset;
-}
-
-}  // namespace art
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
deleted file mode 100644
index 489fefb..0000000
--- a/compiler/elf_writer_mclinker.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_ELF_WRITER_MCLINKER_H_
-#define ART_COMPILER_ELF_WRITER_MCLINKER_H_
-
-#include <memory>
-
-#include "elf_writer.h"
-#include "safe_map.h"
-
-namespace mcld {
-class IRBuilder;
-class Input;
-class LDSection;
-class LDSymbol;
-class Linker;
-class LinkerConfig;
-class LinkerScript;
-class Module;
-}  // namespace mcld
-
-namespace art {
-
-class CompiledCode;
-
-class ElfWriterMclinker FINAL : public ElfWriter {
- public:
-  // Write an ELF file. Returns true on success, false on failure.
-  static bool Create(File* file,
-                     OatWriter* oat_writer,
-                     const std::vector<const DexFile*>& dex_files,
-                     const std::string& android_root,
-                     bool is_host,
-                     const CompilerDriver& driver)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- protected:
-  bool Write(OatWriter* oat_writer,
-             const std::vector<const DexFile*>& dex_files,
-             const std::string& android_root,
-             bool is_host)
-      OVERRIDE
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
-  ElfWriterMclinker(const CompilerDriver& driver, File* elf_file);
-  ~ElfWriterMclinker();
-
-  void Init();
-  mcld::LDSection* AddOatInput(OatWriter* oat_writer, std::vector<uint8_t>* oat_contents);
-  void AddMethodInputs(const std::vector<const DexFile*>& dex_files);
-  void AddCompiledCodeInput(const CompiledCode& compiled_code);
-  void AddRuntimeInputs(const std::string& android_root, bool is_host);
-  void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
-                                   uint32_t oatdata_address,
-                                   const CompiledCode& compiled_code);
-
-  // Setup by Init()
-  std::unique_ptr<mcld::LinkerConfig> linker_config_;
-  std::unique_ptr<mcld::LinkerScript> linker_script_;
-  std::unique_ptr<mcld::Module> module_;
-  std::unique_ptr<mcld::IRBuilder> ir_builder_;
-  std::unique_ptr<mcld::Linker> linker_;
-
-  // Setup by AddOatInput()
-  // TODO: ownership of oat_input_?
-  mcld::Input* oat_input_;
-
-  // Setup by AddCompiledCodeInput
-  // set of symbols for already added mcld::Inputs
-  SafeMap<const std::string*, const std::string*> added_symbols_;
-
-  // Setup by FixupCompiledCodeOffset
-  // map of symbol names to oatdata offset
-  SafeMap<const std::string*, uint32_t> symbol_to_compiled_code_offset_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterMclinker);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_WRITER_MCLINKER_H_
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index e661324..9ec4f28 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -195,7 +195,7 @@
   }
 }
 
-class OatWriterWrapper : public CodeOutput {
+class OatWriterWrapper FINAL : public CodeOutput {
  public:
   explicit OatWriterWrapper(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
 
@@ -206,7 +206,7 @@
     return oat_writer_->Write(out);
   }
  private:
-  OatWriter* oat_writer_;
+  OatWriter* const oat_writer_;
 };
 
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
@@ -222,9 +222,9 @@
           typename Elf_Phdr, typename Elf_Shdr>
 bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
   Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>::Write(OatWriter* oat_writer,
-                           const std::vector<const DexFile*>& dex_files_unused,
-                           const std::string& android_root_unused,
-                           bool is_host_unused) {
+                           const std::vector<const DexFile*>& dex_files_unused ATTRIBUTE_UNUSED,
+                           const std::string& android_root_unused ATTRIBUTE_UNUSED,
+                           bool is_host_unused ATTRIBUTE_UNUSED) {
   constexpr bool debug = false;
   const OatHeader& oat_header = oat_writer->GetOatHeader();
   Elf_Word oat_data_size = oat_header.GetExecutableOffset();
@@ -358,8 +358,8 @@
 };
 
 // TODO: rewriting it using DexFile::DecodeDebugInfo needs unneeded stuff.
-static void GetLineInfoForJava(const uint8_t* dbgstream, const SrcMap& pc2dex,
-                               SrcMap* result, uint32_t start_pc = 0) {
+static void GetLineInfoForJava(const uint8_t* dbgstream, const SwapSrcMap& pc2dex,
+                               DefaultSrcMap* result, uint32_t start_pc = 0) {
   if (dbgstream == nullptr) {
     return;
   }
@@ -415,7 +415,7 @@
       dex_offset += adjopcode / DexFile::DBG_LINE_RANGE;
       java_line += DexFile::DBG_LINE_BASE + (adjopcode % DexFile::DBG_LINE_RANGE);
 
-      for (SrcMap::const_iterator found = pc2dex.FindByTo(dex_offset);
+      for (SwapSrcMap::const_iterator found = pc2dex.FindByTo(dex_offset);
           found != pc2dex.end() && found->to_ == static_cast<int32_t>(dex_offset);
           found++) {
         result->push_back({found->from_ + start_pc, static_cast<int32_t>(java_line)});
@@ -615,7 +615,7 @@
     LineTableGenerator line_table_generator(LINE_BASE, LINE_RANGE, OPCODE_BASE,
                                             dbg_line, 0, 1);
 
-    SrcMap pc2java_map;
+    DefaultSrcMap pc2java_map;
     for (size_t i = 0; i < method_info.size(); ++i) {
       const OatWriter::DebugInfo &dbg = method_info[i];
       const char* file_name = (dbg.src_file_name_ == nullptr) ? "null" : dbg.src_file_name_;
@@ -669,6 +669,8 @@
 template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
           typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr,
           typename Elf_Phdr, typename Elf_Shdr>
+// Do not inline to avoid Clang stack frame problems. b/18738594
+NO_INLINE
 static void WriteDebugSymbols(const CompilerDriver* compiler_driver,
                               ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
                                          Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder,
@@ -676,22 +678,29 @@
   std::unique_ptr<std::vector<uint8_t>> cfi_info(
       ConstructCIEFrame(compiler_driver->GetInstructionSet()));
 
-  Elf_Addr text_section_address = builder->text_builder_.section_.sh_addr;
+  Elf_Addr text_section_address = builder->GetTextBuilder().GetSection()->sh_addr;
 
   // Iterate over the compiled methods.
   const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo();
-  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr,
-                   Elf_Sym, Elf_Shdr>* symtab = &builder->symtab_builder_;
+  ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr>* symtab =
+      builder->GetSymtabBuilder();
   for (auto it = method_info.begin(); it != method_info.end(); ++it) {
-    symtab->AddSymbol(it->method_name_, &builder->text_builder_, it->low_pc_, true,
+    symtab->AddSymbol(it->method_name_, &builder->GetTextBuilder(), it->low_pc_, true,
                       it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC);
 
+    // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
+    // instructions, so that disassembler tools can correctly disassemble.
+    if (it->compiled_method_->GetInstructionSet() == kThumb2) {
+      symtab->AddSymbol("$t", &builder->GetTextBuilder(), it->low_pc_ & ~1, true,
+                        0, STB_LOCAL, STT_NOTYPE);
+    }
+
     // Include CFI for compiled method, if possible.
     if (cfi_info.get() != nullptr) {
       DCHECK(it->compiled_method_ != nullptr);
 
       // Copy in the FDE, if present
-      const std::vector<uint8_t>* fde = it->compiled_method_->GetCFIInfo();
+      const SwapVector<uint8_t>* fde = it->compiled_method_->GetCFIInfo();
       if (fde != nullptr) {
         // Copy the information into cfi_info and then fix the address in the new copy.
         int cur_offset = cfi_info->size();
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index e479322..fd3a912 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"
@@ -45,15 +46,12 @@
     EXPECT_EQ(expected_value, ef->FindDynamicSymbolAddress(symbol_name)); \
   } while (false)
 
+#if defined(ART_USE_OPTIMIZING_COMPILER)
+TEST_F(ElfWriterTest, DISABLED_dlsym) {
+#else
 TEST_F(ElfWriterTest, dlsym) {
-  std::string elf_location;
-  if (IsHost()) {
-    const char* host_dir = getenv("ANDROID_HOST_OUT");
-    CHECK(host_dir != NULL);
-    elf_location = StringPrintf("%s/framework/core.oat", host_dir);
-  } else {
-    elf_location = "/data/art-test/core.oat";
-  }
+#endif
+  std::string elf_location = GetCoreOatLocation();
   std::string elf_filename = GetSystemImageFilename(elf_location.c_str(), kRuntimeISA);
   LOG(INFO) << "elf_filename=" << elf_filename;
 
@@ -62,28 +60,6 @@
   void* dl_oatexec = NULL;
   void* dl_oatlastword = NULL;
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-  {
-    // We only use dlopen for loading with portable. See OatFile::Open.
-    void* dl_oat_so = dlopen(elf_filename.c_str(), RTLD_NOW);
-    ASSERT_TRUE(dl_oat_so != NULL) << dlerror();
-    dl_oatdata = dlsym(dl_oat_so, "oatdata");
-    ASSERT_TRUE(dl_oatdata != NULL);
-
-    OatHeader* dl_oat_header = reinterpret_cast<OatHeader*>(dl_oatdata);
-    ASSERT_TRUE(dl_oat_header->IsValid());
-    dl_oatexec = dlsym(dl_oat_so, "oatexec");
-    ASSERT_TRUE(dl_oatexec != NULL);
-    ASSERT_LT(dl_oatdata, dl_oatexec);
-
-    dl_oatlastword = dlsym(dl_oat_so, "oatlastword");
-    ASSERT_TRUE(dl_oatlastword != NULL);
-    ASSERT_LT(dl_oatexec, dl_oatlastword);
-
-    ASSERT_EQ(0, dlclose(dl_oat_so));
-  }
-#endif
-
   std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
   ASSERT_TRUE(file.get() != NULL);
   {
diff --git a/compiler/file_output_stream.h b/compiler/file_output_stream.h
index 76b00fe..9dfbd7f 100644
--- a/compiler/file_output_stream.h
+++ b/compiler/file_output_stream.h
@@ -23,7 +23,7 @@
 
 namespace art {
 
-class FileOutputStream : public OutputStream {
+class FileOutputStream FINAL : public OutputStream {
  public:
   explicit FileOutputStream(File* file);
 
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 2a37049..cf97943 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -23,7 +23,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "common_compiler_test.h"
-#include "elf_fixup.h"
+#include "elf_writer.h"
 #include "gc/space/image_space.h"
 #include "image_writer.h"
 #include "lock_word.h"
@@ -63,18 +63,15 @@
   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,
+                                                      /*compile_pic*/false));
+  // TODO: compile_pic should be a test argument.
   {
     {
       jobject class_loader = NULL;
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       TimingLogger timings("ImageTest::WriteRead", false, false);
       TimingLogger::ScopedTiming t("CompileAll", &timings);
-      if (kUsePortableCompiler) {
-        // TODO: we disable this for portable so the test executes in a reasonable amount of time.
-        //       We shouldn't need to do this.
-        compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
-      }
       for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
         dex_file->EnableWrite();
       }
@@ -83,8 +80,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,17 +96,20 @@
 
   {
     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 = ElfFixup::Fixup(dup_oat.get(), writer.GetOatDataBegin());
+    bool success_fixup = ElfWriter::Fixup(dup_oat.get(), writer->GetOatDataBegin());
     ASSERT_TRUE(success_fixup);
+
+    ASSERT_EQ(dup_oat->FlushCloseOrErase(), 0) << "Could not flush and close oat file "
+                                               << oat_file.GetFilename();
   }
 
   {
     std::unique_ptr<File> file(OS::OpenFileForReading(image_file.GetFilename().c_str()));
     ASSERT_TRUE(file.get() != NULL);
     ImageHeader image_header;
-    file->ReadFully(&image_header, sizeof(image_header));
+    ASSERT_EQ(file->ReadFully(&image_header, sizeof(image_header)), true);
     ASSERT_TRUE(image_header.IsValid());
     ASSERT_GE(image_header.GetImageBitmapOffset(), sizeof(image_header));
     ASSERT_NE(0U, image_header.GetImageBitmapSize());
@@ -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());
@@ -163,8 +167,8 @@
 
   gc::space::ImageSpace* image_space = heap->GetImageSpace();
   image_space->VerifyImageAllocations();
-  byte* image_begin = image_space->Begin();
-  byte* image_end = image_space->End();
+  uint8_t* image_begin = image_space->Begin();
+  uint8_t* image_end = image_space->End();
   CHECK_EQ(requested_image_base, reinterpret_cast<uintptr_t>(image_begin));
   for (size_t i = 0; i < dex->NumClassDefs(); ++i) {
     const DexFile::ClassDef& class_def = dex->GetClassDef(i);
@@ -173,11 +177,11 @@
     EXPECT_TRUE(klass != nullptr) << descriptor;
     if (image_classes.find(descriptor) != image_classes.end()) {
       // Image classes should be located inside the image.
-      EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
-      EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+      EXPECT_LT(image_begin, reinterpret_cast<uint8_t*>(klass)) << descriptor;
+      EXPECT_LT(reinterpret_cast<uint8_t*>(klass), image_end) << descriptor;
     } else {
-      EXPECT_TRUE(reinterpret_cast<byte*>(klass) >= image_end ||
-                  reinterpret_cast<byte*>(klass) < image_begin) << descriptor;
+      EXPECT_TRUE(reinterpret_cast<uint8_t*>(klass) >= image_end ||
+                  reinterpret_cast<uint8_t*>(klass) < image_begin) << descriptor;
     }
     EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord(false)));
   }
@@ -208,7 +212,8 @@
                              oat_file_begin,
                              oat_data_begin,
                              oat_data_end,
-                             oat_file_end);
+                             oat_file_end,
+                             /*compile_pic*/false);
     ASSERT_TRUE(image_header.IsValid());
 
     char* magic = const_cast<char*>(image_header.GetMagic());
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 1c8b8d5..d69447d 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -54,7 +54,8 @@
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
 #include "handle_scope-inl.h"
-#include "utils.h"
+
+#include <numeric>
 
 using ::art::mirror::ArtField;
 using ::art::mirror::ArtMethod;
@@ -67,12 +68,16 @@
 
 namespace art {
 
+// Separate objects into multiple bins to optimize dirty memory use.
+static constexpr bool kBinObjects = true;
+
 bool ImageWriter::PrepareImageAddressSpace() {
+  target_ptr_size_ = InstructionSetPointerSize(compiler_driver_.GetInstructionSet());
   {
     Thread::Current()->TransitionFromSuspendedToRunnable();
     PruneNonImageClasses();  // Remove junk
     ComputeLazyFieldsForImageClasses();  // Add useful information
-    ComputeEagerResolvedStrings();
+    ProcessStrings();
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   }
   gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -103,13 +108,13 @@
 
   std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
   if (oat_file.get() == NULL) {
-    LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location;
+    PLOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location;
     return false;
   }
   std::string error_msg;
   oat_file_ = OatFile::OpenReadable(oat_file.get(), oat_location, &error_msg);
   if (oat_file_ == nullptr) {
-    LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location
+    PLOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location
         << ": " << error_msg;
     return false;
   }
@@ -122,13 +127,6 @@
 
   jni_dlsym_lookup_offset_ = oat_file_->GetOatHeader().GetJniDlsymLookupOffset();
 
-  portable_imt_conflict_trampoline_offset_ =
-      oat_file_->GetOatHeader().GetPortableImtConflictTrampolineOffset();
-  portable_resolution_trampoline_offset_ =
-      oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset();
-  portable_to_interpreter_bridge_offset_ =
-      oat_file_->GetOatHeader().GetPortableToInterpreterBridgeOffset();
-
   quick_generic_jni_trampoline_offset_ =
       oat_file_->GetOatHeader().GetQuickGenericJniTrampolineOffset();
   quick_imt_conflict_trampoline_offset_ =
@@ -149,6 +147,11 @@
 
   SetOatChecksumFromElfFile(oat_file.get());
 
+  if (oat_file->FlushCloseOrErase() != 0) {
+    LOG(ERROR) << "Failed to flush and close oat file " << oat_filename << " for " << oat_location;
+    return false;
+  }
+
   std::unique_ptr<File> image_file(OS::CreateEmptyFile(image_filename.c_str()));
   ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
   if (image_file.get() == NULL) {
@@ -157,6 +160,7 @@
   }
   if (fchmod(image_file->Fd(), 0644) != 0) {
     PLOG(ERROR) << "Failed to make image file world readable: " << image_filename;
+    image_file->Erase();
     return EXIT_FAILURE;
   }
 
@@ -164,6 +168,7 @@
   CHECK_EQ(image_end_, image_header->GetImageSize());
   if (!image_file->WriteFully(image_->Begin(), image_end_)) {
     PLOG(ERROR) << "Failed to write image file " << image_filename;
+    image_file->Erase();
     return false;
   }
 
@@ -173,53 +178,54 @@
                          image_header->GetImageBitmapSize(),
                          image_header->GetImageBitmapOffset())) {
     PLOG(ERROR) << "Failed to write image file " << image_filename;
+    image_file->Erase();
     return false;
   }
 
+  if (image_file->FlushCloseOrErase() != 0) {
+    PLOG(ERROR) << "Failed to flush and close image file " << image_filename;
+    return false;
+  }
   return true;
 }
 
-void ImageWriter::SetImageOffset(mirror::Object* object, size_t offset) {
+void ImageWriter::SetImageOffset(mirror::Object* object,
+                                 ImageWriter::BinSlot bin_slot,
+                                 size_t offset) {
   DCHECK(object != nullptr);
   DCHECK_NE(offset, 0U);
-  DCHECK(!IsImageOffsetAssigned(object));
   mirror::Object* obj = reinterpret_cast<mirror::Object*>(image_->Begin() + offset);
   DCHECK_ALIGNED(obj, kObjectAlignment);
-  image_bitmap_->Set(obj);
-  // Before we stomp over the lock word, save the hash code for later.
-  Monitor::Deflate(Thread::Current(), object);;
-  LockWord lw(object->GetLockWord(false));
-  switch (lw.GetState()) {
-    case LockWord::kFatLocked: {
-      LOG(FATAL) << "Fat locked object " << obj << " found during object copy";
-      break;
+
+  image_bitmap_->Set(obj);  // Mark the obj as mutated, since we will end up changing it.
+  {
+    // Remember the object-inside-of-the-image's hash code so we can restore it after the copy.
+    auto hash_it = saved_hashes_map_.find(bin_slot);
+    if (hash_it != saved_hashes_map_.end()) {
+      std::pair<BinSlot, uint32_t> slot_hash = *hash_it;
+      saved_hashes_.push_back(std::make_pair(obj, slot_hash.second));
+      saved_hashes_map_.erase(hash_it);
     }
-    case LockWord::kThinLocked: {
-      LOG(FATAL) << "Thin locked object " << obj << " found during object copy";
-      break;
-    }
-    case LockWord::kUnlocked:
-      // No hash, don't need to save it.
-      break;
-    case LockWord::kHashCode:
-      saved_hashes_.push_back(std::make_pair(obj, lw.GetHashCode()));
-      break;
-    default:
-      LOG(FATAL) << "Unreachable.";
-      break;
   }
+  // The object is already deflated from when we set the bin slot. Just overwrite the lock word.
   object->SetLockWord(LockWord::FromForwardingAddress(offset), false);
   DCHECK(IsImageOffsetAssigned(object));
 }
 
-void ImageWriter::AssignImageOffset(mirror::Object* object) {
+void ImageWriter::AssignImageOffset(mirror::Object* object, ImageWriter::BinSlot bin_slot) {
   DCHECK(object != nullptr);
-  SetImageOffset(object, image_end_);
-  image_end_ += RoundUp(object->SizeOf(), 8);  // 64-bit alignment
-  DCHECK_LT(image_end_, image_->Size());
+  DCHECK_NE(image_objects_offset_begin_, 0u);
+
+  size_t previous_bin_sizes = GetBinSizeSum(bin_slot.GetBin());  // sum sizes in [0..bin#)
+  size_t new_offset = image_objects_offset_begin_ + previous_bin_sizes + bin_slot.GetIndex();
+  DCHECK_ALIGNED(new_offset, kObjectAlignment);
+
+  SetImageOffset(object, bin_slot, new_offset);
+  DCHECK_LT(new_offset, image_end_);
 }
 
 bool ImageWriter::IsImageOffsetAssigned(mirror::Object* object) const {
+  // Will also return true if the bin slot was assigned since we are reusing the lock word.
   DCHECK(object != nullptr);
   return object->GetLockWord(false).GetState() == LockWord::kForwardingAddress;
 }
@@ -233,6 +239,178 @@
   return offset;
 }
 
+void ImageWriter::SetImageBinSlot(mirror::Object* object, BinSlot bin_slot) {
+  DCHECK(object != nullptr);
+  DCHECK(!IsImageOffsetAssigned(object));
+  DCHECK(!IsImageBinSlotAssigned(object));
+
+  // Before we stomp over the lock word, save the hash code for later.
+  Monitor::Deflate(Thread::Current(), object);;
+  LockWord lw(object->GetLockWord(false));
+  switch (lw.GetState()) {
+    case LockWord::kFatLocked: {
+      LOG(FATAL) << "Fat locked object " << object << " found during object copy";
+      break;
+    }
+    case LockWord::kThinLocked: {
+      LOG(FATAL) << "Thin locked object " << object << " found during object copy";
+      break;
+    }
+    case LockWord::kUnlocked:
+      // No hash, don't need to save it.
+      break;
+    case LockWord::kHashCode:
+      saved_hashes_map_[bin_slot] = lw.GetHashCode();
+      break;
+    default:
+      LOG(FATAL) << "Unreachable.";
+      UNREACHABLE();
+  }
+  object->SetLockWord(LockWord::FromForwardingAddress(static_cast<uint32_t>(bin_slot)),
+                      false);
+  DCHECK(IsImageBinSlotAssigned(object));
+}
+
+void ImageWriter::AssignImageBinSlot(mirror::Object* object) {
+  DCHECK(object != nullptr);
+  size_t object_size;
+  if (object->IsArtMethod()) {
+    // Methods are sized based on the target pointer size.
+    object_size = mirror::ArtMethod::InstanceSize(target_ptr_size_);
+  } else {
+    object_size = object->SizeOf();
+  }
+
+  // The magic happens here. We segregate objects into different bins based
+  // on how likely they are to get dirty at runtime.
+  //
+  // Likely-to-dirty objects get packed together into the same bin so that
+  // at runtime their page dirtiness ratio (how many dirty objects a page has) is
+  // maximized.
+  //
+  // This means more pages will stay either clean or shared dirty (with zygote) and
+  // the app will use less of its own (private) memory.
+  Bin bin = kBinRegular;
+
+  if (kBinObjects) {
+    //
+    // Changing the bin of an object is purely a memory-use tuning.
+    // It has no change on runtime correctness.
+    //
+    // Memory analysis has determined that the following types of objects get dirtied
+    // the most:
+    //
+    // * Class'es which are verified [their clinit runs only at runtime]
+    //   - classes in general [because their static fields get overwritten]
+    //   - initialized classes with all-final statics are unlikely to be ever dirty,
+    //     so bin them separately
+    // * Art Methods that are:
+    //   - native [their native entry point is not looked up until runtime]
+    //   - have declaring classes that aren't initialized
+    //            [their interpreter/quick entry points are trampolines until the class
+    //             becomes initialized]
+    //
+    // We also assume the following objects get dirtied either never or extremely rarely:
+    //  * Strings (they are immutable)
+    //  * Art methods that aren't native and have initialized declared classes
+    //
+    // We assume that "regular" bin objects are highly unlikely to become dirtied,
+    // so packing them together will not result in a noticeably tighter dirty-to-clean ratio.
+    //
+    if (object->IsClass()) {
+      bin = kBinClassVerified;
+      mirror::Class* klass = object->AsClass();
+
+      if (klass->GetStatus() == Class::kStatusInitialized) {
+        bin = kBinClassInitialized;
+
+        // If the class's static fields are all final, put it into a separate bin
+        // since it's very likely it will stay clean.
+        uint32_t num_static_fields = klass->NumStaticFields();
+        if (num_static_fields == 0) {
+          bin = kBinClassInitializedFinalStatics;
+        } else {
+          // Maybe all the statics are final?
+          bool all_final = true;
+          for (uint32_t i = 0; i < num_static_fields; ++i) {
+            ArtField* field = klass->GetStaticField(i);
+            if (!field->IsFinal()) {
+              all_final = false;
+              break;
+            }
+          }
+
+          if (all_final) {
+            bin = kBinClassInitializedFinalStatics;
+          }
+        }
+      }
+    } else if (object->IsArtMethod<kVerifyNone>()) {
+      mirror::ArtMethod* art_method = down_cast<ArtMethod*>(object);
+      if (art_method->IsNative()) {
+        bin = kBinArtMethodNative;
+      } else {
+        mirror::Class* declaring_class = art_method->GetDeclaringClass();
+        if (declaring_class->GetStatus() != Class::kStatusInitialized) {
+          bin = kBinArtMethodNotInitialized;
+        } else {
+          // This is highly unlikely to dirty since there's no entry points to mutate.
+          bin = kBinArtMethodsManagedInitialized;
+        }
+      }
+    } else if (object->GetClass<kVerifyNone>()->IsStringClass()) {
+      bin = kBinString;  // Strings are almost always immutable (except for object header).
+    }  // else bin = kBinRegular
+  }
+
+  size_t current_offset = bin_slot_sizes_[bin];  // How many bytes the current bin is at (aligned).
+  // Move the current bin size up to accomodate the object we just assigned a bin slot.
+  size_t offset_delta = RoundUp(object_size, kObjectAlignment);  // 64-bit alignment
+  bin_slot_sizes_[bin] += offset_delta;
+
+  BinSlot new_bin_slot(bin, current_offset);
+  SetImageBinSlot(object, new_bin_slot);
+
+  ++bin_slot_count_[bin];
+
+  DCHECK_LT(GetBinSizeSum(), image_->Size());
+
+  // Grow the image closer to the end by the object we just assigned.
+  image_end_ += offset_delta;
+  DCHECK_LT(image_end_, image_->Size());
+}
+
+bool ImageWriter::IsImageBinSlotAssigned(mirror::Object* object) const {
+  DCHECK(object != nullptr);
+
+  // We always stash the bin slot into a lockword, in the 'forwarding address' state.
+  // If it's in some other state, then we haven't yet assigned an image bin slot.
+  if (object->GetLockWord(false).GetState() != LockWord::kForwardingAddress) {
+    return false;
+  } else if (kIsDebugBuild) {
+    LockWord lock_word = object->GetLockWord(false);
+    size_t offset = lock_word.ForwardingAddress();
+    BinSlot bin_slot(offset);
+    DCHECK_LT(bin_slot.GetIndex(), bin_slot_sizes_[bin_slot.GetBin()])
+      << "bin slot offset should not exceed the size of that bin";
+  }
+  return true;
+}
+
+ImageWriter::BinSlot ImageWriter::GetImageBinSlot(mirror::Object* object) const {
+  DCHECK(object != nullptr);
+  DCHECK(IsImageBinSlotAssigned(object));
+
+  LockWord lock_word = object->GetLockWord(false);
+  size_t offset = lock_word.ForwardingAddress();  // TODO: ForwardingAddress should be uint32_t
+  DCHECK_LE(offset, std::numeric_limits<uint32_t>::max());
+
+  BinSlot bin_slot(static_cast<uint32_t>(offset));
+  DCHECK_LT(bin_slot.GetIndex(), bin_slot_sizes_[bin_slot.GetBin()]);
+
+  return bin_slot;
+}
+
 bool ImageWriter::AllocMemory() {
   size_t length = RoundUp(Runtime::Current()->GetHeap()->GetTotalMemory(), kPageSize);
   std::string error_msg;
@@ -265,7 +443,127 @@
   return true;
 }
 
-void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg) {
+// Count the number of strings in the heap and put the result in arg as a size_t pointer.
+static void CountStringsCallback(Object* obj, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (obj->GetClass()->IsStringClass()) {
+    ++*reinterpret_cast<size_t*>(arg);
+  }
+}
+
+// Collect all the java.lang.String in the heap and put them in the output strings_ array.
+class StringCollector {
+ public:
+  StringCollector(Handle<mirror::ObjectArray<mirror::String>> strings, size_t index)
+      : strings_(strings), index_(index) {
+  }
+  static void Callback(Object* obj, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    auto* collector = reinterpret_cast<StringCollector*>(arg);
+    if (obj->GetClass()->IsStringClass()) {
+      collector->strings_->SetWithoutChecks<false>(collector->index_++, obj->AsString());
+    }
+  }
+  size_t GetIndex() const {
+    return index_;
+  }
+
+ private:
+  Handle<mirror::ObjectArray<mirror::String>> strings_;
+  size_t index_;
+};
+
+// Compare strings based on length, used for sorting strings by length / reverse length.
+class LexicographicalStringComparator {
+ public:
+  bool operator()(const mirror::HeapReference<mirror::String>& lhs,
+                  const mirror::HeapReference<mirror::String>& rhs) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::String* lhs_s = lhs.AsMirrorPtr();
+    mirror::String* rhs_s = rhs.AsMirrorPtr();
+    uint16_t* lhs_begin = lhs_s->GetCharArray()->GetData() + lhs_s->GetOffset();
+    uint16_t* rhs_begin = rhs_s->GetCharArray()->GetData() + rhs_s->GetOffset();
+    return std::lexicographical_compare(lhs_begin, lhs_begin + lhs_s->GetLength(),
+                                        rhs_begin, rhs_begin + rhs_s->GetLength());
+  }
+};
+
+static bool IsPrefix(mirror::String* pref, mirror::String* full)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (pref->GetLength() > full->GetLength()) {
+    return false;
+  }
+  uint16_t* pref_begin = pref->GetCharArray()->GetData() + pref->GetOffset();
+  uint16_t* full_begin = full->GetCharArray()->GetData() + full->GetOffset();
+  return std::equal(pref_begin, pref_begin + pref->GetLength(), full_begin);
+}
+
+void ImageWriter::ProcessStrings() {
+  size_t total_strings = 0;
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  ClassLinker* cl = Runtime::Current()->GetClassLinker();
+  // Count the strings.
+  heap->VisitObjects(CountStringsCallback, &total_strings);
+  Thread* self = Thread::Current();
+  StackHandleScope<1> hs(self);
+  auto strings = hs.NewHandle(cl->AllocStringArray(self, total_strings));
+  StringCollector string_collector(strings, 0U);
+  // Read strings into the array.
+  heap->VisitObjects(StringCollector::Callback, &string_collector);
+  // Some strings could have gotten freed if AllocStringArray caused a GC.
+  CHECK_LE(string_collector.GetIndex(), total_strings);
+  total_strings = string_collector.GetIndex();
+  auto* strings_begin = reinterpret_cast<mirror::HeapReference<mirror::String>*>(
+          strings->GetRawData(sizeof(mirror::HeapReference<mirror::String>), 0));
+  std::sort(strings_begin, strings_begin + total_strings, LexicographicalStringComparator());
+  // Characters of strings which are non equal prefix of another string (not the same string).
+  // We don't count the savings from equal strings since these would get interned later anyways.
+  size_t prefix_saved_chars = 0;
+  // Count characters needed for the strings.
+  size_t num_chars = 0u;
+  mirror::String* prev_s = nullptr;
+  for (size_t idx = 0; idx != total_strings; ++idx) {
+    mirror::String* s = strings->GetWithoutChecks(idx);
+    size_t length = s->GetLength();
+    num_chars += length;
+    if (prev_s != nullptr && IsPrefix(prev_s, s)) {
+      size_t prev_length = prev_s->GetLength();
+      num_chars -= prev_length;
+      if (prev_length != length) {
+        prefix_saved_chars += prev_length;
+      }
+    }
+    prev_s = s;
+  }
+  // Create character array, copy characters and point the strings there.
+  mirror::CharArray* array = mirror::CharArray::Alloc(self, num_chars);
+  string_data_array_ = array;
+  uint16_t* array_data = array->GetData();
+  size_t pos = 0u;
+  prev_s = nullptr;
+  for (size_t idx = 0; idx != total_strings; ++idx) {
+    mirror::String* s = strings->GetWithoutChecks(idx);
+    uint16_t* s_data = s->GetCharArray()->GetData() + s->GetOffset();
+    int32_t s_length = s->GetLength();
+    int32_t prefix_length = 0u;
+    if (idx != 0u && IsPrefix(prev_s, s)) {
+      prefix_length = prev_s->GetLength();
+    }
+    memcpy(array_data + pos, s_data + prefix_length, (s_length - prefix_length) * sizeof(*s_data));
+    s->SetOffset(pos - prefix_length);
+    s->SetArray(array);
+    pos += s_length - prefix_length;
+    prev_s = s;
+  }
+  CHECK_EQ(pos, num_chars);
+
+  if (kIsDebugBuild || VLOG_IS_ON(compiler)) {
+    LOG(INFO) << "Total # image strings=" << total_strings << " combined length="
+        << num_chars << " prefix saved chars=" << prefix_saved_chars;
+  }
+  ComputeEagerResolvedStrings();
+}
+
+void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg ATTRIBUTE_UNUSED) {
   if (!obj->GetClass()->IsStringClass()) {
     return;
   }
@@ -293,8 +591,7 @@
   }
 }
 
-void ImageWriter::ComputeEagerResolvedStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+void ImageWriter::ComputeEagerResolvedStrings() {
   Runtime::Current()->GetHeap()->VisitObjects(ComputeEagerResolvedStringsCallback, this);
 }
 
@@ -324,7 +621,8 @@
 
   // Remove the undesired classes from the class roots.
   for (const std::string& it : non_image_classes) {
-    class_linker->RemoveClass(it.c_str(), NULL);
+    bool result = class_linker->RemoveClass(it.c_str(), NULL);
+    DCHECK(result);
   }
 
   // Clear references to removed classes from the DexCaches.
@@ -363,11 +661,9 @@
   return true;
 }
 
-void ImageWriter::CheckNonImageClassesRemoved()
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void ImageWriter::CheckNonImageClassesRemoved() {
   if (compiler_driver_.GetImageClasses() != nullptr) {
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
     heap->VisitObjects(CheckNonImageClassesRemovedCallback, this);
   }
 }
@@ -393,29 +689,29 @@
   }
 }
 
-void ImageWriter::CalculateObjectOffsets(Object* obj) {
+void ImageWriter::CalculateObjectBinSlots(Object* obj) {
   DCHECK(obj != NULL);
   // if it is a string, we want to intern it if its not interned.
   if (obj->GetClass()->IsStringClass()) {
     // we must be an interned string that was forward referenced and already assigned
-    if (IsImageOffsetAssigned(obj)) {
+    if (IsImageBinSlotAssigned(obj)) {
       DCHECK_EQ(obj, obj->AsString()->Intern());
       return;
     }
     mirror::String* const interned = obj->AsString()->Intern();
     if (obj != interned) {
-      if (!IsImageOffsetAssigned(interned)) {
+      if (!IsImageBinSlotAssigned(interned)) {
         // interned obj is after us, allocate its location early
-        AssignImageOffset(interned);
+        AssignImageBinSlot(interned);
       }
       // point those looking for this object to the interned version.
-      SetImageOffset(obj, GetImageOffset(interned));
+      SetImageBinSlot(obj, GetImageBinSlot(interned));
       return;
     }
     // else (obj == interned), nothing to do but fall through to the normal case
   }
 
-  AssignImageOffset(obj);
+  AssignImageBinSlot(obj);
 }
 
 ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
@@ -454,6 +750,8 @@
       ObjectArray<Object>::Alloc(self, object_array_class.Get(), ImageHeader::kImageRootsMax)));
   image_roots->Set<false>(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
   image_roots->Set<false>(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod());
+  image_roots->Set<false>(ImageHeader::kImtUnimplementedMethod,
+                          runtime->GetImtUnimplementedMethod());
   image_roots->Set<false>(ImageHeader::kDefaultImt, runtime->GetDefaultImt());
   image_roots->Set<false>(ImageHeader::kCalleeSaveMethod,
                           runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
@@ -481,36 +779,40 @@
   }
   //
   size_t num_reference_fields = h_class->NumReferenceInstanceFields();
+  MemberOffset field_offset = h_class->GetFirstReferenceInstanceFieldOffset();
   for (size_t i = 0; i < num_reference_fields; ++i) {
-    mirror::ArtField* field = h_class->GetInstanceField(i);
-    MemberOffset field_offset = field->GetOffset();
     mirror::Object* value = obj->GetFieldObject<mirror::Object>(field_offset);
     if (value != nullptr) {
       WalkFieldsInOrder(value);
     }
+    field_offset = MemberOffset(field_offset.Uint32Value() +
+                                sizeof(mirror::HeapReference<mirror::Object>));
   }
 }
 
 // For an unvisited object, visit it then all its children found via fields.
 void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
-  if (!IsImageOffsetAssigned(obj)) {
+  // Use our own visitor routine (instead of GC visitor) to get better locality between
+  // an object and its fields
+  if (!IsImageBinSlotAssigned(obj)) {
     // Walk instance fields of all objects
     StackHandleScope<2> hs(Thread::Current());
     Handle<mirror::Object> h_obj(hs.NewHandle(obj));
     Handle<mirror::Class> klass(hs.NewHandle(obj->GetClass()));
     // visit the object itself.
-    CalculateObjectOffsets(h_obj.Get());
+    CalculateObjectBinSlots(h_obj.Get());
     WalkInstanceFields(h_obj.Get(), klass.Get());
     // Walk static fields of a Class.
     if (h_obj->IsClass()) {
       size_t num_static_fields = klass->NumReferenceStaticFields();
+      MemberOffset field_offset = klass->GetFirstReferenceStaticFieldOffset();
       for (size_t i = 0; i < num_static_fields; ++i) {
-        mirror::ArtField* field = klass->GetStaticField(i);
-        MemberOffset field_offset = field->GetOffset();
         mirror::Object* value = h_obj->GetFieldObject<mirror::Object>(field_offset);
         if (value != nullptr) {
           WalkFieldsInOrder(value);
         }
+        field_offset = MemberOffset(field_offset.Uint32Value() +
+                                    sizeof(mirror::HeapReference<mirror::Object>));
       }
     } else if (h_obj->IsObjectArray()) {
       // Walk elements of an object array.
@@ -532,6 +834,24 @@
   writer->WalkFieldsInOrder(obj);
 }
 
+void ImageWriter::UnbinObjectsIntoOffsetCallback(mirror::Object* obj, void* arg) {
+  ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
+  DCHECK(writer != nullptr);
+  writer->UnbinObjectsIntoOffset(obj);
+}
+
+void ImageWriter::UnbinObjectsIntoOffset(mirror::Object* obj) {
+  CHECK(obj != nullptr);
+
+  // We know the bin slot, and the total bin sizes for all objects by now,
+  // so calculate the object's final image offset.
+
+  DCHECK(IsImageBinSlotAssigned(obj));
+  BinSlot bin_slot = GetImageBinSlot(obj);
+  // Change the lockword from a bin slot into an offset
+  AssignImageOffset(obj, bin_slot);
+}
+
 void ImageWriter::CalculateNewObjectOffsets() {
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
@@ -542,15 +862,18 @@
 
   // Leave space for the header, but do not write it yet, we need to
   // know where image_roots is going to end up
-  image_end_ += RoundUp(sizeof(ImageHeader), 8);  // 64-bit-alignment
+  image_end_ += RoundUp(sizeof(ImageHeader), kObjectAlignment);  // 64-bit-alignment
 
-  {
-    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    // TODO: Image spaces only?
-    DCHECK_LT(image_end_, image_->Size());
-    // Clear any pre-existing monitors which may have been in the monitor words.
-    heap->VisitObjects(WalkFieldsCallback, this);
-  }
+  // TODO: Image spaces only?
+  DCHECK_LT(image_end_, image_->Size());
+  image_objects_offset_begin_ = image_end_;
+  // Clear any pre-existing monitors which may have been in the monitor words, assign bin slots.
+  heap->VisitObjects(WalkFieldsCallback, this);
+  // Transform each object's bin slot into an offset which will be used to do the final copy.
+  heap->VisitObjects(UnbinObjectsIntoOffsetCallback, this);
+  DCHECK(saved_hashes_map_.empty());  // All binslot hashes should've been put into vector by now.
+
+  DCHECK_GT(image_end_, GetBinSizeSum());
 
   image_roots_address_ = PointerToLowMemUInt32(GetImageAddress(image_roots.Get()));
 
@@ -559,10 +882,11 @@
 
 void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) {
   CHECK_NE(0U, oat_loaded_size);
-  const byte* oat_file_begin = GetOatFileBegin();
-  const byte* oat_file_end = oat_file_begin + oat_loaded_size;
+  const uint8_t* oat_file_begin = GetOatFileBegin();
+  const uint8_t* oat_file_end = oat_file_begin + oat_loaded_size;
+
   oat_data_begin_ = oat_file_begin + oat_data_offset;
-  const byte* oat_data_end = oat_data_begin_ + oat_file_->Size();
+  const uint8_t* oat_data_end = oat_data_begin_ + oat_file_->Size();
 
   // Return to write header at start of image with future location of image_roots. At this point,
   // image_end_ is the size of the image (excluding bitmaps).
@@ -578,18 +902,16 @@
                                     PointerToLowMemUInt32(oat_file_begin),
                                     PointerToLowMemUInt32(oat_data_begin_),
                                     PointerToLowMemUInt32(oat_data_end),
-                                    PointerToLowMemUInt32(oat_file_end));
+                                    PointerToLowMemUInt32(oat_file_end),
+                                    compile_pic_);
 }
 
-
-void ImageWriter::CopyAndFixupObjects()
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void ImageWriter::CopyAndFixupObjects() {
   ScopedAssertNoThreadSuspension ants(Thread::Current(), "ImageWriter");
   gc::Heap* heap = Runtime::Current()->GetHeap();
   // TODO: heap validation can't handle this fix up pass
   heap->DisableObjectValidation();
   // TODO: Image spaces only?
-  WriterMutexLock mu(ants.Self(), *Locks::heap_bitmap_lock_);
   heap->VisitObjects(CopyAndFixupObjectsCallback, this);
   // Fix up the object previously had hash codes.
   for (const std::pair<mirror::Object*, uint32_t>& hash_pair : saved_hashes_) {
@@ -604,9 +926,16 @@
   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
   // see GetLocalAddress for similar computation
   size_t offset = image_writer->GetImageOffset(obj);
-  byte* dst = image_writer->image_->Begin() + offset;
-  const byte* src = reinterpret_cast<const byte*>(obj);
-  size_t n = obj->SizeOf();
+  uint8_t* dst = image_writer->image_->Begin() + offset;
+  const uint8_t* src = reinterpret_cast<const uint8_t*>(obj);
+  size_t n;
+  if (obj->IsArtMethod()) {
+    // Size without pointer fields since we don't want to overrun the buffer if target art method
+    // is 32 bits but source is 64 bits.
+    n = mirror::ArtMethod::SizeWithoutPointerFields(sizeof(void*));
+  } else {
+    n = obj->SizeOf();
+  }
   DCHECK_LT(offset + n, image_writer->image_->Size());
   memcpy(dst, src, n);
   Object* copy = reinterpret_cast<Object*>(dst);
@@ -616,6 +945,7 @@
   image_writer->FixupObject(obj, copy);
 }
 
+// Rewrite all the references in the copied object to point to their image address equivalent
 class FixupVisitor {
  public:
   FixupVisitor(ImageWriter* image_writer, Object* copy) : image_writer_(image_writer), copy_(copy) {
@@ -651,14 +981,16 @@
   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
     DCHECK(obj->IsClass());
-    FixupVisitor::operator()(obj, offset, false);
+    FixupVisitor::operator()(obj, offset, /*is_static*/false);
 
+    // TODO: Remove dead code
     if (offset.Uint32Value() < mirror::Class::EmbeddedVTableOffset().Uint32Value()) {
       return;
     }
   }
 
-  void operator()(mirror::Class* /*klass*/, mirror::Reference* ref) const
+  void operator()(mirror::Class* klass ATTRIBUTE_UNUSED,
+                  mirror::Reference* ref ATTRIBUTE_UNUSED) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     LOG(FATAL) << "Reference not expected here.";
@@ -685,18 +1017,22 @@
   }
   if (orig->IsArtMethod<kVerifyNone>()) {
     FixupMethod(orig->AsArtMethod<kVerifyNone>(), down_cast<ArtMethod*>(copy));
+  } else if (orig->IsClass() && orig->AsClass()->IsArtMethodClass()) {
+    // Set the right size for the target.
+    size_t size = mirror::ArtMethod::InstanceSize(target_ptr_size_);
+    down_cast<mirror::Class*>(copy)->SetObjectSizeWithoutChecks(size);
   }
 }
 
-const byte* ImageWriter::GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted) {
+const uint8_t* ImageWriter::GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted) {
   DCHECK(!method->IsResolutionMethod() && !method->IsImtConflictMethod() &&
-         !method->IsAbstract()) << PrettyMethod(method);
+         !method->IsImtUnimplementedMethod() && !method->IsAbstract()) << PrettyMethod(method);
 
   // Use original code if it exists. Otherwise, set the code pointer to the resolution
   // trampoline.
 
   // Quick entrypoint:
-  const byte* quick_code = GetOatAddress(method->GetQuickOatCodeOffset());
+  const uint8_t* quick_code = GetOatAddress(method->GetQuickOatCodeOffset());
   *quick_is_interpreted = false;
   if (quick_code != nullptr &&
       (!method->IsStatic() || method->IsConstructor() || method->GetDeclaringClass()->IsInitialized())) {
@@ -718,12 +1054,14 @@
   return quick_code;
 }
 
-const byte* ImageWriter::GetQuickEntryPoint(mirror::ArtMethod* method) {
+const uint8_t* ImageWriter::GetQuickEntryPoint(mirror::ArtMethod* method) {
   // Calculate the quick entry point following the same logic as FixupMethod() below.
   // The resolution method has a special trampoline to call.
-  if (UNLIKELY(method == Runtime::Current()->GetResolutionMethod())) {
+  Runtime* runtime = Runtime::Current();
+  if (UNLIKELY(method == runtime->GetResolutionMethod())) {
     return GetOatAddress(quick_resolution_trampoline_offset_);
-  } else if (UNLIKELY(method == Runtime::Current()->GetImtConflictMethod())) {
+  } else if (UNLIKELY(method == runtime->GetImtConflictMethod() ||
+                      method == runtime->GetImtUnimplementedMethod())) {
     return GetOatAddress(quick_imt_conflict_trampoline_offset_);
   } else {
     // We assume all methods have code. If they don't currently then we set them to the use the
@@ -741,81 +1079,69 @@
 void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) {
   // OatWriter replaces the code_ with an offset value. Here we re-adjust to a pointer relative to
   // oat_begin_
+  // For 64 bit targets we need to repack the current runtime pointer sized fields to the right
+  // locations.
+  // Copy all of the fields from the runtime methods to the target methods first since we did a
+  // bytewise copy earlier.
+  copy->SetEntryPointFromInterpreterPtrSize<kVerifyNone>(orig->GetEntryPointFromInterpreter(),
+                                                         target_ptr_size_);
+  copy->SetEntryPointFromJniPtrSize<kVerifyNone>(orig->GetEntryPointFromJni(), target_ptr_size_);
+  copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
+      orig->GetEntryPointFromQuickCompiledCode(), target_ptr_size_);
 
   // The resolution method has a special trampoline to call.
-  if (UNLIKELY(orig == Runtime::Current()->GetResolutionMethod())) {
-    copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(GetOatAddress(portable_resolution_trampoline_offset_));
-    copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_));
-  } else if (UNLIKELY(orig == Runtime::Current()->GetImtConflictMethod())) {
-    copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(GetOatAddress(portable_imt_conflict_trampoline_offset_));
-    copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_imt_conflict_trampoline_offset_));
+  Runtime* runtime = Runtime::Current();
+  if (UNLIKELY(orig == runtime->GetResolutionMethod())) {
+    copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
+        GetOatAddress(quick_resolution_trampoline_offset_), target_ptr_size_);
+  } else if (UNLIKELY(orig == runtime->GetImtConflictMethod() ||
+                      orig == runtime->GetImtUnimplementedMethod())) {
+    copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
+        GetOatAddress(quick_imt_conflict_trampoline_offset_), target_ptr_size_);
   } else {
     // We assume all methods have code. If they don't currently then we set them to the use the
     // resolution trampoline. Abstract methods never have code and so we need to make sure their
     // use results in an AbstractMethodError. We use the interpreter to achieve this.
     if (UNLIKELY(orig->IsAbstract())) {
-      copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(GetOatAddress(portable_to_interpreter_bridge_offset_));
-      copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_to_interpreter_bridge_offset_));
-      copy->SetEntryPointFromInterpreter<kVerifyNone>(reinterpret_cast<EntryPointFromInterpreter*>
-          (const_cast<byte*>(GetOatAddress(interpreter_to_interpreter_bridge_offset_))));
+      copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
+          GetOatAddress(quick_to_interpreter_bridge_offset_), target_ptr_size_);
+      copy->SetEntryPointFromInterpreterPtrSize<kVerifyNone>(
+          reinterpret_cast<EntryPointFromInterpreter*>(const_cast<uint8_t*>(
+                  GetOatAddress(interpreter_to_interpreter_bridge_offset_))), target_ptr_size_);
     } else {
       bool quick_is_interpreted;
-      const byte* quick_code = GetQuickCode(orig, &quick_is_interpreted);
-      copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(quick_code);
-
-      // Portable entrypoint:
-      const byte* portable_code = GetOatAddress(orig->GetPortableOatCodeOffset());
-      bool portable_is_interpreted = false;
-      if (portable_code != nullptr &&
-          (!orig->IsStatic() || orig->IsConstructor() || orig->GetDeclaringClass()->IsInitialized())) {
-        // We have code for a non-static or initialized method, just use the code.
-      } else if (portable_code == nullptr && orig->IsNative() &&
-          (!orig->IsStatic() || orig->GetDeclaringClass()->IsInitialized())) {
-        // Non-static or initialized native method missing compiled code, use generic JNI version.
-        // TODO: generic JNI support for LLVM.
-        portable_code = GetOatAddress(portable_resolution_trampoline_offset_);
-      } else if (portable_code == nullptr && !orig->IsNative()) {
-        // We don't have code at all for a non-native method, use the interpreter.
-        portable_code = GetOatAddress(portable_to_interpreter_bridge_offset_);
-        portable_is_interpreted = true;
-      } else {
-        CHECK(!orig->GetDeclaringClass()->IsInitialized());
-        // We have code for a static method, but need to go through the resolution stub for class
-        // initialization.
-        portable_code = GetOatAddress(portable_resolution_trampoline_offset_);
-      }
-      copy->SetEntryPointFromPortableCompiledCode<kVerifyNone>(portable_code);
+      const uint8_t* quick_code = GetQuickCode(orig, &quick_is_interpreted);
+      copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(quick_code, target_ptr_size_);
 
       // JNI entrypoint:
       if (orig->IsNative()) {
         // The native method's pointer is set to a stub to lookup via dlsym.
         // Note this is not the code_ pointer, that is handled above.
-        copy->SetNativeMethod<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_));
-      } else {
-        // Normal (non-abstract non-native) methods have various tables to relocate.
-        uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
-        const byte* native_gc_map = GetOatAddress(native_gc_map_offset);
-        copy->SetNativeGcMap<kVerifyNone>(reinterpret_cast<const uint8_t*>(native_gc_map));
+        copy->SetEntryPointFromJniPtrSize<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_),
+                                                       target_ptr_size_);
       }
 
       // Interpreter entrypoint:
       // Set the interpreter entrypoint depending on whether there is compiled code or not.
-      uint32_t interpreter_code = (quick_is_interpreted && portable_is_interpreted)
+      uint32_t interpreter_code = (quick_is_interpreted)
           ? interpreter_to_interpreter_bridge_offset_
           : interpreter_to_compiled_code_bridge_offset_;
-      copy->SetEntryPointFromInterpreter<kVerifyNone>(
+      EntryPointFromInterpreter* interpreter_entrypoint =
           reinterpret_cast<EntryPointFromInterpreter*>(
-              const_cast<byte*>(GetOatAddress(interpreter_code))));
+              const_cast<uint8_t*>(GetOatAddress(interpreter_code)));
+      copy->SetEntryPointFromInterpreterPtrSize<kVerifyNone>(
+          interpreter_entrypoint, target_ptr_size_);
     }
   }
 }
 
 static OatHeader* GetOatHeaderFromElf(ElfFile* elf) {
-  Elf32_Shdr* data_sec = elf->FindSectionByName(".rodata");
-  if (data_sec == nullptr) {
+  uint64_t data_sec_offset;
+  bool has_data_sec = elf->GetSectionOffsetAndSize(".rodata", &data_sec_offset, nullptr);
+  if (!has_data_sec) {
     return nullptr;
   }
-  return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec->sh_offset);
+  return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec_offset);
 }
 
 void ImageWriter::SetOatChecksumFromElfFile(File* elf_file) {
@@ -834,4 +1160,41 @@
   image_header->SetOatChecksum(oat_header->GetChecksum());
 }
 
+size_t ImageWriter::GetBinSizeSum(ImageWriter::Bin up_to) const {
+  DCHECK_LE(up_to, kBinSize);
+  return std::accumulate(&bin_slot_sizes_[0], &bin_slot_sizes_[up_to], /*init*/0);
+}
+
+ImageWriter::BinSlot::BinSlot(uint32_t lockword) : lockword_(lockword) {
+  // These values may need to get updated if more bins are added to the enum Bin
+  static_assert(kBinBits == 3, "wrong number of bin bits");
+  static_assert(kBinShift == 29, "wrong number of shift");
+  static_assert(sizeof(BinSlot) == sizeof(LockWord), "BinSlot/LockWord must have equal sizes");
+
+  DCHECK_LT(GetBin(), kBinSize);
+  DCHECK_ALIGNED(GetIndex(), kObjectAlignment);
+}
+
+ImageWriter::BinSlot::BinSlot(Bin bin, uint32_t index)
+    : BinSlot(index | (static_cast<uint32_t>(bin) << kBinShift)) {
+  DCHECK_EQ(index, GetIndex());
+}
+
+ImageWriter::Bin ImageWriter::BinSlot::GetBin() const {
+  return static_cast<Bin>((lockword_ & kBinMask) >> kBinShift);
+}
+
+uint32_t ImageWriter::BinSlot::GetIndex() const {
+  return lockword_ & ~kBinMask;
+}
+
+void ImageWriter::FreeStringDataArray() {
+  if (string_data_array_ != nullptr) {
+    gc::space::LargeObjectSpace* los = Runtime::Current()->GetHeap()->GetLargeObjectsSpace();
+    if (los != nullptr) {
+      los->Free(Thread::Current(), reinterpret_cast<mirror::Object*>(string_data_array_));
+    }
+  }
+}
+
 }  // namespace art
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index bdf0614..53f5ce4 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -18,38 +18,53 @@
 #define ART_COMPILER_IMAGE_WRITER_H_
 
 #include <stdint.h>
+#include <valgrind.h>
 
 #include <cstddef>
 #include <memory>
 #include <set>
 #include <string>
+#include <ostream>
 
+#include "base/macros.h"
 #include "driver/compiler_driver.h"
+#include "gc/space/space.h"
 #include "mem_map.h"
 #include "oat_file.h"
 #include "mirror/dex_cache.h"
 #include "os.h"
 #include "safe_map.h"
 #include "gc/space/space.h"
+#include "utils.h"
 
 namespace art {
 
 // Write a Space built during compilation for use during execution.
-class ImageWriter {
+class ImageWriter FINAL {
  public:
-  ImageWriter(const CompilerDriver& compiler_driver, uintptr_t image_begin)
-      : compiler_driver_(compiler_driver), image_begin_(reinterpret_cast<byte*>(image_begin)),
-        image_end_(0), image_roots_address_(0), oat_file_(NULL),
-        oat_data_begin_(NULL), interpreter_to_interpreter_bridge_offset_(0),
+  ImageWriter(const CompilerDriver& compiler_driver, uintptr_t image_begin,
+              bool compile_pic)
+      : compiler_driver_(compiler_driver), image_begin_(reinterpret_cast<uint8_t*>(image_begin)),
+        image_end_(0), image_objects_offset_begin_(0), image_roots_address_(0), oat_file_(nullptr),
+        oat_data_begin_(nullptr), interpreter_to_interpreter_bridge_offset_(0),
         interpreter_to_compiled_code_bridge_offset_(0), jni_dlsym_lookup_offset_(0),
-        portable_imt_conflict_trampoline_offset_(0), portable_resolution_trampoline_offset_(0),
-        portable_to_interpreter_bridge_offset_(0), quick_generic_jni_trampoline_offset_(0),
+        quick_generic_jni_trampoline_offset_(0),
         quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0),
-        quick_to_interpreter_bridge_offset_(0) {
+        quick_to_interpreter_bridge_offset_(0), compile_pic_(compile_pic),
+        target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())),
+        bin_slot_sizes_(), bin_slot_count_() {
     CHECK_NE(image_begin, 0U);
   }
 
-  ~ImageWriter() {}
+  ~ImageWriter() {
+    // For interned strings a large array is allocated to hold all the character data and avoid
+    // overhead. However, no GC is run anymore at this point. As the array is likely large, it
+    // will be allocated in the large object space, where valgrind can track every single
+    // allocation. Not explicitly freeing that array will be recognized as a leak.
+    if (RUNNING_ON_VALGRIND != 0) {
+      FreeStringDataArray();
+    }
+  }
 
   bool PrepareImageAddressSpace();
 
@@ -59,13 +74,13 @@
 
   mirror::Object* GetImageAddress(mirror::Object* object) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (object == NULL) {
-      return NULL;
+    if (object == nullptr) {
+      return nullptr;
     }
     return reinterpret_cast<mirror::Object*>(image_begin_ + GetImageOffset(object));
   }
 
-  byte* GetOatFileBegin() const {
+  uint8_t* GetOatFileBegin() const {
     return image_begin_ + RoundUp(image_end_, kPageSize);
   }
 
@@ -84,14 +99,71 @@
   // Mark the objects defined in this space in the given live bitmap.
   void RecordImageAllocations() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Classify different kinds of bins that objects end up getting packed into during image writing.
+  enum Bin {
+    // Likely-clean:
+    kBinString,                        // [String] Almost always immutable (except for obj header).
+    kBinArtMethodsManagedInitialized,  // [ArtMethod] Not-native, and initialized. Unlikely to dirty
+    // Unknown mix of clean/dirty:
+    kBinRegular,
+    // Likely-dirty:
+    // All classes get their own bins since their fields often dirty
+    kBinClassInitializedFinalStatics,  // Class initializers have been run, no non-final statics
+    kBinClassInitialized,         // Class initializers have been run
+    kBinClassVerified,            // Class verified, but initializers haven't been run
+    kBinArtMethodNative,          // Art method that is actually native
+    kBinArtMethodNotInitialized,  // Art method with a declaring class that wasn't initialized
+    // Don't care about other art methods since they don't dirty
+    // Add more bins here if we add more segregation code.
+    kBinSize,
+  };
+
+  friend std::ostream& operator<<(std::ostream& stream, const Bin& bin);
+
+  static constexpr size_t kBinBits = MinimumBitsToStore(kBinSize - 1);
+  // uint32 = typeof(lockword_)
+  static constexpr size_t kBinShift = BitSizeOf<uint32_t>() - kBinBits;
+  // 111000.....0
+  static constexpr size_t kBinMask = ((static_cast<size_t>(1) << kBinBits) - 1) << kBinShift;
+
+  // We use the lock word to store the bin # and bin index of the object in the image.
+  //
+  // The struct size must be exactly sizeof(LockWord), currently 32-bits, since this will end up
+  // stored in the lock word bit-for-bit when object forwarding addresses are being calculated.
+  struct BinSlot {
+    explicit BinSlot(uint32_t lockword);
+    BinSlot(Bin bin, uint32_t index);
+
+    // The bin an object belongs to, i.e. regular, class/verified, class/initialized, etc.
+    Bin GetBin() const;
+    // The offset in bytes from the beginning of the bin. Aligned to object size.
+    uint32_t GetIndex() const;
+    // Pack into a single uint32_t, for storing into a lock word.
+    explicit operator uint32_t() const { return lockword_; }
+    // Comparison operator for map support
+    bool operator<(const BinSlot& other) const  { return lockword_ < other.lockword_; }
+
+  private:
+    // Must be the same size as LockWord, any larger and we would truncate the data.
+    const uint32_t lockword_;
+  };
+
   // We use the lock word to store the offset of the object in the image.
-  void AssignImageOffset(mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetImageOffset(mirror::Object* object, size_t offset)
+  void AssignImageOffset(mirror::Object* object, BinSlot bin_slot)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SetImageOffset(mirror::Object* object, BinSlot bin_slot, size_t offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsImageOffsetAssigned(mirror::Object* object) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   size_t GetImageOffset(mirror::Object* object) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void AssignImageBinSlot(mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SetImageBinSlot(mirror::Object* object, BinSlot bin_slot)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool IsImageBinSlotAssigned(mirror::Object* object) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  BinSlot GetImageBinSlot(mirror::Object* object) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static void* GetImageAddressCallback(void* writer, mirror::Object* obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return reinterpret_cast<ImageWriter*>(writer)->GetImageAddress(obj);
@@ -100,19 +172,16 @@
   mirror::Object* GetLocalAddress(mirror::Object* object) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     size_t offset = GetImageOffset(object);
-    byte* dst = image_->Begin() + offset;
+    uint8_t* dst = image_->Begin() + offset;
     return reinterpret_cast<mirror::Object*>(dst);
   }
 
-  const byte* GetOatAddress(uint32_t offset) const {
-#if !defined(ART_USE_PORTABLE_COMPILER)
+  const uint8_t* GetOatAddress(uint32_t offset) const {
     // With Quick, code is within the OatFile, as there are all in one
-    // .o ELF object. However with Portable, the code is always in
-    // different .o ELF objects.
+    // .o ELF object.
     DCHECK_LT(offset, oat_file_->Size());
-#endif
-    if (offset == 0) {
-      return NULL;
+    if (offset == 0u) {
+      return nullptr;
     }
     return oat_data_begin_ + offset;
   }
@@ -134,13 +203,16 @@
   static void ComputeEagerResolvedStringsCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Combine string char arrays.
+  void ProcessStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Remove unwanted classes from various roots.
   void PruneNonImageClasses() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static bool NonImageClassesVisitor(mirror::Class* c, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Verify unwanted classes removed.
-  void CheckNonImageClassesRemoved();
+  void CheckNonImageClassesRemoved() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void CheckNonImageClassesRemovedCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -151,7 +223,9 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::ObjectArray<mirror::Object>* CreateImageRoots() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CalculateObjectOffsets(mirror::Object* obj)
+  void CalculateObjectBinSlots(mirror::Object* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void UnbinObjectsIntoOffset(mirror::Object* obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void WalkInstanceFields(mirror::Object* obj, mirror::Class* klass)
@@ -160,9 +234,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void WalkFieldsCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static void UnbinObjectsIntoOffsetCallback(mirror::Object* obj, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Creates the contiguous image in memory and adjusts pointers.
-  void CopyAndFixupObjects();
+  void CopyAndFixupObjects() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void CopyAndFixupObjectsCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void FixupMethod(mirror::ArtMethod* orig, mirror::ArtMethod* copy)
@@ -171,23 +247,32 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get quick code for non-resolution/imt_conflict/abstract method.
-  const byte* GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted)
+  const uint8_t* GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const byte* GetQuickEntryPoint(mirror::ArtMethod* method)
+  const uint8_t* GetQuickEntryPoint(mirror::ArtMethod* method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Patches references in OatFile to expect runtime addresses.
   void SetOatChecksumFromElfFile(File* elf_file);
 
+  // Calculate the sum total of the bin slot sizes in [0, up_to). Defaults to all bins.
+  size_t GetBinSizeSum(Bin up_to = kBinSize) const;
+
+  // Release the string_data_array_.
+  void FreeStringDataArray();
+
   const CompilerDriver& compiler_driver_;
 
   // Beginning target image address for the output image.
-  byte* image_begin_;
+  uint8_t* image_begin_;
 
   // Offset to the free space in image_.
   size_t image_end_;
 
+  // Offset from image_begin_ to where the first object is in image_.
+  size_t image_objects_offset_begin_;
+
   // The image roots address in the image.
   uint32_t image_roots_address_;
 
@@ -200,8 +285,11 @@
   // Saved hashes (objects are inside of the image so that they don't move).
   std::vector<std::pair<mirror::Object*, uint32_t>> saved_hashes_;
 
+  // Saved hashes (objects are bin slots to inside of the image, not yet allocated an address).
+  std::map<BinSlot, uint32_t> saved_hashes_map_;
+
   // Beginning target oat address for the pointers from the output image to its oat file.
-  const byte* oat_data_begin_;
+  const uint8_t* oat_data_begin_;
 
   // Image bitmap which lets us know where the objects inside of the image reside.
   std::unique_ptr<gc::accounting::ContinuousSpaceBitmap> image_bitmap_;
@@ -210,13 +298,20 @@
   uint32_t interpreter_to_interpreter_bridge_offset_;
   uint32_t interpreter_to_compiled_code_bridge_offset_;
   uint32_t jni_dlsym_lookup_offset_;
-  uint32_t portable_imt_conflict_trampoline_offset_;
-  uint32_t portable_resolution_trampoline_offset_;
-  uint32_t portable_to_interpreter_bridge_offset_;
   uint32_t quick_generic_jni_trampoline_offset_;
   uint32_t quick_imt_conflict_trampoline_offset_;
   uint32_t quick_resolution_trampoline_offset_;
   uint32_t quick_to_interpreter_bridge_offset_;
+  const bool compile_pic_;
+
+  // Size of pointers on the target architecture.
+  size_t target_ptr_size_;
+
+  // Bin slot tracking for dirty object packing
+  size_t bin_slot_sizes_[kBinSize];  // Number of bytes in a bin
+  size_t bin_slot_count_[kBinSize];  // Number of objects in a bin
+
+  void* string_data_array_;  // The backing for the interned strings.
 
   friend class FixupVisitor;
   friend class FixupClassVisitor;
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index a21004c..f513ea8 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -73,15 +73,13 @@
     }
     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;
-        ASSERT_TRUE(method->GetEntryPointFromPortableCompiledCode() != nullptr)
-            << method_name << " " << method_sig;
       }
     }
   }
@@ -204,7 +202,6 @@
 }
 
 void JniCompilerTest::CompileAndRunNoArgMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClassNatives_foo));
 
   EXPECT_EQ(0, gJava_MyClassNatives_foo_calls);
@@ -219,7 +216,6 @@
 JNI_TEST(CompileAndRunNoArgMethod)
 
 void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "bar", "(I)I", nullptr);
   // calling through stub will link with &Java_MyClassNatives_bar
 
@@ -234,7 +230,6 @@
 JNI_TEST(CompileAndRunIntMethodThroughStub)
 
 void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "sbar", "(I)I", nullptr);
   // calling through stub will link with &Java_MyClassNatives_sbar
 
@@ -262,7 +257,6 @@
 }
 
 void JniCompilerTest::CompileAndRunIntMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooI));
 
@@ -293,7 +287,6 @@
 }
 
 void JniCompilerTest::CompileAndRunIntIntMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooII", "(II)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooII));
 
@@ -325,7 +318,6 @@
 }
 
 void JniCompilerTest::CompileAndRunLongLongMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooJJ", "(JJ)J",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ));
 
@@ -358,19 +350,18 @@
 }
 
 void JniCompilerTest::CompileAndRunDoubleDoubleMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooDD", "(DD)D",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooDD));
 
   EXPECT_EQ(0, gJava_MyClassNatives_fooDD_calls);
   jdouble result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_,
                                                     99.0, 10.0);
-  EXPECT_EQ(99.0 - 10.0, result);
+  EXPECT_DOUBLE_EQ(99.0 - 10.0, result);
   EXPECT_EQ(1, gJava_MyClassNatives_fooDD_calls);
   jdouble a = 3.14159265358979323846;
   jdouble b = 0.69314718055994530942;
   result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_, a, b);
-  EXPECT_EQ(a - b, result);
+  EXPECT_DOUBLE_EQ(a - b, result);
   EXPECT_EQ(2, gJava_MyClassNatives_fooDD_calls);
 
   gJava_MyClassNatives_fooDD_calls = 0;
@@ -390,7 +381,6 @@
 }
 
 void JniCompilerTest::CompileAndRun_fooJJ_synchronizedImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooJJ_synchronized", "(JJ)J",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ_synchronized));
 
@@ -430,7 +420,6 @@
 }
 
 void JniCompilerTest::CompileAndRunIntObjectObjectMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooIOO));
@@ -479,7 +468,6 @@
 }
 
 void JniCompilerTest::CompileAndRunStaticIntIntMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSII", "(II)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSII));
 
@@ -507,19 +495,18 @@
 }
 
 void JniCompilerTest::CompileAndRunStaticDoubleDoubleMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSDD", "(DD)D",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSDD));
 
   EXPECT_EQ(0, gJava_MyClassNatives_fooSDD_calls);
   jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 99.0, 10.0);
-  EXPECT_EQ(99.0 - 10.0, result);
+  EXPECT_DOUBLE_EQ(99.0 - 10.0, result);
   EXPECT_EQ(1, gJava_MyClassNatives_fooSDD_calls);
   jdouble a = 3.14159265358979323846;
   jdouble b = 0.69314718055994530942;
   result = env_->CallStaticDoubleMethod(jklass_, jmethod_, a, b);
-  EXPECT_EQ(a - b, result);
-  EXPECT_EQ(2, gJava_MyClassNatives_fooSDD_calls);
+  EXPECT_DOUBLE_EQ(a - b, result);
+  EXPECT_DOUBLE_EQ(2, gJava_MyClassNatives_fooSDD_calls);
 
   gJava_MyClassNatives_fooSDD_calls = 0;
 }
@@ -530,48 +517,45 @@
 // point return value would be in xmm0. We use log, to somehow ensure
 // the compiler will use the floating point stack.
 
-jdouble Java_MyClassNatives_logD(JNIEnv* env, jclass klass, jdouble x) {
+jdouble Java_MyClassNatives_logD(JNIEnv*, jclass, jdouble x) {
   return log(x);
 }
 
 void JniCompilerTest::RunStaticLogDoubleMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "logD", "(D)D", reinterpret_cast<void*>(&Java_MyClassNatives_logD));
 
   jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 2.0);
-  EXPECT_EQ(log(2.0), result);
+  EXPECT_DOUBLE_EQ(log(2.0), result);
 }
 
 JNI_TEST(RunStaticLogDoubleMethod)
 
-jfloat Java_MyClassNatives_logF(JNIEnv* env, jclass klass, jfloat x) {
+jfloat Java_MyClassNatives_logF(JNIEnv*, jclass, jfloat x) {
   return logf(x);
 }
 
 void JniCompilerTest::RunStaticLogFloatMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "logF", "(F)F", reinterpret_cast<void*>(&Java_MyClassNatives_logF));
 
   jfloat result = env_->CallStaticFloatMethod(jklass_, jmethod_, 2.0);
-  EXPECT_EQ(logf(2.0), result);
+  EXPECT_FLOAT_EQ(logf(2.0), result);
 }
 
 JNI_TEST(RunStaticLogFloatMethod)
 
-jboolean Java_MyClassNatives_returnTrue(JNIEnv* env, jclass klass) {
+jboolean Java_MyClassNatives_returnTrue(JNIEnv*, jclass) {
   return JNI_TRUE;
 }
 
-jboolean Java_MyClassNatives_returnFalse(JNIEnv* env, jclass klass) {
+jboolean Java_MyClassNatives_returnFalse(JNIEnv*, jclass) {
   return JNI_FALSE;
 }
 
-jint Java_MyClassNatives_returnInt(JNIEnv* env, jclass klass) {
+jint Java_MyClassNatives_returnInt(JNIEnv*, jclass) {
   return 42;
 }
 
 void JniCompilerTest::RunStaticReturnTrueImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "returnTrue", "()Z", reinterpret_cast<void*>(&Java_MyClassNatives_returnTrue));
 
   jboolean result = env_->CallStaticBooleanMethod(jklass_, jmethod_);
@@ -581,7 +565,6 @@
 JNI_TEST(RunStaticReturnTrue)
 
 void JniCompilerTest::RunStaticReturnFalseImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "returnFalse", "()Z",
                reinterpret_cast<void*>(&Java_MyClassNatives_returnFalse));
 
@@ -592,7 +575,6 @@
 JNI_TEST(RunStaticReturnFalse)
 
 void JniCompilerTest::RunGenericStaticReturnIntImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "returnInt", "()I", reinterpret_cast<void*>(&Java_MyClassNatives_returnInt));
 
   jint result = env_->CallStaticIntMethod(jklass_, jmethod_);
@@ -626,7 +608,6 @@
 
 
 void JniCompilerTest::CompileAndRunStaticIntObjectObjectMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSIOO));
@@ -684,7 +665,6 @@
 }
 
 void JniCompilerTest::CompileAndRunStaticSynchronizedIntObjectObjectMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "fooSSIOO",
                "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooSSIOO));
@@ -725,7 +705,6 @@
 }
 
 void JniCompilerTest::ExceptionHandlingImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   {
     ASSERT_FALSE(runtime_->IsStarted());
     ScopedObjectAccess soa(Thread::Current());
@@ -785,9 +764,9 @@
     EXPECT_EQ(11, trace_array->GetLength());
 
     // Check stack trace entries have expected values
-    for (int32_t i = 0; i < trace_array->GetLength(); ++i) {
-      EXPECT_EQ(-2, trace_array->Get(i)->GetLineNumber());
-      mirror::StackTraceElement* ste = trace_array->Get(i);
+    for (int32_t j = 0; j < trace_array->GetLength(); ++j) {
+      EXPECT_EQ(-2, trace_array->Get(j)->GetLineNumber());
+      mirror::StackTraceElement* ste = trace_array->Get(j);
       EXPECT_STREQ("MyClassNatives.java", ste->GetFileName()->ToModifiedUtf8().c_str());
       EXPECT_STREQ("MyClassNatives", ste->GetDeclaringClass()->ToModifiedUtf8().c_str());
       EXPECT_STREQ("fooI", ste->GetMethodName()->ToModifiedUtf8().c_str());
@@ -810,7 +789,6 @@
 }
 
 void JniCompilerTest::NativeStackTraceElementImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I",
                reinterpret_cast<void*>(&Java_MyClassNatives_nativeUpCall));
   jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 10);
@@ -824,7 +802,6 @@
 }
 
 void JniCompilerTest::ReturnGlobalRefImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooO", "(Ljava/lang/Object;)Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_fooO));
   jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, jobj_);
@@ -844,7 +821,6 @@
 }
 
 void JniCompilerTest::LocalReferenceTableClearingTestImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&local_ref_test));
   // 1000 invocations of a method that adds 10 local references
   for (int i = 0; i < 1000; i++) {
@@ -865,7 +841,6 @@
 }
 
 void JniCompilerTest::JavaLangSystemArrayCopyImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V",
                reinterpret_cast<void*>(&my_arraycopy));
   env_->CallStaticVoidMethod(jklass_, jmethod_, jobj_, 1234, jklass_, 5678, 9876);
@@ -883,7 +858,6 @@
 }
 
 void JniCompilerTest::CompareAndSwapIntImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
                reinterpret_cast<void*>(&my_casi));
   jboolean result = env_->CallBooleanMethod(jobj_, jmethod_, jobj_, INT64_C(0x12345678ABCDEF88),
@@ -903,7 +877,6 @@
 }
 
 void JniCompilerTest::GetTextImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "getText", "(JLjava/lang/Object;JLjava/lang/Object;)I",
                reinterpret_cast<void*>(&my_gettext));
   jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 0x12345678ABCDEF88ll, jobj_,
@@ -931,7 +904,6 @@
 }
 
 void JniCompilerTest::GetSinkPropertiesNativeImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
                reinterpret_cast<void*>(&Java_MyClassNatives_GetSinkProperties));
 
@@ -957,12 +929,10 @@
 }
 
 void JniCompilerTest::UpcallReturnTypeChecking_InstanceImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "instanceMethodThatShouldReturnClass", "()Ljava/lang/Class;",
                reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldReturnClass));
 
   CheckJniAbortCatcher check_jni_abort_catcher;
-  // TODO: check type of returns with portable JNI compiler.
   // This native method is bad, and tries to return a jstring as a jclass.
   env_->CallObjectMethod(jobj_, jmethod_);
   check_jni_abort_catcher.Check("attempt to return an instance of java.lang.String from java.lang.Class MyClassNatives.instanceMethodThatShouldReturnClass()");
@@ -977,12 +947,10 @@
 JNI_TEST(UpcallReturnTypeChecking_Instance)
 
 void JniCompilerTest::UpcallReturnTypeChecking_StaticImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "staticMethodThatShouldReturnClass", "()Ljava/lang/Class;",
                reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldReturnClass));
 
   CheckJniAbortCatcher check_jni_abort_catcher;
-  // TODO: check type of returns with portable JNI compiler.
   // This native method is bad, and tries to return a jstring as a jclass.
   env_->CallStaticObjectMethod(jklass_, jmethod_);
   check_jni_abort_catcher.Check("attempt to return an instance of java.lang.String from java.lang.Class MyClassNatives.staticMethodThatShouldReturnClass()");
@@ -1005,7 +973,9 @@
 }
 
 void JniCompilerTest::UpcallArgumentTypeChecking_InstanceImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   SetUpForTest(false, "instanceMethodThatShouldTakeClass", "(ILjava/lang/Class;)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldTakeClass));
 
@@ -1018,7 +988,9 @@
 JNI_TEST(UpcallArgumentTypeChecking_Instance)
 
 void JniCompilerTest::UpcallArgumentTypeChecking_StaticImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   SetUpForTest(true, "staticMethodThatShouldTakeClass", "(ILjava/lang/Class;)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldTakeClass));
 
@@ -1041,22 +1013,24 @@
 }
 
 void JniCompilerTest::CompileAndRunFloatFloatMethodImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "checkFloats", "(FF)F",
                reinterpret_cast<void*>(&Java_MyClassNatives_checkFloats));
 
   jfloat result = env_->CallNonvirtualFloatMethod(jobj_, jklass_, jmethod_,
                                                     99.0F, 10.0F);
-  EXPECT_EQ(99.0F - 10.0F, result);
+  EXPECT_FLOAT_EQ(99.0F - 10.0F, result);
   jfloat a = 3.14159F;
   jfloat b = 0.69314F;
   result = env_->CallNonvirtualFloatMethod(jobj_, jklass_, jmethod_, a, b);
-  EXPECT_EQ(a - b, result);
+  EXPECT_FLOAT_EQ(a - b, result);
 }
 
 JNI_TEST(CompileAndRunFloatFloatMethod)
 
-void Java_MyClassNatives_checkParameterAlign(JNIEnv* env, jobject thisObj, jint i1, jlong l1) {
+void Java_MyClassNatives_checkParameterAlign(JNIEnv* env ATTRIBUTE_UNUSED,
+                                             jobject thisObj ATTRIBUTE_UNUSED,
+                                             jint i1 ATTRIBUTE_UNUSED,
+                                             jlong l1 ATTRIBUTE_UNUSED) {
 //  EXPECT_EQ(kNative, Thread::Current()->GetState());
 //  EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
 //  EXPECT_TRUE(thisObj != nullptr);
@@ -1068,7 +1042,6 @@
 }
 
 void JniCompilerTest::CheckParameterAlignImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "checkParameterAlign", "(IJ)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_checkParameterAlign));
 
@@ -1483,7 +1456,6 @@
     "Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V";
 
 void JniCompilerTest::MaxParamNumberImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(false, "maxParamNumber", longSig,
                reinterpret_cast<void*>(&Java_MyClassNatives_maxParamNumber));
 
@@ -1509,7 +1481,9 @@
 JNI_TEST(MaxParamNumber)
 
 void JniCompilerTest::WithoutImplementationImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   SetUpForTest(false, "withoutImplementation", "()V", nullptr);
 
   env_->CallVoidMethod(jobj_, jmethod_);
@@ -1520,7 +1494,7 @@
 
 JNI_TEST(WithoutImplementation)
 
-void Java_MyClassNatives_stackArgsIntsFirst(JNIEnv* env, jclass klass, jint i1, jint i2, jint i3,
+void Java_MyClassNatives_stackArgsIntsFirst(JNIEnv*, jclass, jint i1, jint i2, jint i3,
                                             jint i4, jint i5, jint i6, jint i7, jint i8, jint i9,
                                             jint i10, jfloat f1, jfloat f2, jfloat f3, jfloat f4,
                                             jfloat f5, jfloat f6, jfloat f7, jfloat f8, jfloat f9,
@@ -1559,7 +1533,6 @@
 }
 
 void JniCompilerTest::StackArgsIntsFirstImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "stackArgsIntsFirst", "(IIIIIIIIIIFFFFFFFFFF)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsIntsFirst));
 
@@ -1591,7 +1564,7 @@
 
 JNI_TEST(StackArgsIntsFirst)
 
-void Java_MyClassNatives_stackArgsFloatsFirst(JNIEnv* env, jclass klass, jfloat f1, jfloat f2,
+void Java_MyClassNatives_stackArgsFloatsFirst(JNIEnv*, jclass, jfloat f1, jfloat f2,
                                               jfloat f3, jfloat f4, jfloat f5, jfloat f6, jfloat f7,
                                               jfloat f8, jfloat f9, jfloat f10, jint i1, jint i2,
                                               jint i3, jint i4, jint i5, jint i6, jint i7, jint i8,
@@ -1630,7 +1603,6 @@
 }
 
 void JniCompilerTest::StackArgsFloatsFirstImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "stackArgsFloatsFirst", "(FFFFFFFFFFIIIIIIIIII)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsFloatsFirst));
 
@@ -1662,7 +1634,7 @@
 
 JNI_TEST(StackArgsFloatsFirst)
 
-void Java_MyClassNatives_stackArgsMixed(JNIEnv* env, jclass klass, jint i1, jfloat f1, jint i2,
+void Java_MyClassNatives_stackArgsMixed(JNIEnv*, jclass, jint i1, jfloat f1, jint i2,
                                         jfloat f2, jint i3, jfloat f3, jint i4, jfloat f4, jint i5,
                                         jfloat f5, jint i6, jfloat f6, jint i7, jfloat f7, jint i8,
                                         jfloat f8, jint i9, jfloat f9, jint i10, jfloat f10) {
@@ -1700,7 +1672,6 @@
 }
 
 void JniCompilerTest::StackArgsMixedImpl() {
-  TEST_DISABLED_FOR_PORTABLE();
   SetUpForTest(true, "stackArgsMixed", "(IFIFIFIFIFIFIFIFIFIF)V",
                reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsMixed));
 
diff --git a/compiler/jni/portable/jni_compiler.cc b/compiler/jni/portable/jni_compiler.cc
deleted file mode 100644
index d2f54f8..0000000
--- a/compiler/jni/portable/jni_compiler.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jni_compiler.h"
-
-#include "base/logging.h"
-#include "class_linker.h"
-#include "compiled_method.h"
-#include "dex_file-inl.h"
-#include "driver/compiler_driver.h"
-#include "driver/dex_compilation_unit.h"
-#include "llvm/compiler_llvm.h"
-#include "llvm/ir_builder.h"
-#include "llvm/llvm_compilation_unit.h"
-#include "llvm/runtime_support_llvm_func.h"
-#include "llvm/utils_llvm.h"
-#include "mirror/art_method.h"
-#include "runtime.h"
-#include "stack.h"
-#include "thread.h"
-
-#include <llvm/ADT/SmallVector.h>
-#include <llvm/IR/BasicBlock.h>
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/Type.h>
-
-namespace art {
-namespace llvm {
-
-using ::art::llvm::runtime_support::JniMethodEnd;
-using ::art::llvm::runtime_support::JniMethodEndSynchronized;
-using ::art::llvm::runtime_support::JniMethodEndWithReference;
-using ::art::llvm::runtime_support::JniMethodEndWithReferenceSynchronized;
-using ::art::llvm::runtime_support::JniMethodStart;
-using ::art::llvm::runtime_support::JniMethodStartSynchronized;
-using ::art::llvm::runtime_support::RuntimeId;
-
-JniCompiler::JniCompiler(LlvmCompilationUnit* cunit,
-                         CompilerDriver* driver,
-                         const DexCompilationUnit* dex_compilation_unit)
-    : cunit_(cunit), driver_(driver), module_(cunit_->GetModule()),
-      context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()),
-      dex_compilation_unit_(dex_compilation_unit),
-      func_(NULL), elf_func_idx_(0) {
-  // Check: Ensure that JNI compiler will only get "native" method
-  CHECK(dex_compilation_unit->IsNative());
-}
-
-CompiledMethod* JniCompiler::Compile() {
-  const bool is_static = dex_compilation_unit_->IsStatic();
-  const bool is_synchronized = dex_compilation_unit_->IsSynchronized();
-  const DexFile* dex_file = dex_compilation_unit_->GetDexFile();
-  DexFile::MethodId const& method_id =
-      dex_file->GetMethodId(dex_compilation_unit_->GetDexMethodIndex());
-  char const return_shorty = dex_file->GetMethodShorty(method_id)[0];
-  ::llvm::Value* this_object_or_class_object;
-
-  uint32_t method_idx = dex_compilation_unit_->GetDexMethodIndex();
-  std::string func_name(StringPrintf("jni_%s",
-                                     MangleForJni(PrettyMethod(method_idx, *dex_file)).c_str()));
-  CreateFunction(func_name);
-
-  // Set argument name
-  ::llvm::Function::arg_iterator arg_begin(func_->arg_begin());
-  ::llvm::Function::arg_iterator arg_end(func_->arg_end());
-  ::llvm::Function::arg_iterator arg_iter(arg_begin);
-
-  DCHECK_NE(arg_iter, arg_end);
-  arg_iter->setName("method");
-  ::llvm::Value* method_object_addr = arg_iter++;
-
-  if (!is_static) {
-    // Non-static, the second argument is "this object"
-    this_object_or_class_object = arg_iter++;
-  } else {
-    // Load class object
-    this_object_or_class_object =
-        irb_.LoadFromObjectOffset(method_object_addr,
-                                  mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                                  irb_.getJObjectTy(),
-                                  kTBAAConstJObject);
-  }
-  // Actual argument (ignore method and this object)
-  arg_begin = arg_iter;
-
-  // Count the number of Object* arguments
-  uint32_t handle_scope_size = 1;
-  // "this" object pointer for non-static
-  // "class" object pointer for static
-  for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
-#if !defined(NDEBUG)
-    arg_iter->setName(StringPrintf("a%u", i));
-#endif
-    if (arg_iter->getType() == irb_.getJObjectTy()) {
-      ++handle_scope_size;
-    }
-  }
-
-  // Shadow stack
-  ::llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(handle_scope_size);
-  ::llvm::AllocaInst* shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
-
-  // Store the dex pc
-  irb_.StoreToObjectOffset(shadow_frame_,
-                           ShadowFrame::DexPCOffset(),
-                           irb_.getInt32(DexFile::kDexNoIndex),
-                           kTBAAShadowFrame);
-
-  // Push the shadow frame
-  ::llvm::Value* shadow_frame_upcast = irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
-  ::llvm::Value* old_shadow_frame =
-      irb_.Runtime().EmitPushShadowFrame(shadow_frame_upcast, method_object_addr, handle_scope_size);
-
-  // Get JNIEnv
-  ::llvm::Value* jni_env_object_addr =
-      irb_.Runtime().EmitLoadFromThreadOffset(Thread::JniEnvOffset().Int32Value(),
-                                              irb_.getJObjectTy(),
-                                              kTBAARuntimeInfo);
-
-  // Get callee code_addr
-  ::llvm::Value* code_addr =
-      irb_.LoadFromObjectOffset(method_object_addr,
-                                mirror::ArtMethod::NativeMethodOffset().Int32Value(),
-                                GetFunctionType(dex_compilation_unit_->GetDexMethodIndex(),
-                                                is_static, true)->getPointerTo(),
-                                kTBAARuntimeInfo);
-
-  // Load actual parameters
-  std::vector< ::llvm::Value*> args;
-
-  // The 1st parameter: JNIEnv*
-  args.push_back(jni_env_object_addr);
-
-  // Variables for GetElementPtr
-  ::llvm::Value* gep_index[] = {
-    irb_.getInt32(0),  // No displacement for shadow frame pointer
-    irb_.getInt32(1),  // handle scope
-    NULL,
-  };
-
-  size_t handle_scope_member_index = 0;
-
-  // Store the "this object or class object" to handle scope
-  gep_index[2] = irb_.getInt32(handle_scope_member_index++);
-  ::llvm::Value* handle_scope_field_addr = irb_.CreateBitCast(irb_.CreateGEP(shadow_frame_, gep_index),
-                                                    irb_.getJObjectTy()->getPointerTo());
-  irb_.CreateStore(this_object_or_class_object, handle_scope_field_addr, kTBAAShadowFrame);
-  // Push the "this object or class object" to out args
-  this_object_or_class_object = irb_.CreateBitCast(handle_scope_field_addr, irb_.getJObjectTy());
-  args.push_back(this_object_or_class_object);
-  // Store arguments to handle scope, and push back to args
-  for (arg_iter = arg_begin; arg_iter != arg_end; ++arg_iter) {
-    if (arg_iter->getType() == irb_.getJObjectTy()) {
-      // Store the reference type arguments to handle scope
-      gep_index[2] = irb_.getInt32(handle_scope_member_index++);
-      ::llvm::Value* handle_scope_field_addr = irb_.CreateBitCast(irb_.CreateGEP(shadow_frame_, gep_index),
-                                                        irb_.getJObjectTy()->getPointerTo());
-      irb_.CreateStore(arg_iter, handle_scope_field_addr, kTBAAShadowFrame);
-      // Note null is placed in the handle scope but the jobject passed to the native code must be null
-      // (not a pointer into the handle scope as with regular references).
-      ::llvm::Value* equal_null = irb_.CreateICmpEQ(arg_iter, irb_.getJNull());
-      ::llvm::Value* arg =
-          irb_.CreateSelect(equal_null,
-                            irb_.getJNull(),
-                            irb_.CreateBitCast(handle_scope_field_addr, irb_.getJObjectTy()));
-      args.push_back(arg);
-    } else {
-      args.push_back(arg_iter);
-    }
-  }
-
-  ::llvm::Value* saved_local_ref_cookie;
-  {  // JniMethodStart
-    RuntimeId func_id = is_synchronized ? JniMethodStartSynchronized
-                                        : JniMethodStart;
-    ::llvm::SmallVector< ::llvm::Value*, 2> args;
-    if (is_synchronized) {
-      args.push_back(this_object_or_class_object);
-    }
-    args.push_back(irb_.Runtime().EmitGetCurrentThread());
-    saved_local_ref_cookie =
-        irb_.CreateCall(irb_.GetRuntime(func_id), args);
-  }
-
-  // Call!!!
-  ::llvm::Value* retval = irb_.CreateCall(code_addr, args);
-
-  {  // JniMethodEnd
-    bool is_return_ref = return_shorty == 'L';
-    RuntimeId func_id =
-        is_return_ref ? (is_synchronized ? JniMethodEndWithReferenceSynchronized
-                                         : JniMethodEndWithReference)
-                      : (is_synchronized ? JniMethodEndSynchronized
-                                         : JniMethodEnd);
-    ::llvm::SmallVector< ::llvm::Value*, 4> args;
-    if (is_return_ref) {
-      args.push_back(retval);
-    }
-    args.push_back(saved_local_ref_cookie);
-    if (is_synchronized) {
-      args.push_back(this_object_or_class_object);
-    }
-    args.push_back(irb_.Runtime().EmitGetCurrentThread());
-
-    ::llvm::Value* decoded_jobject =
-        irb_.CreateCall(irb_.GetRuntime(func_id), args);
-
-    // Return decoded jobject if return reference.
-    if (is_return_ref) {
-      retval = decoded_jobject;
-    }
-  }
-
-  // Pop the shadow frame
-  irb_.Runtime().EmitPopShadowFrame(old_shadow_frame);
-
-  // Return!
-  switch (return_shorty) {
-    case 'V':
-      irb_.CreateRetVoid();
-      break;
-    case 'Z':
-    case 'C':
-      irb_.CreateRet(irb_.CreateZExt(retval, irb_.getInt32Ty()));
-      break;
-    case 'B':
-    case 'S':
-      irb_.CreateRet(irb_.CreateSExt(retval, irb_.getInt32Ty()));
-      break;
-    default:
-      irb_.CreateRet(retval);
-      break;
-  }
-
-  // Verify the generated bitcode
-  VERIFY_LLVM_FUNCTION(*func_);
-
-  cunit_->Materialize();
-
-  return new CompiledMethod(*driver_, cunit_->GetInstructionSet(), cunit_->GetElfObject(),
-                            func_name);
-}
-
-
-void JniCompiler::CreateFunction(const std::string& func_name) {
-  CHECK_NE(0U, func_name.size());
-
-  const bool is_static = dex_compilation_unit_->IsStatic();
-
-  // Get function type
-  ::llvm::FunctionType* func_type =
-    GetFunctionType(dex_compilation_unit_->GetDexMethodIndex(), is_static, false);
-
-  // Create function
-  func_ = ::llvm::Function::Create(func_type, ::llvm::Function::InternalLinkage,
-                                   func_name, module_);
-
-  // Create basic block
-  ::llvm::BasicBlock* basic_block = ::llvm::BasicBlock::Create(*context_, "B0", func_);
-
-  // Set insert point
-  irb_.SetInsertPoint(basic_block);
-}
-
-
-::llvm::FunctionType* JniCompiler::GetFunctionType(uint32_t method_idx,
-                                                   bool is_static, bool is_native_function) {
-  // Get method signature
-  uint32_t shorty_size;
-  const char* shorty = dex_compilation_unit_->GetShorty(&shorty_size);
-  CHECK_GE(shorty_size, 1u);
-
-  // Get return type
-  ::llvm::Type* ret_type = NULL;
-  switch (shorty[0]) {
-    case 'V': ret_type =  irb_.getJVoidTy(); break;
-    case 'Z':
-    case 'B':
-    case 'C':
-    case 'S':
-    case 'I': ret_type =  irb_.getJIntTy(); break;
-    case 'F': ret_type =  irb_.getJFloatTy(); break;
-    case 'J': ret_type =  irb_.getJLongTy(); break;
-    case 'D': ret_type =  irb_.getJDoubleTy(); break;
-    case 'L': ret_type =  irb_.getJObjectTy(); break;
-    default: LOG(FATAL)  << "Unreachable: unexpected return type in shorty " << shorty;
-  }
-  // Get argument type
-  std::vector< ::llvm::Type*> args_type;
-
-  args_type.push_back(irb_.getJObjectTy());  // method object pointer
-
-  if (!is_static || is_native_function) {
-    // "this" object pointer for non-static
-    // "class" object pointer for static naitve
-    args_type.push_back(irb_.getJType('L'));
-  }
-
-  for (uint32_t i = 1; i < shorty_size; ++i) {
-    args_type.push_back(irb_.getJType(shorty[i]));
-  }
-
-  return ::llvm::FunctionType::get(ret_type, args_type, false);
-}
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/jni/portable/jni_compiler.h b/compiler/jni/portable/jni_compiler.h
deleted file mode 100644
index ffabfe6..0000000
--- a/compiler/jni/portable/jni_compiler.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_JNI_PORTABLE_JNI_COMPILER_H_
-#define ART_COMPILER_JNI_PORTABLE_JNI_COMPILER_H_
-
-#include <stdint.h>
-
-#include <string>
-
-namespace art {
-  class ClassLinker;
-  class CompiledMethod;
-  class CompilerDriver;
-  class DexFile;
-  class DexCompilationUnit;
-  namespace mirror {
-    class ArtMethod;
-    class ClassLoader;
-    class DexCache;
-  }  // namespace mirror
-}  // namespace art
-
-namespace llvm {
-  class AllocaInst;
-  class Function;
-  class FunctionType;
-  class BasicBlock;
-  class LLVMContext;
-  class Module;
-  class Type;
-  class Value;
-}  // namespace llvm
-
-namespace art {
-namespace llvm {
-
-class LlvmCompilationUnit;
-class IRBuilder;
-
-class JniCompiler {
- public:
-  JniCompiler(LlvmCompilationUnit* cunit,
-              CompilerDriver* driver,
-              const DexCompilationUnit* dex_compilation_unit);
-
-  CompiledMethod* Compile();
-
- private:
-  void CreateFunction(const std::string& symbol);
-
-  ::llvm::FunctionType* GetFunctionType(uint32_t method_idx,
-                                        bool is_static, bool is_target_function);
-
- private:
-  LlvmCompilationUnit* cunit_;
-  CompilerDriver* const driver_;
-
-  ::llvm::Module* module_;
-  ::llvm::LLVMContext* context_;
-  IRBuilder& irb_;
-
-  const DexCompilationUnit* const dex_compilation_unit_;
-
-  ::llvm::Function* func_;
-  uint16_t elf_func_idx_;
-};
-
-
-}  // namespace llvm
-}  // namespace art
-
-
-#endif  // ART_COMPILER_JNI_PORTABLE_JNI_COMPILER_H_
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index f0c0ed7..669c3bb 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -16,11 +16,28 @@
 
 #include "base/logging.h"
 #include "calling_convention_arm.h"
+#include "handle_scope-inl.h"
 #include "utils/arm/managed_register_arm.h"
 
 namespace art {
 namespace arm {
 
+// Used by hard float.
+static const Register kHFCoreArgumentRegisters[] = {
+  R0, R1, R2, R3
+};
+
+static const SRegister kHFSArgumentRegisters[] = {
+  S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15
+};
+
+static const DRegister kHFDArgumentRegisters[] = {
+  D0, D1, D2, D3, D4, D5, D6, D7
+};
+
+static_assert(arraysize(kHFDArgumentRegisters) * 2 == arraysize(kHFSArgumentRegisters),
+    "ks d argument registers mismatch");
+
 // Calling convention
 
 ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
@@ -31,26 +48,43 @@
   return ArmManagedRegister::FromCoreRegister(IP);  // R12
 }
 
-static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
-  if (shorty[0] == 'F') {
-    return ArmManagedRegister::FromCoreRegister(R0);
-  } else if (shorty[0] == 'D') {
-    return ArmManagedRegister::FromRegisterPair(R0_R1);
-  } else if (shorty[0] == 'J') {
-    return ArmManagedRegister::FromRegisterPair(R0_R1);
-  } else if (shorty[0] == 'V') {
-    return ArmManagedRegister::NoRegister();
+ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
+  if (kArm32QuickCodeUseSoftFloat) {
+    switch (GetShorty()[0]) {
+    case 'V':
+      return ArmManagedRegister::NoRegister();
+    case 'D':
+    case 'J':
+      return ArmManagedRegister::FromRegisterPair(R0_R1);
+    default:
+      return ArmManagedRegister::FromCoreRegister(R0);
+    }
   } else {
-    return ArmManagedRegister::FromCoreRegister(R0);
+    switch (GetShorty()[0]) {
+    case 'V':
+      return ArmManagedRegister::NoRegister();
+    case 'D':
+      return ArmManagedRegister::FromDRegister(D0);
+    case 'F':
+      return ArmManagedRegister::FromSRegister(S0);
+    case 'J':
+      return ArmManagedRegister::FromRegisterPair(R0_R1);
+    default:
+      return ArmManagedRegister::FromCoreRegister(R0);
+    }
   }
 }
 
-ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
-  return ReturnRegisterForShorty(GetShorty());
-}
-
 ManagedRegister ArmJniCallingConvention::ReturnRegister() {
-  return ReturnRegisterForShorty(GetShorty());
+  switch (GetShorty()[0]) {
+  case 'V':
+    return ArmManagedRegister::NoRegister();
+  case 'D':
+  case 'J':
+    return ArmManagedRegister::FromRegisterPair(R0_R1);
+  default:
+    return ArmManagedRegister::FromCoreRegister(R0);
+  }
 }
 
 ManagedRegister ArmJniCallingConvention::IntReturnRegister() {
@@ -88,17 +122,81 @@
 const ManagedRegisterEntrySpills& ArmManagedRuntimeCallingConvention::EntrySpills() {
   // We spill the argument registers on ARM to free them up for scratch use, we then assume
   // all arguments are on the stack.
-  if (entry_spills_.size() == 0) {
-    size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
-    if (num_spills > 0) {
-      entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R1));
-      if (num_spills > 1) {
-        entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R2));
-        if (num_spills > 2) {
-          entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R3));
+  if (kArm32QuickCodeUseSoftFloat) {
+    if (entry_spills_.size() == 0) {
+      size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
+      if (num_spills > 0) {
+        entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R1));
+        if (num_spills > 1) {
+          entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R2));
+          if (num_spills > 2) {
+            entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R3));
+          }
         }
       }
     }
+  } else {
+    if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
+      uint32_t gpr_index = 1;  // R0 ~ R3. Reserve r0 for ArtMethod*.
+      uint32_t fpr_index = 0;  // S0 ~ S15.
+      uint32_t fpr_double_index = 0;  // D0 ~ D7.
+
+      ResetIterator(FrameOffset(0));
+      while (HasNext()) {
+        if (IsCurrentParamAFloatOrDouble()) {
+          if (IsCurrentParamADouble()) {  // Double.
+            // Double should not overlap with float.
+            fpr_double_index = (std::max(fpr_double_index * 2, RoundUp(fpr_index, 2))) / 2;
+            if (fpr_double_index < arraysize(kHFDArgumentRegisters)) {
+              entry_spills_.push_back(
+                  ArmManagedRegister::FromDRegister(kHFDArgumentRegisters[fpr_double_index++]));
+            } else {
+              entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
+            }
+          } else {  // Float.
+            // Float should not overlap with double.
+            if (fpr_index % 2 == 0) {
+              fpr_index = std::max(fpr_double_index * 2, fpr_index);
+            }
+            if (fpr_index < arraysize(kHFSArgumentRegisters)) {
+              entry_spills_.push_back(
+                  ArmManagedRegister::FromSRegister(kHFSArgumentRegisters[fpr_index++]));
+            } else {
+              entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+            }
+          }
+        } else {
+          // FIXME: Pointer this returns as both reference and long.
+          if (IsCurrentParamALong() && !IsCurrentParamAReference()) {  // Long.
+            if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
+              // Skip R1, and use R2_R3 if the long is the first parameter.
+              if (gpr_index == 1) {
+                gpr_index++;
+              }
+            }
+
+            // If it spans register and memory, we must use the value in memory.
+            if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
+              entry_spills_.push_back(
+                  ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
+            } else if (gpr_index == arraysize(kHFCoreArgumentRegisters) - 1) {
+              gpr_index++;
+              entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+            } else {
+              entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+            }
+          }
+          // High part of long or 32-bit argument.
+          if (gpr_index < arraysize(kHFCoreArgumentRegisters)) {
+            entry_spills_.push_back(
+                ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
+          } else {
+            entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+          }
+        }
+        Next();
+      }
+    }
   }
   return entry_spills_;
 }
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index b95dad2..b9c8178 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -16,12 +16,13 @@
 
 #include "base/logging.h"
 #include "calling_convention_arm64.h"
+#include "handle_scope-inl.h"
 #include "utils/arm64/managed_register_arm64.h"
 
 namespace art {
 namespace arm64 {
 
-static const Register kCoreArgumentRegisters[] = {
+static const XRegister kXArgumentRegisters[] = {
   X0, X1, X2, X3, X4, X5, X6, X7
 };
 
@@ -39,11 +40,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 +53,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 +76,7 @@
 // Managed runtime calling convention
 
 ManagedRegister Arm64ManagedRuntimeCallingConvention::MethodRegister() {
-  return Arm64ManagedRegister::FromCoreRegister(X0);
+  return Arm64ManagedRegister::FromXRegister(X0);
 }
 
 bool Arm64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
@@ -129,7 +130,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 +155,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 +233,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 78a228b..bf996a2 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.
@@ -311,7 +307,9 @@
   }
 
   // 9. Plant call to native code associated with method.
-  __ Call(main_jni_conv->MethodStackOffset(), mirror::ArtMethod::NativeMethodOffset(),
+  MemberOffset jni_entrypoint_offset = mirror::ArtMethod::EntryPointFromJniOffset(
+      InstructionSetPointerSize(instruction_set));
+  __ Call(main_jni_conv->MethodStackOffset(), jni_entrypoint_offset,
           mr_conv->InterproceduralScratchRegister());
 
   // 10. Fix differences in result widths.
@@ -428,21 +426,22 @@
   // 17. Finalize code generation
   __ EmitSlowPaths();
   size_t cs = __ CodeSize();
-  if (instruction_set == kArm64) {
-    // Test that we do not exceed the buffer size.
-    CHECK(cs < arm64::kBufferSizeArm64);
-  }
   std::vector<uint8_t> managed_code(cs);
   MemoryRegion code(&managed_code[0], managed_code.size());
   __ FinalizeInstructions(code);
   jni_asm->FinalizeFrameDescriptionEntry();
-  return new CompiledMethod(driver,
-                            instruction_set,
-                            managed_code,
-                            frame_size,
-                            main_jni_conv->CoreSpillMask(),
-                            main_jni_conv->FpSpillMask(),
-                            jni_asm->GetFrameDescriptionEntry());
+  std::vector<uint8_t>* fde(jni_asm->GetFrameDescriptionEntry());
+  ArrayRef<const uint8_t> cfi_ref;
+  if (fde != nullptr) {
+    cfi_ref = ArrayRef<const uint8_t>(*fde);
+  }
+  return CompiledMethod::SwapAllocCompiledMethodCFI(driver,
+                                                    instruction_set,
+                                                    ArrayRef<const uint8_t>(managed_code),
+                                                    frame_size,
+                                                    main_jni_conv->CoreSpillMask(),
+                                                    main_jni_conv->FpSpillMask(),
+                                                    cfi_ref);
 }
 
 // Copy a single parameter from the managed to the JNI calling convention
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index f7a7be7..aefbf06 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -17,6 +17,7 @@
 #include "calling_convention_mips.h"
 
 #include "base/logging.h"
+#include "handle_scope-inl.h"
 #include "utils/mips/managed_register_mips.h"
 
 namespace art {
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index 9bf7d0f..a5686e1 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -17,6 +17,7 @@
 #include "calling_convention_x86.h"
 
 #include "base/logging.h"
+#include "handle_scope-inl.h"
 #include "utils/x86/managed_register_x86.h"
 #include "utils.h"
 
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
index 525f05c..bbdf1fe 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -17,6 +17,7 @@
 #include "calling_convention_x86_64.h"
 
 #include "base/logging.h"
+#include "handle_scope-inl.h"
 #include "utils/x86_64/managed_register_x86_64.h"
 #include "utils.h"
 
@@ -38,6 +39,7 @@
 }
 
 static ManagedRegister ReturnRegisterForShorty(const char* shorty, bool jni) {
+  UNUSED(jni);
   if (shorty[0] == 'F' || shorty[0] == 'D') {
     return X86_64ManagedRegister::FromXmmRegister(XMM0);
   } else if (shorty[0] == 'J') {
diff --git a/compiler/llvm/art_module.ll b/compiler/llvm/art_module.ll
deleted file mode 100644
index 233692c..0000000
--- a/compiler/llvm/art_module.ll
+++ /dev/null
@@ -1,153 +0,0 @@
-;;
-;; Copyright (C) 2012 The Android Open Source Project
-;;
-;; Licensed under the Apache License, Version 2.0 (the "License");
-;; you may not use this file except in compliance with the License.
-;; You may obtain a copy of the License at
-;;
-;;      http://www.apache.org/licenses/LICENSE-2.0
-;;
-;; Unless required by applicable law or agreed to in writing, software
-;; distributed under the License is distributed on an "AS IS" BASIS,
-;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-;; See the License for the specific language governing permissions and
-;; limitations under the License.
-;;
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Type
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-%JavaObject = type opaque
-
-%ShadowFrame = type { i32                  ; Number of VRegs
-                    , %ShadowFrame*        ; Previous frame
-                    , %JavaObject*         ; Method object pointer
-                    , i32                  ; Line number for stack backtrace
-                    ; [0 x i32]            ; VRegs
-                    }
-
-declare void @__art_type_list(%JavaObject*, %ShadowFrame*)
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Thread
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare %JavaObject* @art_portable_get_current_thread_from_code()
-declare %JavaObject* @art_portable_set_current_thread_from_code(%JavaObject*)
-
-declare void @art_portable_lock_object_from_code(%JavaObject*, %JavaObject*)
-declare void @art_portable_unlock_object_from_code(%JavaObject*, %JavaObject*)
-
-declare void @art_portable_test_suspend_from_code(%JavaObject*)
-
-declare %ShadowFrame* @art_portable_push_shadow_frame_from_code(%JavaObject*, %ShadowFrame*, %JavaObject*, i32)
-declare void @art_portable_pop_shadow_frame_from_code(%ShadowFrame*)
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Exception
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare %JavaObject* @art_portable_get_and_clear_exception(%JavaObject*)
-declare void @art_portable_throw_div_zero_from_code()
-declare void @art_portable_throw_array_bounds_from_code(i32, i32)
-declare void @art_portable_throw_no_such_method_from_code(i32)
-declare void @art_portable_throw_null_pointer_exception_from_code(i32)
-declare void @art_portable_throw_stack_overflow_from_code()
-declare void @art_portable_throw_exception_from_code(%JavaObject*)
-
-declare i32 @art_portable_find_catch_block_from_code(%JavaObject*, i32)
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Object Space
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare %JavaObject* @art_portable_alloc_object_from_code(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_alloc_object_from_code_with_access_check(i32, %JavaObject*, %JavaObject*)
-
-declare %JavaObject* @art_portable_alloc_array_from_code(i32, %JavaObject*, i32, %JavaObject*)
-declare %JavaObject* @art_portable_alloc_array_from_code_with_access_check(i32, %JavaObject*, i32, %JavaObject*)
-declare %JavaObject* @art_portable_check_and_alloc_array_from_code(i32, %JavaObject*, i32, %JavaObject*)
-declare %JavaObject* @art_portable_check_and_alloc_array_from_code_with_access_check(i32, %JavaObject*, i32, %JavaObject*)
-
-declare void @art_portable_find_instance_field_from_code(i32, %JavaObject*)
-declare void @art_portable_find_static_field_from_code(i32, %JavaObject*)
-
-declare %JavaObject* @art_portable_find_static_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_find_direct_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_find_virtual_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_find_super_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_find_interface_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_find_interface_method_from_code(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-
-declare %JavaObject* @art_portable_initialize_static_storage_from_code(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_initialize_type_from_code(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_initialize_type_and_verify_access_from_code(i32, %JavaObject*, %JavaObject*)
-
-declare %JavaObject* @art_portable_resolve_string_from_code(%JavaObject*, i32)
-
-declare i32 @art_portable_set32_static_from_code(i32, %JavaObject*, i32)
-declare i32 @art_portable_set64_static_from_code(i32, %JavaObject*, i64)
-declare i32 @art_portable_set_obj_static_from_code(i32, %JavaObject*, %JavaObject*)
-
-declare i32 @art_portable_get32_static_from_code(i32, %JavaObject*)
-declare i64 @art_portable_get64_static_from_code(i32, %JavaObject*)
-declare %JavaObject* @art_portable_get_obj_static_from_code(i32, %JavaObject*)
-
-declare i32 @art_portable_set32_instance_from_code(i32, %JavaObject*, %JavaObject*, i32)
-declare i32 @art_portable_set64_instance_from_code(i32, %JavaObject*, %JavaObject*, i64)
-declare i32 @art_portable_set_obj_instance_from_code(i32, %JavaObject*, %JavaObject*, %JavaObject*)
-
-declare i32 @art_portable_get32_instance_from_code(i32, %JavaObject*, %JavaObject*)
-declare i64 @art_portable_get64_instance_from_code(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_get_obj_instance_from_code(i32, %JavaObject*, %JavaObject*)
-
-declare %JavaObject* @art_portable_decode_jobject_in_thread(%JavaObject*, %JavaObject*)
-
-declare void @art_portable_fill_array_data_from_code(%JavaObject*, i32, %JavaObject*, i32)
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Type Checking, in the nature of casting
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare i32 @art_portable_is_assignable_from_code(%JavaObject*, %JavaObject*)
-declare void @art_portable_check_cast_from_code(%JavaObject*, %JavaObject*)
-declare void @art_portable_check_put_array_element_from_code(%JavaObject*, %JavaObject*)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Math
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare i64 @art_d2l(double)
-declare i32 @art_d2i(double)
-declare i64 @art_f2l(float)
-declare i32 @art_f2i(float)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; JNI
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare i32 @art_portable_jni_method_start(%JavaObject*)
-declare i32 @art_portable_jni_method_start_synchronized(%JavaObject*, %JavaObject*)
-
-declare void @art_portable_jni_method_end(i32, %JavaObject*)
-declare void @art_portable_jni_method_end_synchronized(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_portable_jni_method_end_with_reference(%JavaObject*, i32, %JavaObject*)
-declare %JavaObject* @art_portable_jni_method_end_with_reference_synchronized(%JavaObject*, i32, %JavaObject*, %JavaObject*)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Temporary runtime support, will be removed in the future
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-declare i1 @art_portable_is_exception_pending_from_code()
-
-declare void @art_portable_mark_gc_card_from_code(%JavaObject*, %JavaObject*)
-
-declare void @art_portable_proxy_invoke_handler_from_code(%JavaObject*, ...)
diff --git a/compiler/llvm/backend_options.h b/compiler/llvm/backend_options.h
deleted file mode 100644
index 2a08bda..0000000
--- a/compiler/llvm/backend_options.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_BACKEND_OPTIONS_H_
-#define ART_COMPILER_LLVM_BACKEND_OPTIONS_H_
-
-#include <llvm/Support/CommandLine.h>
-
-#define DECLARE_ARM_BACKEND_OPTIONS \
-extern llvm::cl::opt<bool> EnableARMLongCalls; \
-extern llvm::cl::opt<bool> ReserveR9;
-
-#define INITIAL_ARM_BACKEND_OPTIONS \
-EnableARMLongCalls = true; \
-ReserveR9 = true;
-
-#define DECLARE_X86_BACKEND_OPTIONS
-#define INITIAL_X86_BACKEND_OPTIONS
-
-#define DECLARE_Mips_BACKEND_OPTIONS
-#define INITIAL_Mips_BACKEND_OPTIONS
-
-#define LLVM_TARGET(TargetName) DECLARE_##TargetName##_BACKEND_OPTIONS
-#include "llvm/Config/Targets.def"
-
-namespace art {
-namespace llvm {
-
-inline void InitialBackendOptions() {
-#define LLVM_TARGET(TargetName) INITIAL_##TargetName##_BACKEND_OPTIONS
-#include "llvm/Config/Targets.def"
-}
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_BACKEND_OPTIONS_H_
diff --git a/compiler/llvm/backend_types.h b/compiler/llvm/backend_types.h
deleted file mode 100644
index 8ca88dd..0000000
--- a/compiler/llvm/backend_types.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_BACKEND_TYPES_H_
-#define ART_COMPILER_LLVM_BACKEND_TYPES_H_
-
-#include "base/logging.h"
-
-
-namespace art {
-namespace llvm {
-
-
-enum JType {
-  kVoid,
-  kBoolean,
-  kByte,
-  kChar,
-  kShort,
-  kInt,
-  kLong,
-  kFloat,
-  kDouble,
-  kObject,
-  MAX_JTYPE
-};
-
-enum TBAASpecialType {
-  kTBAARegister,
-  kTBAAStackTemp,
-  kTBAAHeapArray,
-  kTBAAHeapInstance,
-  kTBAAHeapStatic,
-  kTBAAJRuntime,
-  kTBAARuntimeInfo,
-  kTBAAShadowFrame,
-  kTBAAConstJObject,
-  MAX_TBAA_SPECIAL_TYPE
-};
-
-
-enum ExpectCond {
-  kLikely,
-  kUnlikely,
-  MAX_EXPECT
-};
-
-
-inline JType GetJTypeFromShorty(char shorty_jty) {
-  switch (shorty_jty) {
-  case 'V':
-    return kVoid;
-
-  case 'Z':
-    return kBoolean;
-
-  case 'B':
-    return kByte;
-
-  case 'C':
-    return kChar;
-
-  case 'S':
-    return kShort;
-
-  case 'I':
-    return kInt;
-
-  case 'J':
-    return kLong;
-
-  case 'F':
-    return kFloat;
-
-  case 'D':
-    return kDouble;
-
-  case 'L':
-    return kObject;
-
-  default:
-    LOG(FATAL) << "Unknown Dalvik shorty descriptor: " << shorty_jty;
-    return kVoid;
-  }
-}
-
-}  // namespace llvm
-}  // namespace art
-
-
-#endif  // ART_COMPILER_LLVM_BACKEND_TYPES_H_
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
deleted file mode 100644
index 3aeecad..0000000
--- a/compiler/llvm/compiler_llvm.cc
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compiler_llvm.h"
-
-#include "backend_options.h"
-#include "base/stl_util.h"
-#include "class_linker.h"
-#include "compiled_method.h"
-#include "dex/verification_results.h"
-#include "dex/verified_method.h"
-#include "driver/compiler_driver.h"
-#include "driver/dex_compilation_unit.h"
-#include "globals.h"
-#include "ir_builder.h"
-#include "jni/portable/jni_compiler.h"
-#include "llvm_compilation_unit.h"
-#include "thread-inl.h"
-#include "utils_llvm.h"
-#include "verifier/method_verifier.h"
-
-#include <llvm/LinkAllPasses.h>
-#include <llvm/Support/ManagedStatic.h>
-#include <llvm/Support/TargetSelect.h>
-#include <llvm/Support/Threading.h>
-
-namespace art {
-void CompileOneMethod(CompilerDriver& driver,
-                      Compiler* compiler,
-                      const DexFile::CodeItem* code_item,
-                      uint32_t access_flags, InvokeType invoke_type,
-                      uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
-                      const DexFile& dex_file,
-                      void* llvm_info);
-}
-
-namespace llvm {
-  extern bool TimePassesIsEnabled;
-}
-
-namespace {
-
-pthread_once_t llvm_initialized = PTHREAD_ONCE_INIT;
-
-void InitializeLLVM() {
-  // Initialize LLVM internal data structure for multithreading
-  llvm::llvm_start_multithreaded();
-
-  // NOTE: Uncomment following line to show the time consumption of LLVM passes
-  // llvm::TimePassesIsEnabled = true;
-
-  // Initialize LLVM target-specific options.
-  art::llvm::InitialBackendOptions();
-
-  // Initialize LLVM target, MC subsystem, asm printer, and asm parser.
-  if (art::kIsTargetBuild) {
-    // Don't initialize all targets on device. Just initialize the device's native target
-    llvm::InitializeNativeTarget();
-    llvm::InitializeNativeTargetAsmPrinter();
-    llvm::InitializeNativeTargetAsmParser();
-  } else {
-    llvm::InitializeAllTargets();
-    llvm::InitializeAllTargetMCs();
-    llvm::InitializeAllAsmPrinters();
-    llvm::InitializeAllAsmParsers();
-  }
-
-  // Initialize LLVM optimization passes
-  llvm::PassRegistry &registry = *llvm::PassRegistry::getPassRegistry();
-
-  llvm::initializeCore(registry);
-  llvm::initializeScalarOpts(registry);
-  llvm::initializeIPO(registry);
-  llvm::initializeAnalysis(registry);
-  llvm::initializeIPA(registry);
-  llvm::initializeTransformUtils(registry);
-  llvm::initializeInstCombine(registry);
-  llvm::initializeInstrumentation(registry);
-  llvm::initializeTarget(registry);
-}
-
-// The Guard to Shutdown LLVM
-// llvm::llvm_shutdown_obj llvm_guard;
-// TODO: We are commenting out this line because this will cause SEGV from
-// time to time.
-// Two reasons: (1) the order of the destruction of static objects, or
-//              (2) dlopen/dlclose side-effect on static objects.
-
-}  // anonymous namespace
-
-
-namespace art {
-namespace llvm {
-
-
-::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
-
-
-CompilerLLVM::CompilerLLVM(CompilerDriver* driver, InstructionSet insn_set)
-    : compiler_driver_(driver), insn_set_(insn_set),
-      next_cunit_id_lock_("compilation unit id lock"), next_cunit_id_(1) {
-
-  // Initialize LLVM libraries
-  pthread_once(&llvm_initialized, InitializeLLVM);
-}
-
-
-CompilerLLVM::~CompilerLLVM() {
-}
-
-
-LlvmCompilationUnit* CompilerLLVM::AllocateCompilationUnit() {
-  MutexLock GUARD(Thread::Current(), next_cunit_id_lock_);
-  LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, next_cunit_id_++);
-  if (!bitcode_filename_.empty()) {
-    cunit->SetBitcodeFileName(StringPrintf("%s-%u",
-                                           bitcode_filename_.c_str(),
-                                           cunit->GetCompilationUnitId()));
-  }
-  return cunit;
-}
-
-
-CompiledMethod* CompilerLLVM::
-CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_type) {
-  std::unique_ptr<LlvmCompilationUnit> cunit(AllocateCompilationUnit());
-
-  cunit->SetDexCompilationUnit(dex_compilation_unit);
-  cunit->SetCompilerDriver(compiler_driver_);
-  // TODO: consolidate ArtCompileMethods
-  CompileOneMethod(compiler_driver_,
-                   compiler_driver_->GetCompiler(),
-                   dex_compilation_unit->GetCodeItem(),
-                   dex_compilation_unit->GetAccessFlags(),
-                   invoke_type,
-                   dex_compilation_unit->GetClassDefIndex(),
-                   dex_compilation_unit->GetDexMethodIndex(),
-                   dex_compilation_unit->GetClassLoader(),
-                   *dex_compilation_unit->GetDexFile(),
-                   cunit.get());
-
-  cunit->Materialize();
-
-  return new CompiledMethod(*compiler_driver_, compiler_driver_->GetInstructionSet(),
-                            cunit->GetElfObject(),
-                            dex_compilation_unit->GetVerifiedMethod()->GetDexGcMap(),
-                            cunit->GetDexCompilationUnit()->GetSymbol());
-}
-
-
-CompiledMethod* CompilerLLVM::
-CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) {
-  std::unique_ptr<LlvmCompilationUnit> cunit(AllocateCompilationUnit());
-
-  std::unique_ptr<JniCompiler> jni_compiler(
-      new JniCompiler(cunit.get(), compiler_driver_, dex_compilation_unit));
-
-  return jni_compiler->Compile();
-}
-
-
-static CompilerLLVM* ContextOf(art::CompilerDriver* driver) {
-  void *compiler_context = driver->GetCompilerContext();
-  CHECK(compiler_context != NULL);
-  return reinterpret_cast<CompilerLLVM*>(compiler_context);
-}
-
-static CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
-  void *compiler_context = driver.GetCompilerContext();
-  CHECK(compiler_context != NULL);
-  return reinterpret_cast<CompilerLLVM*>(compiler_context);
-}
-
-void ArtInitCompilerContext(CompilerDriver* driver) {
-  CHECK(driver->GetCompilerContext() == nullptr);
-
-  CompilerLLVM* compiler_llvm = new CompilerLLVM(driver, driver->GetInstructionSet());
-
-  driver->SetCompilerContext(compiler_llvm);
-}
-
-void ArtUnInitCompilerContext(CompilerDriver* driver) {
-  delete ContextOf(driver);
-  driver->SetCompilerContext(nullptr);
-}
-
-CompiledMethod* ArtCompileMethod(CompilerDriver* driver, const DexFile::CodeItem* code_item,
-                                 uint32_t access_flags, InvokeType invoke_type,
-                                 uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
-                                 const DexFile& dex_file) {
-  UNUSED(class_def_idx);  // TODO: this is used with Compiler::RequiresConstructorBarrier.
-  ClassLinker *class_linker = Runtime::Current()->GetClassLinker();
-
-  DexCompilationUnit dex_compilation_unit(nullptr, class_loader, class_linker, dex_file, code_item,
-                                          class_def_idx, method_idx, access_flags,
-                                          driver->GetVerifiedMethod(&dex_file, method_idx));
-  CompilerLLVM* compiler_llvm = ContextOf(driver);
-  CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type);
-  return result;
-}
-
-CompiledMethod* ArtLLVMJniCompileMethod(CompilerDriver* driver, uint32_t access_flags,
-                                        uint32_t method_idx, const DexFile& dex_file) {
-  ClassLinker *class_linker = Runtime::Current()->GetClassLinker();
-
-  DexCompilationUnit dex_compilation_unit(nullptr, nullptr, class_linker, dex_file, nullptr,
-                                          0, method_idx, access_flags, nullptr);
-
-  CompilerLLVM* compiler_llvm = ContextOf(driver);
-  CompiledMethod* result = compiler_llvm->CompileNativeMethod(&dex_compilation_unit);
-  return result;
-}
-
-void compilerLLVMSetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
-  ContextOf(driver)->SetBitcodeFileName(filename);
-}
-
-}  // namespace llvm
-}  // namespace art
-
diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h
deleted file mode 100644
index 7d29198..0000000
--- a/compiler/llvm/compiler_llvm.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_COMPILER_LLVM_H_
-#define ART_COMPILER_LLVM_COMPILER_LLVM_H_
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "dex_file.h"
-#include "driver/compiler_driver.h"
-#include "instruction_set.h"
-#include "mirror/object.h"
-
-namespace art {
-  class CompiledMethod;
-  class CompilerDriver;
-  class DexCompilationUnit;
-  namespace mirror {
-    class ArtMethod;
-    class ClassLoader;
-  }  // namespace mirror
-}  // namespace art
-
-
-namespace llvm {
-  class Function;
-  class LLVMContext;
-  class Module;
-  class PointerType;
-  class StructType;
-  class Type;
-}  // namespace llvm
-
-
-namespace art {
-namespace llvm {
-
-class LlvmCompilationUnit;
-class IRBuilder;
-
-class CompilerLLVM {
- public:
-  CompilerLLVM(CompilerDriver* driver, InstructionSet insn_set);
-
-  ~CompilerLLVM();
-
-  CompilerDriver* GetCompiler() const {
-    return compiler_driver_;
-  }
-
-  InstructionSet GetInstructionSet() const {
-    return insn_set_;
-  }
-
-  void SetBitcodeFileName(const std::string& filename) {
-    bitcode_filename_ = filename;
-  }
-
-  CompiledMethod* CompileDexMethod(DexCompilationUnit* dex_compilation_unit,
-                                   InvokeType invoke_type);
-
-  CompiledMethod* CompileGBCMethod(DexCompilationUnit* dex_compilation_unit, std::string* func);
-
-  CompiledMethod* CompileNativeMethod(DexCompilationUnit* dex_compilation_unit);
-
- private:
-  LlvmCompilationUnit* AllocateCompilationUnit();
-
-  CompilerDriver* const compiler_driver_;
-
-  const InstructionSet insn_set_;
-
-  Mutex next_cunit_id_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  size_t next_cunit_id_ GUARDED_BY(next_cunit_id_lock_);
-
-  std::string bitcode_filename_;
-
-  DISALLOW_COPY_AND_ASSIGN(CompilerLLVM);
-};
-
-void ArtInitCompilerContext(CompilerDriver* driver);
-
-void ArtUnInitCompilerContext(CompilerDriver* driver);
-
-CompiledMethod* ArtCompileMethod(CompilerDriver* driver, const DexFile::CodeItem* code_item,
-                                 uint32_t access_flags, InvokeType invoke_type,
-                                 uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
-                                 const DexFile& dex_file);
-
-CompiledMethod* ArtLLVMJniCompileMethod(CompilerDriver* driver, uint32_t access_flags,
-                                        uint32_t method_idx, const DexFile& dex_file);
-
-void compilerLLVMSetBitcodeFileName(const CompilerDriver& driver, const std::string& filename);
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_COMPILER_LLVM_H_
diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc
deleted file mode 100644
index 902f8dd..0000000
--- a/compiler/llvm/gbc_expander.cc
+++ /dev/null
@@ -1,3796 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file.h"
-#include "dex_file-inl.h"
-#include "driver/compiler_driver.h"
-#include "driver/dex_compilation_unit.h"
-#include "intrinsic_helper.h"
-#include "ir_builder.h"
-#include "method_reference.h"
-#include "mirror/art_method.h"
-#include "mirror/array.h"
-#include "mirror/string.h"
-#include "thread.h"
-#include "utils_llvm.h"
-#include "verifier/method_verifier.h"
-
-#include "dex/compiler_ir.h"
-#include "dex/mir_graph.h"
-#include "dex/quick/mir_to_lir.h"
-
-#include <llvm/ADT/STLExtras.h>
-#include <llvm/IR/Intrinsics.h>
-#include <llvm/IR/Metadata.h>
-#include <llvm/Pass.h>
-#include <llvm/Support/CFG.h>
-#include <llvm/Support/InstIterator.h>
-
-#include <vector>
-#include <map>
-#include <utility>
-
-using ::art::kMIRIgnoreNullCheck;
-using ::art::kMIRIgnoreRangeCheck;
-using ::art::llvm::IRBuilder;
-using ::art::llvm::IntrinsicHelper;
-using ::art::llvm::JType;
-using ::art::llvm::RuntimeSupportBuilder;
-using ::art::llvm::kBoolean;
-using ::art::llvm::kByte;
-using ::art::llvm::kChar;
-using ::art::llvm::kDouble;
-using ::art::llvm::kFloat;
-using ::art::llvm::kInt;
-using ::art::llvm::kLikely;
-using ::art::llvm::kLong;
-using ::art::llvm::kObject;
-using ::art::llvm::kShort;
-using ::art::llvm::kTBAAConstJObject;
-using ::art::llvm::kTBAAHeapArray;
-using ::art::llvm::kTBAAHeapInstance;
-using ::art::llvm::kTBAAHeapStatic;
-using ::art::llvm::kTBAARegister;
-using ::art::llvm::kTBAARuntimeInfo;
-using ::art::llvm::kTBAAShadowFrame;
-using ::art::llvm::kUnlikely;
-using ::art::llvm::kVoid;
-using ::art::llvm::runtime_support::AllocArray;
-using ::art::llvm::runtime_support::AllocArrayWithAccessCheck;
-using ::art::llvm::runtime_support::AllocObject;
-using ::art::llvm::runtime_support::AllocObjectWithAccessCheck;
-using ::art::llvm::runtime_support::CheckAndAllocArray;
-using ::art::llvm::runtime_support::CheckAndAllocArrayWithAccessCheck;
-using ::art::llvm::runtime_support::CheckCast;
-using ::art::llvm::runtime_support::CheckPutArrayElement;
-using ::art::llvm::runtime_support::FillArrayData;
-using ::art::llvm::runtime_support::FindCatchBlock;
-using ::art::llvm::runtime_support::FindDirectMethodWithAccessCheck;
-using ::art::llvm::runtime_support::FindInterfaceMethod;
-using ::art::llvm::runtime_support::FindInterfaceMethodWithAccessCheck;
-using ::art::llvm::runtime_support::FindStaticMethodWithAccessCheck;
-using ::art::llvm::runtime_support::FindSuperMethodWithAccessCheck;
-using ::art::llvm::runtime_support::FindVirtualMethodWithAccessCheck;
-using ::art::llvm::runtime_support::Get32Instance;
-using ::art::llvm::runtime_support::Get32Static;
-using ::art::llvm::runtime_support::Get64Instance;
-using ::art::llvm::runtime_support::Get64Static;
-using ::art::llvm::runtime_support::GetObjectInstance;
-using ::art::llvm::runtime_support::GetObjectStatic;
-using ::art::llvm::runtime_support::InitializeStaticStorage;
-using ::art::llvm::runtime_support::InitializeType;
-using ::art::llvm::runtime_support::InitializeTypeAndVerifyAccess;
-using ::art::llvm::runtime_support::IsAssignable;
-using ::art::llvm::runtime_support::ResolveString;
-using ::art::llvm::runtime_support::RuntimeId;
-using ::art::llvm::runtime_support::Set32Instance;
-using ::art::llvm::runtime_support::Set32Static;
-using ::art::llvm::runtime_support::Set64Instance;
-using ::art::llvm::runtime_support::Set64Static;
-using ::art::llvm::runtime_support::SetObjectInstance;
-using ::art::llvm::runtime_support::SetObjectStatic;
-using ::art::llvm::runtime_support::ThrowDivZeroException;
-using ::art::llvm::runtime_support::ThrowException;
-using ::art::llvm::runtime_support::ThrowIndexOutOfBounds;
-using ::art::llvm::runtime_support::ThrowNullPointerException;
-using ::art::llvm::runtime_support::ThrowStackOverflowException;
-using ::art::llvm::runtime_support::art_d2i;
-using ::art::llvm::runtime_support::art_d2l;
-using ::art::llvm::runtime_support::art_f2i;
-using ::art::llvm::runtime_support::art_f2l;
-
-namespace art {
-extern char RemapShorty(char shortyType);
-}  // namespace art
-
-namespace {
-
-class GBCExpanderPass : public llvm::FunctionPass {
- private:
-  const IntrinsicHelper& intrinsic_helper_;
-  IRBuilder& irb_;
-
-  llvm::LLVMContext& context_;
-  RuntimeSupportBuilder& rtb_;
-
- private:
-  llvm::AllocaInst* shadow_frame_;
-  llvm::Value* old_shadow_frame_;
-
- private:
-  art::CompilerDriver* const driver_;
-
-  const art::DexCompilationUnit* const dex_compilation_unit_;
-
-  llvm::Function* func_;
-
-  std::vector<llvm::BasicBlock*> basic_blocks_;
-
-  std::vector<llvm::BasicBlock*> basic_block_landing_pads_;
-  llvm::BasicBlock* current_bb_;
-  std::map<llvm::BasicBlock*, std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*>>>
-      landing_pad_phi_mapping_;
-  llvm::BasicBlock* basic_block_unwind_;
-
-  // Maps each vreg to its shadow frame address.
-  std::vector<llvm::Value*> shadow_frame_vreg_addresses_;
-
-  bool changed_;
-
- private:
-  //----------------------------------------------------------------------------
-  // Constant for GBC expansion
-  //----------------------------------------------------------------------------
-  enum IntegerShiftKind {
-    kIntegerSHL,
-    kIntegerSHR,
-    kIntegerUSHR,
-  };
-
- private:
-  //----------------------------------------------------------------------------
-  // Helper function for GBC expansion
-  //----------------------------------------------------------------------------
-
-  llvm::Value* ExpandToRuntime(RuntimeId rt, llvm::CallInst& inst);
-
-  uint64_t LV2UInt(llvm::Value* lv) {
-    return llvm::cast<llvm::ConstantInt>(lv)->getZExtValue();
-  }
-
-  int64_t LV2SInt(llvm::Value* lv) {
-    return llvm::cast<llvm::ConstantInt>(lv)->getSExtValue();
-  }
-
- private:
-  // TODO: Almost all Emit* are directly copy-n-paste from MethodCompiler.
-  // Refactor these utility functions from MethodCompiler to avoid forking.
-
-  void EmitStackOverflowCheck(llvm::Instruction* first_non_alloca);
-
-  void RewriteFunction();
-
-  void RewriteBasicBlock(llvm::BasicBlock* original_block);
-
-  void UpdatePhiInstruction(llvm::BasicBlock* old_basic_block,
-                            llvm::BasicBlock* new_basic_block);
-
-
-  // Sign or zero extend category 1 types < 32bits in size to 32bits.
-  llvm::Value* SignOrZeroExtendCat1Types(llvm::Value* value, JType jty);
-
-  // Truncate category 1 types from 32bits to the given JType size.
-  llvm::Value* TruncateCat1Types(llvm::Value* value, JType jty);
-
-  //----------------------------------------------------------------------------
-  // Dex cache code generation helper function
-  //----------------------------------------------------------------------------
-  llvm::Value* EmitLoadDexCacheAddr(art::MemberOffset dex_cache_offset);
-
-  llvm::Value* EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx);
-
-  llvm::Value* EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx);
-
-  llvm::Value* EmitLoadDexCacheStringFieldAddr(uint32_t string_idx);
-
-  //----------------------------------------------------------------------------
-  // Code generation helper function
-  //----------------------------------------------------------------------------
-  llvm::Value* EmitLoadMethodObjectAddr();
-
-  llvm::Value* EmitLoadArrayLength(llvm::Value* array);
-
-  llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
-
-  llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
-                                                     llvm::Value* this_addr);
-
-  llvm::Value* EmitArrayGEP(llvm::Value* array_addr,
-                            llvm::Value* index_value,
-                            JType elem_jty);
-
-  //----------------------------------------------------------------------------
-  // Invoke helper function
-  //----------------------------------------------------------------------------
-  llvm::Value* EmitInvoke(llvm::CallInst& call_inst);
-
-  //----------------------------------------------------------------------------
-  // Inlining helper functions
-  //----------------------------------------------------------------------------
-  bool EmitIntrinsic(llvm::CallInst& call_inst, llvm::Value** result);
-
-  bool EmitIntrinsicStringLengthOrIsEmpty(llvm::CallInst& call_inst,
-                                          llvm::Value** result, bool is_empty);
-
- private:
-  //----------------------------------------------------------------------------
-  // Expand Greenland intrinsics
-  //----------------------------------------------------------------------------
-  void Expand_TestSuspend(llvm::CallInst& call_inst);
-
-  void Expand_MarkGCCard(llvm::CallInst& call_inst);
-
-  llvm::Value* Expand_LoadStringFromDexCache(llvm::Value* string_idx_value);
-
-  llvm::Value* Expand_LoadTypeFromDexCache(llvm::Value* type_idx_value);
-
-  void Expand_LockObject(llvm::Value* obj);
-
-  void Expand_UnlockObject(llvm::Value* obj);
-
-  llvm::Value* Expand_ArrayGet(llvm::Value* array_addr,
-                               llvm::Value* index_value,
-                               JType elem_jty);
-
-  void Expand_ArrayPut(llvm::Value* new_value,
-                       llvm::Value* array_addr,
-                       llvm::Value* index_value,
-                       JType elem_jty);
-
-  void Expand_FilledNewArray(llvm::CallInst& call_inst);
-
-  llvm::Value* Expand_IGetFast(llvm::Value* field_offset_value,
-                               llvm::Value* is_volatile_value,
-                               llvm::Value* object_addr,
-                               JType field_jty);
-
-  void Expand_IPutFast(llvm::Value* field_offset_value,
-                       llvm::Value* is_volatile_value,
-                       llvm::Value* object_addr,
-                       llvm::Value* new_value,
-                       JType field_jty);
-
-  llvm::Value* Expand_SGetFast(llvm::Value* static_storage_addr,
-                               llvm::Value* field_offset_value,
-                               llvm::Value* is_volatile_value,
-                               JType field_jty);
-
-  void Expand_SPutFast(llvm::Value* static_storage_addr,
-                       llvm::Value* field_offset_value,
-                       llvm::Value* is_volatile_value,
-                       llvm::Value* new_value,
-                       JType field_jty);
-
-  llvm::Value* Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr);
-
-  llvm::Value*
-  Expand_GetSDCalleeMethodObjAddrFast(llvm::Value* callee_method_idx_value);
-
-  llvm::Value*
-  Expand_GetVirtualCalleeMethodObjAddrFast(llvm::Value* vtable_idx_value,
-                                           llvm::Value* this_addr);
-
-  llvm::Value* Expand_Invoke(llvm::CallInst& call_inst);
-
-  llvm::Value* Expand_DivRem(llvm::CallInst& call_inst, bool is_div, JType op_jty);
-
-  void Expand_AllocaShadowFrame(llvm::Value* num_vregs_value);
-
-  void Expand_SetVReg(llvm::Value* entry_idx, llvm::Value* obj);
-
-  void Expand_PopShadowFrame();
-
-  void Expand_UpdateDexPC(llvm::Value* dex_pc_value);
-
-  //----------------------------------------------------------------------------
-  // Quick
-  //----------------------------------------------------------------------------
-
-  llvm::Value* Expand_FPCompare(llvm::Value* src1_value,
-                                llvm::Value* src2_value,
-                                bool gt_bias);
-
-  llvm::Value* Expand_LongCompare(llvm::Value* src1_value, llvm::Value* src2_value);
-
-  llvm::Value* EmitCompareResultSelection(llvm::Value* cmp_eq,
-                                          llvm::Value* cmp_lt);
-
-  llvm::Value* EmitLoadConstantClass(uint32_t dex_pc, uint32_t type_idx);
-  llvm::Value* EmitLoadStaticStorage(uint32_t dex_pc, uint32_t type_idx);
-
-  llvm::Value* Expand_HLIGet(llvm::CallInst& call_inst, JType field_jty);
-  void Expand_HLIPut(llvm::CallInst& call_inst, JType field_jty);
-
-  llvm::Value* Expand_HLSget(llvm::CallInst& call_inst, JType field_jty);
-  void Expand_HLSput(llvm::CallInst& call_inst, JType field_jty);
-
-  llvm::Value* Expand_HLArrayGet(llvm::CallInst& call_inst, JType field_jty);
-  void Expand_HLArrayPut(llvm::CallInst& call_inst, JType field_jty);
-
-  llvm::Value* Expand_ConstString(llvm::CallInst& call_inst);
-  llvm::Value* Expand_ConstClass(llvm::CallInst& call_inst);
-
-  void Expand_MonitorEnter(llvm::CallInst& call_inst);
-  void Expand_MonitorExit(llvm::CallInst& call_inst);
-
-  void Expand_HLCheckCast(llvm::CallInst& call_inst);
-  llvm::Value* Expand_InstanceOf(llvm::CallInst& call_inst);
-
-  llvm::Value* Expand_NewInstance(llvm::CallInst& call_inst);
-
-  llvm::Value* Expand_HLInvoke(llvm::CallInst& call_inst);
-
-  llvm::Value* Expand_OptArrayLength(llvm::CallInst& call_inst);
-  llvm::Value* Expand_NewArray(llvm::CallInst& call_inst);
-  llvm::Value* Expand_HLFilledNewArray(llvm::CallInst& call_inst);
-  void Expand_HLFillArrayData(llvm::CallInst& call_inst);
-
-  llvm::Value* EmitAllocNewArray(uint32_t dex_pc,
-                                 llvm::Value* array_length_value,
-                                 uint32_t type_idx,
-                                 bool is_filled_new_array);
-
-  llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
-                                                        art::InvokeType invoke_type,
-                                                        llvm::Value* this_addr,
-                                                        uint32_t dex_pc,
-                                                        bool is_fast_path);
-
-  void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr);
-
-  void EmitUpdateDexPC(uint32_t dex_pc);
-
-  void EmitGuard_DivZeroException(uint32_t dex_pc,
-                                  llvm::Value* denominator,
-                                  JType op_jty);
-
-  void EmitGuard_NullPointerException(uint32_t dex_pc, llvm::Value* object,
-                                      int opt_flags);
-
-  void EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
-                                                llvm::Value* array,
-                                                llvm::Value* index,
-                                                int opt_flags);
-
-  llvm::FunctionType* GetFunctionType(llvm::Type* ret_type, uint32_t method_idx, bool is_static);
-
-  llvm::BasicBlock* GetBasicBlock(uint32_t dex_pc);
-
-  llvm::BasicBlock* CreateBasicBlockWithDexPC(uint32_t dex_pc,
-                                              const char* postfix);
-
-  int32_t GetTryItemOffset(uint32_t dex_pc);
-
-  llvm::BasicBlock* GetLandingPadBasicBlock(uint32_t dex_pc);
-
-  llvm::BasicBlock* GetUnwindBasicBlock();
-
-  void EmitGuard_ExceptionLandingPad(uint32_t dex_pc);
-
-  void EmitBranchExceptionLandingPad(uint32_t dex_pc);
-
-  //----------------------------------------------------------------------------
-  // Expand Arithmetic Helper Intrinsics
-  //----------------------------------------------------------------------------
-
-  llvm::Value* Expand_IntegerShift(llvm::Value* src1_value,
-                                   llvm::Value* src2_value,
-                                   IntegerShiftKind kind,
-                                   JType op_jty);
-
- public:
-  static char ID;
-
-  GBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb,
-                  art::CompilerDriver* driver, const art::DexCompilationUnit* dex_compilation_unit)
-      : llvm::FunctionPass(ID), intrinsic_helper_(intrinsic_helper), irb_(irb),
-        context_(irb.getContext()), rtb_(irb.Runtime()),
-        shadow_frame_(NULL), old_shadow_frame_(NULL),
-        driver_(driver),
-        dex_compilation_unit_(dex_compilation_unit),
-        func_(NULL), current_bb_(NULL), basic_block_unwind_(NULL), changed_(false) {}
-
-  bool runOnFunction(llvm::Function& func);
-
- private:
-  void InsertStackOverflowCheck(llvm::Function& func);
-
-  llvm::Value* ExpandIntrinsic(IntrinsicHelper::IntrinsicId intr_id,
-                               llvm::CallInst& call_inst);
-};
-
-char GBCExpanderPass::ID = 0;
-
-bool GBCExpanderPass::runOnFunction(llvm::Function& func) {
-  VLOG(compiler) << "GBC expansion on " << func.getName().str();
-
-  // Runtime support or stub
-  if (dex_compilation_unit_ == NULL) {
-    return false;
-  }
-
-  // Setup rewrite context
-  shadow_frame_ = NULL;
-  old_shadow_frame_ = NULL;
-  func_ = &func;
-  changed_ = false;  // Assume unchanged
-
-  shadow_frame_vreg_addresses_.resize(dex_compilation_unit_->GetCodeItem()->registers_size_, NULL);
-  basic_blocks_.resize(dex_compilation_unit_->GetCodeItem()->insns_size_in_code_units_);
-  basic_block_landing_pads_.resize(dex_compilation_unit_->GetCodeItem()->tries_size_, NULL);
-  basic_block_unwind_ = NULL;
-  for (llvm::Function::iterator bb_iter = func_->begin(), bb_end = func_->end();
-       bb_iter != bb_end;
-       ++bb_iter) {
-    if (bb_iter->begin()->getMetadata("DexOff") == NULL) {
-      continue;
-    }
-    uint32_t dex_pc = LV2UInt(bb_iter->begin()->getMetadata("DexOff")->getOperand(0));
-    basic_blocks_[dex_pc] = bb_iter;
-  }
-
-  // Insert stack overflow check
-  InsertStackOverflowCheck(func);  // TODO: Use intrinsic.
-
-  // Rewrite the intrinsics
-  RewriteFunction();
-
-  VERIFY_LLVM_FUNCTION(func);
-
-  return changed_;
-}
-
-void GBCExpanderPass::RewriteBasicBlock(llvm::BasicBlock* original_block) {
-  llvm::BasicBlock* curr_basic_block = original_block;
-
-  llvm::BasicBlock::iterator inst_iter = original_block->begin();
-  llvm::BasicBlock::iterator inst_end = original_block->end();
-
-  while (inst_iter != inst_end) {
-    llvm::CallInst* call_inst = llvm::dyn_cast<llvm::CallInst>(inst_iter);
-    IntrinsicHelper::IntrinsicId intr_id = IntrinsicHelper::UnknownId;
-
-    if (call_inst) {
-      llvm::Function* callee_func = call_inst->getCalledFunction();
-      intr_id = intrinsic_helper_.GetIntrinsicId(callee_func);
-    }
-
-    if (intr_id == IntrinsicHelper::UnknownId) {
-      // This is not intrinsic call.  Skip this instruction.
-      ++inst_iter;
-      continue;
-    }
-
-    // Rewrite the intrinsic and change the function
-    changed_ = true;
-    irb_.SetInsertPoint(inst_iter);
-
-    // Expand the intrinsic
-    if (llvm::Value* new_value = ExpandIntrinsic(intr_id, *call_inst)) {
-      inst_iter->replaceAllUsesWith(new_value);
-    }
-
-    // Remove the old intrinsic call instruction
-    llvm::BasicBlock::iterator old_inst = inst_iter++;
-    old_inst->eraseFromParent();
-
-    // Splice the instruction to the new basic block
-    llvm::BasicBlock* next_basic_block = irb_.GetInsertBlock();
-    if (next_basic_block != curr_basic_block) {
-      next_basic_block->getInstList().splice(
-          irb_.GetInsertPoint(), curr_basic_block->getInstList(),
-          inst_iter, inst_end);
-      curr_basic_block = next_basic_block;
-      inst_end = curr_basic_block->end();
-    }
-  }
-}
-
-
-void GBCExpanderPass::RewriteFunction() {
-  size_t num_basic_blocks = func_->getBasicBlockList().size();
-  // NOTE: We are not using (bb_iter != bb_end) as the for-loop condition,
-  // because we will create new basic block while expanding the intrinsics.
-  // We only want to iterate through the input basic blocks.
-
-  landing_pad_phi_mapping_.clear();
-
-  for (llvm::Function::iterator bb_iter = func_->begin();
-       num_basic_blocks > 0; ++bb_iter, --num_basic_blocks) {
-    // Set insert point to current basic block.
-    irb_.SetInsertPoint(bb_iter);
-
-    current_bb_ = bb_iter;
-
-    // Rewrite the basic block
-    RewriteBasicBlock(bb_iter);
-
-    // Update the phi-instructions in the successor basic block
-    llvm::BasicBlock* last_block = irb_.GetInsertBlock();
-    if (last_block != bb_iter) {
-      UpdatePhiInstruction(bb_iter, last_block);
-    }
-  }
-
-  typedef std::map<llvm::PHINode*, llvm::PHINode*> HandlerPHIMap;
-  HandlerPHIMap handler_phi;
-  // Iterate every used landing pad basic block
-  for (size_t i = 0, ei = basic_block_landing_pads_.size(); i != ei; ++i) {
-    llvm::BasicBlock* lbb = basic_block_landing_pads_[i];
-    if (lbb == NULL) {
-      continue;
-    }
-
-    llvm::TerminatorInst* term_inst = lbb->getTerminator();
-    std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*>>& rewrite_pair
-        = landing_pad_phi_mapping_[lbb];
-    irb_.SetInsertPoint(lbb->begin());
-
-    // Iterate every succeeding basic block (catch block)
-    for (unsigned succ_iter = 0, succ_end = term_inst->getNumSuccessors();
-         succ_iter != succ_end; ++succ_iter) {
-      llvm::BasicBlock* succ_basic_block = term_inst->getSuccessor(succ_iter);
-
-      // Iterate every phi instructions in the succeeding basic block
-      for (llvm::BasicBlock::iterator
-           inst_iter = succ_basic_block->begin(),
-           inst_end = succ_basic_block->end();
-           inst_iter != inst_end; ++inst_iter) {
-        llvm::PHINode *phi = llvm::dyn_cast<llvm::PHINode>(inst_iter);
-
-        if (!phi) {
-          break;  // Meet non-phi instruction.  Done.
-        }
-
-        if (handler_phi[phi] == NULL) {
-          handler_phi[phi] = llvm::PHINode::Create(phi->getType(), 1);
-        }
-
-        // Create new_phi in landing pad
-        llvm::PHINode* new_phi = irb_.CreatePHI(phi->getType(), rewrite_pair.size());
-        // Insert all incoming value into new_phi by rewrite_pair
-        for (size_t j = 0, ej = rewrite_pair.size(); j != ej; ++j) {
-          llvm::BasicBlock* old_bb = rewrite_pair[j].first;
-          llvm::BasicBlock* new_bb = rewrite_pair[j].second;
-          new_phi->addIncoming(phi->getIncomingValueForBlock(old_bb), new_bb);
-        }
-        // Delete all incoming value from phi by rewrite_pair
-        for (size_t j = 0, ej = rewrite_pair.size(); j != ej; ++j) {
-          llvm::BasicBlock* old_bb = rewrite_pair[j].first;
-          int old_bb_idx = phi->getBasicBlockIndex(old_bb);
-          if (old_bb_idx >= 0) {
-            phi->removeIncomingValue(old_bb_idx, false);
-          }
-        }
-        // Insert new_phi into new handler phi
-        handler_phi[phi]->addIncoming(new_phi, lbb);
-      }
-    }
-  }
-
-  // Replace all handler phi
-  // We can't just use the old handler phi, because some exception edges will disappear after we
-  // compute fast-path.
-  for (HandlerPHIMap::iterator it = handler_phi.begin(); it != handler_phi.end(); ++it) {
-    llvm::PHINode* old_phi = it->first;
-    llvm::PHINode* new_phi = it->second;
-    new_phi->insertBefore(old_phi);
-    old_phi->replaceAllUsesWith(new_phi);
-    old_phi->eraseFromParent();
-  }
-}
-
-void GBCExpanderPass::UpdatePhiInstruction(llvm::BasicBlock* old_basic_block,
-                                           llvm::BasicBlock* new_basic_block) {
-  llvm::TerminatorInst* term_inst = new_basic_block->getTerminator();
-
-  if (!term_inst) {
-    return;  // No terminating instruction in new_basic_block.  Nothing to do.
-  }
-
-  // Iterate every succeeding basic block
-  for (unsigned succ_iter = 0, succ_end = term_inst->getNumSuccessors();
-       succ_iter != succ_end; ++succ_iter) {
-    llvm::BasicBlock* succ_basic_block = term_inst->getSuccessor(succ_iter);
-
-    // Iterate every phi instructions in the succeeding basic block
-    for (llvm::BasicBlock::iterator
-         inst_iter = succ_basic_block->begin(),
-         inst_end = succ_basic_block->end();
-         inst_iter != inst_end; ++inst_iter) {
-      llvm::PHINode *phi = llvm::dyn_cast<llvm::PHINode>(inst_iter);
-
-      if (!phi) {
-        break;  // Meet non-phi instruction.  Done.
-      }
-
-      // Update the incoming block of this phi instruction
-      for (llvm::PHINode::block_iterator
-           ibb_iter = phi->block_begin(), ibb_end = phi->block_end();
-           ibb_iter != ibb_end; ++ibb_iter) {
-        if (*ibb_iter == old_basic_block) {
-          *ibb_iter = new_basic_block;
-        }
-      }
-    }
-  }
-}
-
-llvm::Value* GBCExpanderPass::ExpandToRuntime(RuntimeId rt, llvm::CallInst& inst) {
-  // Some GBC intrinsic can directly replace with IBC runtime. "Directly" means
-  // the arguments passed to the GBC intrinsic are as the same as IBC runtime
-  // function, therefore only called function is needed to change.
-  unsigned num_args = inst.getNumArgOperands();
-
-  if (num_args <= 0) {
-    return irb_.CreateCall(irb_.GetRuntime(rt));
-  } else {
-    std::vector<llvm::Value*> args;
-    for (unsigned i = 0; i < num_args; i++) {
-      args.push_back(inst.getArgOperand(i));
-    }
-
-    return irb_.CreateCall(irb_.GetRuntime(rt), args);
-  }
-}
-
-void
-GBCExpanderPass::EmitStackOverflowCheck(llvm::Instruction* first_non_alloca) {
-  llvm::Function* func = first_non_alloca->getParent()->getParent();
-  llvm::Module* module = func->getParent();
-
-  // Call llvm intrinsic function to get frame address.
-  llvm::Function* frameaddress =
-      llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::frameaddress);
-
-  // The type of llvm::frameaddress is: i8* @llvm.frameaddress(i32)
-  llvm::Value* frame_address = irb_.CreateCall(frameaddress, irb_.getInt32(0));
-
-  // Cast i8* to int
-  frame_address = irb_.CreatePtrToInt(frame_address, irb_.getPtrEquivIntTy());
-
-  // Get thread.stack_end_
-  llvm::Value* stack_end =
-    irb_.Runtime().EmitLoadFromThreadOffset(art::Thread::StackEndOffset().Int32Value(),
-                                            irb_.getPtrEquivIntTy(),
-                                            kTBAARuntimeInfo);
-
-  // Check the frame address < thread.stack_end_ ?
-  llvm::Value* is_stack_overflow = irb_.CreateICmpULT(frame_address, stack_end);
-
-  llvm::BasicBlock* block_exception =
-      llvm::BasicBlock::Create(context_, "stack_overflow", func);
-
-  llvm::BasicBlock* block_continue =
-      llvm::BasicBlock::Create(context_, "stack_overflow_cont", func);
-
-  irb_.CreateCondBr(is_stack_overflow, block_exception, block_continue, kUnlikely);
-
-  // If stack overflow, throw exception.
-  irb_.SetInsertPoint(block_exception);
-  irb_.CreateCall(irb_.GetRuntime(ThrowStackOverflowException));
-
-  // Unwind.
-  llvm::Type* ret_type = func->getReturnType();
-  if (ret_type->isVoidTy()) {
-    irb_.CreateRetVoid();
-  } else {
-    // The return value is ignored when there's an exception. MethodCompiler
-    // returns zero value under the the corresponding return type  in this case.
-    // GBCExpander returns LLVM undef value here for brevity
-    irb_.CreateRet(llvm::UndefValue::get(ret_type));
-  }
-
-  irb_.SetInsertPoint(block_continue);
-}
-
-llvm::Value* GBCExpanderPass::EmitLoadDexCacheAddr(art::MemberOffset offset) {
-  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-  return irb_.LoadFromObjectOffset(method_object_addr,
-                                   offset.Int32Value(),
-                                   irb_.getJObjectTy(),
-                                   kTBAAConstJObject);
-}
-
-llvm::Value*
-GBCExpanderPass::EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx) {
-  llvm::Value* resolved_type_dex_cache_addr =
-    EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheResolvedTypesOffset());
-
-  llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx);
-
-  return EmitArrayGEP(resolved_type_dex_cache_addr, type_idx_value, kObject);
-}
-
-llvm::Value* GBCExpanderPass::
-EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx) {
-  llvm::Value* resolved_method_dex_cache_addr =
-    EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheResolvedMethodsOffset());
-
-  llvm::Value* method_idx_value = irb_.getPtrEquivInt(method_idx);
-
-  return EmitArrayGEP(resolved_method_dex_cache_addr, method_idx_value, kObject);
-}
-
-llvm::Value* GBCExpanderPass::
-EmitLoadDexCacheStringFieldAddr(uint32_t string_idx) {
-  llvm::Value* string_dex_cache_addr =
-    EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheStringsOffset());
-
-  llvm::Value* string_idx_value = irb_.getPtrEquivInt(string_idx);
-
-  return EmitArrayGEP(string_dex_cache_addr, string_idx_value, kObject);
-}
-
-llvm::Value* GBCExpanderPass::EmitLoadMethodObjectAddr() {
-  llvm::Function* parent_func = irb_.GetInsertBlock()->getParent();
-  return parent_func->arg_begin();
-}
-
-llvm::Value* GBCExpanderPass::EmitLoadArrayLength(llvm::Value* array) {
-  // Load array length
-  return irb_.LoadFromObjectOffset(array,
-                                   art::mirror::Array::LengthOffset().Int32Value(),
-                                   irb_.getJIntTy(),
-                                   kTBAAConstJObject);
-}
-
-llvm::Value*
-GBCExpanderPass::EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx) {
-  llvm::Value* callee_method_object_field_addr =
-    EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
-
-  return irb_.CreateLoad(callee_method_object_field_addr, kTBAARuntimeInfo);
-}
-
-llvm::Value* GBCExpanderPass::
-EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx, llvm::Value* this_addr) {
-  // Load class object of *this* pointer
-  llvm::Value* class_object_addr =
-    irb_.LoadFromObjectOffset(this_addr,
-                              art::mirror::Object::ClassOffset().Int32Value(),
-                              irb_.getJObjectTy(),
-                              kTBAAConstJObject);
-
-  // Load vtable address
-  llvm::Value* vtable_addr =
-    irb_.LoadFromObjectOffset(class_object_addr,
-                              art::mirror::Class::VTableOffset().Int32Value(),
-                              irb_.getJObjectTy(),
-                              kTBAAConstJObject);
-
-  // Load callee method object
-  llvm::Value* vtable_idx_value =
-    irb_.getPtrEquivInt(static_cast<uint64_t>(vtable_idx));
-
-  llvm::Value* method_field_addr =
-    EmitArrayGEP(vtable_addr, vtable_idx_value, kObject);
-
-  return irb_.CreateLoad(method_field_addr, kTBAAConstJObject);
-}
-
-// Emit Array GetElementPtr
-llvm::Value* GBCExpanderPass::EmitArrayGEP(llvm::Value* array_addr,
-                                           llvm::Value* index_value,
-                                           JType elem_jty) {
-  int data_offset;
-  if (elem_jty == kLong || elem_jty == kDouble ||
-      (elem_jty == kObject && sizeof(uint64_t) == sizeof(art::mirror::Object*))) {
-    data_offset = art::mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
-  } else {
-    data_offset = art::mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
-  }
-
-  llvm::Constant* data_offset_value =
-    irb_.getPtrEquivInt(data_offset);
-
-  llvm::Type* elem_type = irb_.getJType(elem_jty);
-
-  llvm::Value* array_data_addr =
-    irb_.CreatePtrDisp(array_addr, data_offset_value,
-                       elem_type->getPointerTo());
-
-  return irb_.CreateGEP(array_data_addr, index_value);
-}
-
-llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  art::InvokeType invoke_type =
-      static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
-  bool is_static = (invoke_type == art::kStatic);
-  art::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
-                                     LV2UInt(call_inst.getArgOperand(1)));
-
-  // Load *this* actual parameter
-  llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL;
-
-  // Compute invoke related information for compiler decision
-  int vtable_idx = -1;
-  uintptr_t direct_code = 0;
-  uintptr_t direct_method = 0;
-  bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc,
-                                                 true, true,
-                                                 &invoke_type, &target_method,
-                                                 &vtable_idx,
-                                                 &direct_code, &direct_method);
-  // Load the method object
-  llvm::Value* callee_method_object_addr = NULL;
-
-  if (!is_fast_path) {
-    callee_method_object_addr =
-        EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, invoke_type,
-                                                 this_addr, dex_pc, is_fast_path);
-  } else {
-    switch (invoke_type) {
-      case art::kStatic:
-      case art::kDirect:
-        if (direct_method != 0u &&
-            direct_method != static_cast<uintptr_t>(-1)) {
-          callee_method_object_addr =
-              irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_method),
-                                  irb_.getJObjectTy());
-        } else {
-          callee_method_object_addr =
-              EmitLoadSDCalleeMethodObjectAddr(target_method.dex_method_index);
-        }
-        break;
-
-      case art::kVirtual:
-        DCHECK_NE(vtable_idx, -1);
-        callee_method_object_addr =
-            EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr);
-        break;
-
-      case art::kSuper:
-        LOG(FATAL) << "invoke-super should be promoted to invoke-direct in "
-        "the fast path.";
-        break;
-
-      case art::kInterface:
-        callee_method_object_addr =
-            EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index,
-                                                     invoke_type, this_addr,
-                                                     dex_pc, is_fast_path);
-        break;
-    }
-  }
-
-  // Load the actual parameter
-  std::vector<llvm::Value*> args;
-
-  args.push_back(callee_method_object_addr);  // method object for callee
-
-  for (uint32_t i = 3; i < call_inst.getNumArgOperands(); ++i) {
-    args.push_back(call_inst.getArgOperand(i));
-  }
-
-  llvm::Value* code_addr;
-  llvm::Type* func_type = GetFunctionType(call_inst.getType(),
-                                          target_method.dex_method_index, is_static);
-  if (direct_code != 0u && direct_code != static_cast<uintptr_t>(-1)) {
-    code_addr =
-        irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code),
-                            func_type->getPointerTo());
-  } else {
-    code_addr =
-        irb_.LoadFromObjectOffset(callee_method_object_addr,
-                                  art::mirror::ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value(),
-                                  func_type->getPointerTo(), kTBAARuntimeInfo);
-  }
-
-  // Invoke callee
-  EmitUpdateDexPC(dex_pc);
-  llvm::Value* retval = irb_.CreateCall(code_addr, args);
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  return retval;
-}
-
-bool GBCExpanderPass::EmitIntrinsic(llvm::CallInst& call_inst,
-                                    llvm::Value** result) {
-  DCHECK(result != NULL);
-
-  uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1));
-  std::string callee_method_name(
-      PrettyMethod(callee_method_idx, *dex_compilation_unit_->GetDexFile()));
-
-  if (callee_method_name == "int java.lang.String.length()") {
-    return EmitIntrinsicStringLengthOrIsEmpty(call_inst, result,
-                                              false /* is_empty */);
-  }
-  if (callee_method_name == "boolean java.lang.String.isEmpty()") {
-    return EmitIntrinsicStringLengthOrIsEmpty(call_inst, result,
-                                              true /* is_empty */);
-  }
-
-  *result = NULL;
-  return false;
-}
-
-bool GBCExpanderPass::EmitIntrinsicStringLengthOrIsEmpty(llvm::CallInst& call_inst,
-                                                         llvm::Value** result,
-                                                         bool is_empty) {
-  art::InvokeType invoke_type =
-        static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
-  DCHECK_NE(invoke_type, art::kStatic);
-  DCHECK_EQ(call_inst.getNumArgOperands(), 4U);
-
-  llvm::Value* this_object = call_inst.getArgOperand(3);
-  llvm::Value* string_count =
-      irb_.LoadFromObjectOffset(this_object,
-                                art::mirror::String::CountOffset().Int32Value(),
-                                irb_.getJIntTy(),
-                                kTBAAConstJObject);
-  if (is_empty) {
-    llvm::Value* count_equals_zero = irb_.CreateICmpEQ(string_count,
-                                                       irb_.getJInt(0));
-    llvm::Value* is_empty = irb_.CreateSelect(count_equals_zero,
-                                              irb_.getJBoolean(true),
-                                              irb_.getJBoolean(false));
-    is_empty = SignOrZeroExtendCat1Types(is_empty, kBoolean);
-    *result = is_empty;
-  } else {
-    *result = string_count;
-  }
-  return true;
-}
-
-void GBCExpanderPass::Expand_TestSuspend(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-
-  llvm::Value* suspend_count =
-      irb_.Runtime().EmitLoadFromThreadOffset(art::Thread::ThreadFlagsOffset().Int32Value(),
-                                              irb_.getInt16Ty(),
-                                              kTBAARuntimeInfo);
-  llvm::Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getInt16(0));
-
-  llvm::BasicBlock* basic_block_suspend = CreateBasicBlockWithDexPC(dex_pc, "suspend");
-  llvm::BasicBlock* basic_block_cont = CreateBasicBlockWithDexPC(dex_pc, "suspend_cont");
-
-  irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_cont, kUnlikely);
-
-  irb_.SetInsertPoint(basic_block_suspend);
-  if (dex_pc != art::DexFile::kDexNoIndex) {
-    EmitUpdateDexPC(dex_pc);
-  }
-  irb_.Runtime().EmitTestSuspend();
-
-  llvm::BasicBlock* basic_block_exception = CreateBasicBlockWithDexPC(dex_pc, "exception");
-  llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
-  irb_.CreateCondBr(exception_pending, basic_block_exception, basic_block_cont, kUnlikely);
-
-  irb_.SetInsertPoint(basic_block_exception);
-  llvm::Type* ret_type = call_inst.getParent()->getParent()->getReturnType();
-  if (ret_type->isVoidTy()) {
-    irb_.CreateRetVoid();
-  } else {
-    // The return value is ignored when there's an exception.
-    irb_.CreateRet(llvm::UndefValue::get(ret_type));
-  }
-
-  irb_.SetInsertPoint(basic_block_cont);
-  return;
-}
-
-void GBCExpanderPass::Expand_MarkGCCard(llvm::CallInst& call_inst) {
-  irb_.Runtime().EmitMarkGCCard(call_inst.getArgOperand(0), call_inst.getArgOperand(1));
-  return;
-}
-
-llvm::Value*
-GBCExpanderPass::Expand_LoadStringFromDexCache(llvm::Value* string_idx_value) {
-  uint32_t string_idx =
-    llvm::cast<llvm::ConstantInt>(string_idx_value)->getZExtValue();
-
-  llvm::Value* string_field_addr = EmitLoadDexCacheStringFieldAddr(string_idx);
-
-  return irb_.CreateLoad(string_field_addr, kTBAARuntimeInfo);
-}
-
-llvm::Value*
-GBCExpanderPass::Expand_LoadTypeFromDexCache(llvm::Value* type_idx_value) {
-  uint32_t type_idx =
-    llvm::cast<llvm::ConstantInt>(type_idx_value)->getZExtValue();
-
-  llvm::Value* type_field_addr =
-    EmitLoadDexCacheResolvedTypeFieldAddr(type_idx);
-
-  return irb_.CreateLoad(type_field_addr, kTBAARuntimeInfo);
-}
-
-void GBCExpanderPass::Expand_LockObject(llvm::Value* obj) {
-  rtb_.EmitLockObject(obj);
-  return;
-}
-
-void GBCExpanderPass::Expand_UnlockObject(llvm::Value* obj) {
-  rtb_.EmitUnlockObject(obj);
-  return;
-}
-
-llvm::Value* GBCExpanderPass::Expand_ArrayGet(llvm::Value* array_addr,
-                                              llvm::Value* index_value,
-                                              JType elem_jty) {
-  llvm::Value* array_elem_addr =
-    EmitArrayGEP(array_addr, index_value, elem_jty);
-
-  return irb_.CreateLoad(array_elem_addr, kTBAAHeapArray, elem_jty);
-}
-
-void GBCExpanderPass::Expand_ArrayPut(llvm::Value* new_value,
-                                      llvm::Value* array_addr,
-                                      llvm::Value* index_value,
-                                      JType elem_jty) {
-  llvm::Value* array_elem_addr =
-    EmitArrayGEP(array_addr, index_value, elem_jty);
-
-  irb_.CreateStore(new_value, array_elem_addr, kTBAAHeapArray, elem_jty);
-
-  return;
-}
-
-void GBCExpanderPass::Expand_FilledNewArray(llvm::CallInst& call_inst) {
-  // Most of the codes refer to MethodCompiler::EmitInsn_FilledNewArray
-  llvm::Value* array = call_inst.getArgOperand(0);
-
-  uint32_t element_jty =
-    llvm::cast<llvm::ConstantInt>(call_inst.getArgOperand(1))->getZExtValue();
-
-  DCHECK_GT(call_inst.getNumArgOperands(), 2U);
-  unsigned num_elements = (call_inst.getNumArgOperands() - 2);
-
-  bool is_elem_int_ty = (static_cast<JType>(element_jty) == kInt);
-
-  uint32_t alignment;
-  llvm::Constant* elem_size;
-  llvm::PointerType* field_type;
-
-  // NOTE: Currently filled-new-array only supports 'L', '[', and 'I'
-  // as the element, thus we are only checking 2 cases: primitive int and
-  // non-primitive type.
-  if (is_elem_int_ty) {
-    alignment = sizeof(int32_t);
-    elem_size = irb_.getPtrEquivInt(sizeof(int32_t));
-    field_type = irb_.getJIntTy()->getPointerTo();
-  } else {
-    alignment = irb_.getSizeOfPtrEquivInt();
-    elem_size = irb_.getSizeOfPtrEquivIntValue();
-    field_type = irb_.getJObjectTy()->getPointerTo();
-  }
-
-  llvm::Value* data_field_offset =
-    irb_.getPtrEquivInt(art::mirror::Array::DataOffset(alignment).Int32Value());
-
-  llvm::Value* data_field_addr =
-    irb_.CreatePtrDisp(array, data_field_offset, field_type);
-
-  for (unsigned i = 0; i < num_elements; ++i) {
-    // Values to fill the array begin at the 3rd argument
-    llvm::Value* reg_value = call_inst.getArgOperand(2 + i);
-
-    irb_.CreateStore(reg_value, data_field_addr, kTBAAHeapArray);
-
-    data_field_addr =
-      irb_.CreatePtrDisp(data_field_addr, elem_size, field_type);
-  }
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::Expand_IGetFast(llvm::Value* field_offset_value,
-                                              llvm::Value* /*is_volatile_value*/,
-                                              llvm::Value* object_addr,
-                                              JType field_jty) {
-  int field_offset =
-    llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
-
-  DCHECK_GE(field_offset, 0);
-
-  llvm::PointerType* field_type =
-    irb_.getJType(field_jty)->getPointerTo();
-
-  field_offset_value = irb_.getPtrEquivInt(field_offset);
-
-  llvm::Value* field_addr =
-    irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
-
-  // TODO: Check is_volatile.  We need to generate atomic load instruction
-  // when is_volatile is true.
-  return irb_.CreateLoad(field_addr, kTBAAHeapInstance, field_jty);
-}
-
-void GBCExpanderPass::Expand_IPutFast(llvm::Value* field_offset_value,
-                                      llvm::Value* /* is_volatile_value */,
-                                      llvm::Value* object_addr,
-                                      llvm::Value* new_value,
-                                      JType field_jty) {
-  int field_offset =
-    llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
-
-  DCHECK_GE(field_offset, 0);
-
-  llvm::PointerType* field_type =
-    irb_.getJType(field_jty)->getPointerTo();
-
-  field_offset_value = irb_.getPtrEquivInt(field_offset);
-
-  llvm::Value* field_addr =
-    irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
-
-  // TODO: Check is_volatile.  We need to generate atomic store instruction
-  // when is_volatile is true.
-  irb_.CreateStore(new_value, field_addr, kTBAAHeapInstance, field_jty);
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::Expand_SGetFast(llvm::Value* static_storage_addr,
-                                              llvm::Value* field_offset_value,
-                                              llvm::Value* /*is_volatile_value*/,
-                                              JType field_jty) {
-  int field_offset =
-    llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
-
-  DCHECK_GE(field_offset, 0);
-
-  llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
-
-  llvm::Value* static_field_addr =
-    irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
-                       irb_.getJType(field_jty)->getPointerTo());
-
-  // TODO: Check is_volatile.  We need to generate atomic store instruction
-  // when is_volatile is true.
-  return irb_.CreateLoad(static_field_addr, kTBAAHeapStatic, field_jty);
-}
-
-void GBCExpanderPass::Expand_SPutFast(llvm::Value* static_storage_addr,
-                                      llvm::Value* field_offset_value,
-                                      llvm::Value* /* is_volatile_value */,
-                                      llvm::Value* new_value,
-                                      JType field_jty) {
-  int field_offset =
-    llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue();
-
-  DCHECK_GE(field_offset, 0);
-
-  llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
-
-  llvm::Value* static_field_addr =
-    irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
-                       irb_.getJType(field_jty)->getPointerTo());
-
-  // TODO: Check is_volatile.  We need to generate atomic store instruction
-  // when is_volatile is true.
-  irb_.CreateStore(new_value, static_field_addr, kTBAAHeapStatic, field_jty);
-
-  return;
-}
-
-llvm::Value*
-GBCExpanderPass::Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr) {
-  return irb_.LoadFromObjectOffset(method_object_addr,
-                                   art::mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                                   irb_.getJObjectTy(),
-                                   kTBAAConstJObject);
-}
-
-llvm::Value*
-GBCExpanderPass::Expand_GetSDCalleeMethodObjAddrFast(llvm::Value* callee_method_idx_value) {
-  uint32_t callee_method_idx =
-    llvm::cast<llvm::ConstantInt>(callee_method_idx_value)->getZExtValue();
-
-  return EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
-}
-
-llvm::Value* GBCExpanderPass::Expand_GetVirtualCalleeMethodObjAddrFast(
-    llvm::Value* vtable_idx_value,
-    llvm::Value* this_addr) {
-  int vtable_idx =
-    llvm::cast<llvm::ConstantInt>(vtable_idx_value)->getSExtValue();
-
-  return EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr);
-}
-
-llvm::Value* GBCExpanderPass::Expand_Invoke(llvm::CallInst& call_inst) {
-  // Most of the codes refer to MethodCompiler::EmitInsn_Invoke
-  llvm::Value* callee_method_object_addr = call_inst.getArgOperand(0);
-  unsigned num_args = call_inst.getNumArgOperands();
-  llvm::Type* ret_type = call_inst.getType();
-
-  // Determine the function type of the callee method
-  std::vector<llvm::Type*> args_type;
-  std::vector<llvm::Value*> args;
-  for (unsigned i = 0; i < num_args; i++) {
-    args.push_back(call_inst.getArgOperand(i));
-    args_type.push_back(args[i]->getType());
-  }
-
-  llvm::FunctionType* callee_method_type =
-    llvm::FunctionType::get(ret_type, args_type, false);
-
-  llvm::Value* code_addr =
-    irb_.LoadFromObjectOffset(callee_method_object_addr,
-                              art::mirror::ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value(),
-                              callee_method_type->getPointerTo(),
-                              kTBAARuntimeInfo);
-
-  // Invoke callee
-  llvm::Value* retval = irb_.CreateCall(code_addr, args);
-
-  return retval;
-}
-
-llvm::Value* GBCExpanderPass::Expand_DivRem(llvm::CallInst& call_inst,
-                                            bool is_div, JType op_jty) {
-  llvm::Value* dividend = call_inst.getArgOperand(0);
-  llvm::Value* divisor = call_inst.getArgOperand(1);
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  EmitGuard_DivZeroException(dex_pc, divisor, op_jty);
-  // Most of the codes refer to MethodCompiler::EmitIntDivRemResultComputation
-
-  // Check the special case: MININT / -1 = MININT
-  // That case will cause overflow, which is undefined behavior in llvm.
-  // So we check the divisor is -1 or not, if the divisor is -1, we do
-  // the special path to avoid undefined behavior.
-  llvm::Type* op_type = irb_.getJType(op_jty);
-  llvm::Value* zero = irb_.getJZero(op_jty);
-  llvm::Value* neg_one = llvm::ConstantInt::getSigned(op_type, -1);
-
-  llvm::Function* parent = irb_.GetInsertBlock()->getParent();
-  llvm::BasicBlock* eq_neg_one = llvm::BasicBlock::Create(context_, "", parent);
-  llvm::BasicBlock* ne_neg_one = llvm::BasicBlock::Create(context_, "", parent);
-  llvm::BasicBlock* neg_one_cont =
-    llvm::BasicBlock::Create(context_, "", parent);
-
-  llvm::Value* is_equal_neg_one = irb_.CreateICmpEQ(divisor, neg_one);
-  irb_.CreateCondBr(is_equal_neg_one, eq_neg_one, ne_neg_one, kUnlikely);
-
-  // If divisor == -1
-  irb_.SetInsertPoint(eq_neg_one);
-  llvm::Value* eq_result;
-  if (is_div) {
-    // We can just change from "dividend div -1" to "neg dividend". The sub
-    // don't care the sign/unsigned because of two's complement representation.
-    // And the behavior is what we want:
-    //  -(2^n)        (2^n)-1
-    //  MININT  < k <= MAXINT    ->     mul k -1  =  -k
-    //  MININT == k              ->     mul k -1  =   k
-    //
-    // LLVM use sub to represent 'neg'
-    eq_result = irb_.CreateSub(zero, dividend);
-  } else {
-    // Everything modulo -1 will be 0.
-    eq_result = zero;
-  }
-  irb_.CreateBr(neg_one_cont);
-
-  // If divisor != -1, just do the division.
-  irb_.SetInsertPoint(ne_neg_one);
-  llvm::Value* ne_result;
-  if (is_div) {
-    ne_result = irb_.CreateSDiv(dividend, divisor);
-  } else {
-    ne_result = irb_.CreateSRem(dividend, divisor);
-  }
-  irb_.CreateBr(neg_one_cont);
-
-  irb_.SetInsertPoint(neg_one_cont);
-  llvm::PHINode* result = irb_.CreatePHI(op_type, 2);
-  result->addIncoming(eq_result, eq_neg_one);
-  result->addIncoming(ne_result, ne_neg_one);
-
-  return result;
-}
-
-void GBCExpanderPass::Expand_AllocaShadowFrame(llvm::Value* num_vregs_value) {
-  // Most of the codes refer to MethodCompiler::EmitPrologueAllocShadowFrame and
-  // MethodCompiler::EmitPushShadowFrame
-  uint16_t num_vregs =
-    llvm::cast<llvm::ConstantInt>(num_vregs_value)->getZExtValue();
-
-  llvm::StructType* shadow_frame_type =
-    irb_.getShadowFrameTy(num_vregs);
-
-  // Create allocas at the start of entry block.
-  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
-  llvm::BasicBlock* entry_block = &func_->front();
-  irb_.SetInsertPoint(&entry_block->front());
-
-  shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
-
-  // Alloca a pointer to old shadow frame
-  old_shadow_frame_ =
-    irb_.CreateAlloca(shadow_frame_type->getElementType(0)->getPointerTo());
-
-  irb_.restoreIP(irb_ip_original);
-
-  // Push the shadow frame
-  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-  llvm::Value* shadow_frame_upcast =
-    irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
-
-  llvm::Value* result = rtb_.EmitPushShadowFrame(shadow_frame_upcast,
-                                                 method_object_addr,
-                                                 num_vregs);
-
-  irb_.CreateStore(result, old_shadow_frame_, kTBAARegister);
-
-  return;
-}
-
-void GBCExpanderPass::Expand_SetVReg(llvm::Value* entry_idx,
-                                     llvm::Value* value) {
-  unsigned vreg_idx = LV2UInt(entry_idx);
-  DCHECK_LT(vreg_idx, dex_compilation_unit_->GetCodeItem()->registers_size_);
-
-  llvm::Value* vreg_addr = shadow_frame_vreg_addresses_[vreg_idx];
-  if (UNLIKELY(vreg_addr == NULL)) {
-    DCHECK(shadow_frame_ != NULL);
-
-    llvm::Value* gep_index[] = {
-      irb_.getInt32(0),  // No pointer displacement
-      irb_.getInt32(1),  // VRegs
-      entry_idx  // Pointer field
-    };
-
-    // A shadow frame address must dominate every use in the function so we
-    // place it in the entry block right after the allocas.
-    llvm::BasicBlock::iterator first_non_alloca = func_->getEntryBlock().begin();
-    while (llvm::isa<llvm::AllocaInst>(first_non_alloca)) {
-      ++first_non_alloca;
-    }
-
-    llvm::IRBuilderBase::InsertPoint ip = irb_.saveIP();
-    irb_.SetInsertPoint(static_cast<llvm::Instruction*>(first_non_alloca));
-    vreg_addr = irb_.CreateGEP(shadow_frame_, gep_index);
-    shadow_frame_vreg_addresses_[vreg_idx] = vreg_addr;
-    irb_.restoreIP(ip);
-  }
-
-  irb_.CreateStore(value,
-                   irb_.CreateBitCast(vreg_addr, value->getType()->getPointerTo()),
-                   kTBAAShadowFrame);
-  return;
-}
-
-void GBCExpanderPass::Expand_PopShadowFrame() {
-  if (old_shadow_frame_ == NULL) {
-    return;
-  }
-  rtb_.EmitPopShadowFrame(irb_.CreateLoad(old_shadow_frame_, kTBAARegister));
-  return;
-}
-
-void GBCExpanderPass::Expand_UpdateDexPC(llvm::Value* dex_pc_value) {
-  irb_.StoreToObjectOffset(shadow_frame_,
-                           art::ShadowFrame::DexPCOffset(),
-                           dex_pc_value,
-                           kTBAAShadowFrame);
-  return;
-}
-
-void GBCExpanderPass::InsertStackOverflowCheck(llvm::Function& func) {
-  // All alloca instructions are generated in the first basic block of the
-  // function, and there are no alloca instructions after the first non-alloca
-  // instruction.
-
-  llvm::BasicBlock* first_basic_block = &func.front();
-
-  // Look for first non-alloca instruction
-  llvm::BasicBlock::iterator first_non_alloca = first_basic_block->begin();
-  while (llvm::isa<llvm::AllocaInst>(first_non_alloca)) {
-    ++first_non_alloca;
-  }
-
-  irb_.SetInsertPoint(first_non_alloca);
-
-  // Insert stack overflow check codes before first_non_alloca (i.e., after all
-  // alloca instructions)
-  EmitStackOverflowCheck(&*first_non_alloca);
-
-  irb_.Runtime().EmitTestSuspend();
-
-  llvm::BasicBlock* next_basic_block = irb_.GetInsertBlock();
-  if (next_basic_block != first_basic_block) {
-    // Splice the rest of the instruction to the continuing basic block
-    next_basic_block->getInstList().splice(
-        irb_.GetInsertPoint(), first_basic_block->getInstList(),
-        first_non_alloca, first_basic_block->end());
-
-    // Rewrite the basic block
-    RewriteBasicBlock(next_basic_block);
-
-    // Update the phi-instructions in the successor basic block
-    UpdatePhiInstruction(first_basic_block, irb_.GetInsertBlock());
-  }
-
-  // We have changed the basic block
-  changed_ = true;
-}
-
-// ==== High-level intrinsic expander ==========================================
-
-llvm::Value* GBCExpanderPass::Expand_FPCompare(llvm::Value* src1_value,
-                                               llvm::Value* src2_value,
-                                               bool gt_bias) {
-  llvm::Value* cmp_eq = irb_.CreateFCmpOEQ(src1_value, src2_value);
-  llvm::Value* cmp_lt;
-
-  if (gt_bias) {
-    cmp_lt = irb_.CreateFCmpOLT(src1_value, src2_value);
-  } else {
-    cmp_lt = irb_.CreateFCmpULT(src1_value, src2_value);
-  }
-
-  return EmitCompareResultSelection(cmp_eq, cmp_lt);
-}
-
-llvm::Value* GBCExpanderPass::Expand_LongCompare(llvm::Value* src1_value, llvm::Value* src2_value) {
-  llvm::Value* cmp_eq = irb_.CreateICmpEQ(src1_value, src2_value);
-  llvm::Value* cmp_lt = irb_.CreateICmpSLT(src1_value, src2_value);
-
-  return EmitCompareResultSelection(cmp_eq, cmp_lt);
-}
-
-llvm::Value* GBCExpanderPass::EmitCompareResultSelection(llvm::Value* cmp_eq,
-                                                         llvm::Value* cmp_lt) {
-  llvm::Constant* zero = irb_.getJInt(0);
-  llvm::Constant* pos1 = irb_.getJInt(1);
-  llvm::Constant* neg1 = irb_.getJInt(-1);
-
-  llvm::Value* result_lt = irb_.CreateSelect(cmp_lt, neg1, pos1);
-  llvm::Value* result_eq = irb_.CreateSelect(cmp_eq, zero, result_lt);
-
-  return result_eq;
-}
-
-llvm::Value* GBCExpanderPass::Expand_IntegerShift(llvm::Value* src1_value,
-                                                  llvm::Value* src2_value,
-                                                  IntegerShiftKind kind,
-                                                  JType op_jty) {
-  DCHECK(op_jty == kInt || op_jty == kLong);
-
-  // Mask and zero-extend RHS properly
-  if (op_jty == kInt) {
-    src2_value = irb_.CreateAnd(src2_value, 0x1f);
-  } else {
-    llvm::Value* masked_src2_value = irb_.CreateAnd(src2_value, 0x3f);
-    src2_value = irb_.CreateZExt(masked_src2_value, irb_.getJLongTy());
-  }
-
-  // Create integer shift llvm instruction
-  switch (kind) {
-  case kIntegerSHL:
-    return irb_.CreateShl(src1_value, src2_value);
-
-  case kIntegerSHR:
-    return irb_.CreateAShr(src1_value, src2_value);
-
-  case kIntegerUSHR:
-    return irb_.CreateLShr(src1_value, src2_value);
-
-  default:
-    LOG(FATAL) << "Unknown integer shift kind: " << kind;
-    return NULL;
-  }
-}
-
-llvm::Value* GBCExpanderPass::SignOrZeroExtendCat1Types(llvm::Value* value, JType jty) {
-  switch (jty) {
-    case kBoolean:
-    case kChar:
-      return irb_.CreateZExt(value, irb_.getJType(kInt));
-    case kByte:
-    case kShort:
-      return irb_.CreateSExt(value, irb_.getJType(kInt));
-    case kVoid:
-    case kInt:
-    case kLong:
-    case kFloat:
-    case kDouble:
-    case kObject:
-      return value;  // Nothing to do.
-    default:
-      LOG(FATAL) << "Unknown java type: " << jty;
-      return NULL;
-  }
-}
-
-llvm::Value* GBCExpanderPass::TruncateCat1Types(llvm::Value* value, JType jty) {
-  switch (jty) {
-    case kBoolean:
-    case kChar:
-    case kByte:
-    case kShort:
-      return irb_.CreateTrunc(value, irb_.getJType(jty));
-    case kVoid:
-    case kInt:
-    case kLong:
-    case kFloat:
-    case kDouble:
-    case kObject:
-      return value;  // Nothing to do.
-    default:
-      LOG(FATAL) << "Unknown java type: " << jty;
-      return NULL;
-  }
-}
-
-llvm::Value* GBCExpanderPass::Expand_HLArrayGet(llvm::CallInst& call_inst,
-                                                JType elem_jty) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  llvm::Value* array_addr = call_inst.getArgOperand(1);
-  llvm::Value* index_value = call_inst.getArgOperand(2);
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags);
-  EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value,
-                                           opt_flags);
-
-  llvm::Value* array_elem_addr = EmitArrayGEP(array_addr, index_value, elem_jty);
-
-  llvm::Value* array_elem_value = irb_.CreateLoad(array_elem_addr, kTBAAHeapArray, elem_jty);
-
-  return SignOrZeroExtendCat1Types(array_elem_value, elem_jty);
-}
-
-
-void GBCExpanderPass::Expand_HLArrayPut(llvm::CallInst& call_inst,
-                                        JType elem_jty) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  llvm::Value* new_value = call_inst.getArgOperand(1);
-  llvm::Value* array_addr = call_inst.getArgOperand(2);
-  llvm::Value* index_value = call_inst.getArgOperand(3);
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags);
-  EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value,
-                                           opt_flags);
-
-  new_value = TruncateCat1Types(new_value, elem_jty);
-
-  llvm::Value* array_elem_addr = EmitArrayGEP(array_addr, index_value, elem_jty);
-
-  if (elem_jty == kObject) {  // If put an object, check the type, and mark GC card table.
-    llvm::Function* runtime_func = irb_.GetRuntime(CheckPutArrayElement);
-
-    irb_.CreateCall2(runtime_func, new_value, array_addr);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-    EmitMarkGCCard(new_value, array_addr);
-  }
-
-  irb_.CreateStore(new_value, array_elem_addr, kTBAAHeapArray, elem_jty);
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst,
-                                            JType field_jty) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  llvm::Value* object_addr = call_inst.getArgOperand(1);
-  uint32_t field_idx = LV2UInt(call_inst.getArgOperand(2));
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
-
-  llvm::Value* field_value;
-
-  art::MemberOffset field_offset(0u);
-  bool is_volatile;
-  bool is_fast_path = driver_->ComputeInstanceFieldInfo(
-    field_idx, dex_compilation_unit_, false, &field_offset, &is_volatile);
-
-  if (!is_fast_path) {
-    llvm::Function* runtime_func;
-
-    if (field_jty == kObject) {
-      runtime_func = irb_.GetRuntime(GetObjectInstance);
-    } else if (field_jty == kLong || field_jty == kDouble) {
-      runtime_func = irb_.GetRuntime(Get64Instance);
-    } else {
-      runtime_func = irb_.GetRuntime(Get32Instance);
-    }
-
-    llvm::ConstantInt* field_idx_value = irb_.getInt32(field_idx);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    EmitUpdateDexPC(dex_pc);
-
-    field_value = irb_.CreateCall3(runtime_func, field_idx_value,
-                                   method_object_addr, object_addr);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-    if (field_jty == kFloat || field_jty == kDouble) {
-      field_value = irb_.CreateBitCast(field_value, irb_.getJType(field_jty));
-    }
-  } else {
-    DCHECK_GE(field_offset.Int32Value(), 0);
-
-    llvm::PointerType* field_type =
-      irb_.getJType(field_jty)->getPointerTo();
-
-    llvm::ConstantInt* field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
-
-    llvm::Value* field_addr =
-      irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
-
-    field_value = irb_.CreateLoad(field_addr, kTBAAHeapInstance, field_jty);
-    field_value = SignOrZeroExtendCat1Types(field_value, field_jty);
-
-    if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kLoadAny);
-    }
-  }
-
-  return field_value;
-}
-
-void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst,
-                                    JType field_jty) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  llvm::Value* new_value = call_inst.getArgOperand(1);
-  llvm::Value* object_addr = call_inst.getArgOperand(2);
-  uint32_t field_idx = LV2UInt(call_inst.getArgOperand(3));
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
-
-  art::MemberOffset field_offset(0u);
-  bool is_volatile;
-  bool is_fast_path = driver_->ComputeInstanceFieldInfo(
-    field_idx, dex_compilation_unit_, true, &field_offset, &is_volatile);
-
-  if (!is_fast_path) {
-    llvm::Function* runtime_func;
-
-    if (field_jty == kFloat) {
-      new_value = irb_.CreateBitCast(new_value, irb_.getJType(kInt));
-    } else if (field_jty == kDouble) {
-      new_value = irb_.CreateBitCast(new_value, irb_.getJType(kLong));
-    }
-
-    if (field_jty == kObject) {
-      runtime_func = irb_.GetRuntime(SetObjectInstance);
-    } else if (field_jty == kLong || field_jty == kDouble) {
-      runtime_func = irb_.GetRuntime(Set64Instance);
-    } else {
-      runtime_func = irb_.GetRuntime(Set32Instance);
-    }
-
-    llvm::Value* field_idx_value = irb_.getInt32(field_idx);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    EmitUpdateDexPC(dex_pc);
-
-    irb_.CreateCall4(runtime_func, field_idx_value,
-                     method_object_addr, object_addr, new_value);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-  } else {
-    DCHECK_GE(field_offset.Int32Value(), 0);
-
-    if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kAnyStore);
-    }
-
-    llvm::PointerType* field_type =
-      irb_.getJType(field_jty)->getPointerTo();
-
-    llvm::Value* field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
-
-    llvm::Value* field_addr =
-      irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
-
-    new_value = TruncateCat1Types(new_value, field_jty);
-    irb_.CreateStore(new_value, field_addr, kTBAAHeapInstance, field_jty);
-
-    if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kAnyAny);
-    }
-
-    if (field_jty == kObject) {  // If put an object, mark the GC card table.
-      EmitMarkGCCard(new_value, object_addr);
-    }
-  }
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::EmitLoadConstantClass(uint32_t dex_pc,
-                                                    uint32_t type_idx) {
-  if (!driver_->CanAccessTypeWithoutChecks(dex_compilation_unit_->GetDexMethodIndex(),
-                                           *dex_compilation_unit_->GetDexFile(), type_idx)) {
-    llvm::Value* type_idx_value = irb_.getInt32(type_idx);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
-    llvm::Function* runtime_func = irb_.GetRuntime(InitializeTypeAndVerifyAccess);
-
-    EmitUpdateDexPC(dex_pc);
-
-    llvm::Value* type_object_addr =
-      irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-    return type_object_addr;
-
-  } else {
-    // Try to load the class (type) object from the test cache.
-    llvm::Value* type_field_addr =
-      EmitLoadDexCacheResolvedTypeFieldAddr(type_idx);
-
-    llvm::Value* type_object_addr = irb_.CreateLoad(type_field_addr, kTBAARuntimeInfo);
-
-    if (driver_->CanAssumeTypeIsPresentInDexCache(*dex_compilation_unit_->GetDexFile(), type_idx)) {
-      return type_object_addr;
-    }
-
-    llvm::BasicBlock* block_original = irb_.GetInsertBlock();
-
-    // Test whether class (type) object is in the dex cache or not
-    llvm::Value* equal_null =
-      irb_.CreateICmpEQ(type_object_addr, irb_.getJNull());
-
-    llvm::BasicBlock* block_cont =
-      CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-    llvm::BasicBlock* block_load_class =
-      CreateBasicBlockWithDexPC(dex_pc, "load_class");
-
-    irb_.CreateCondBr(equal_null, block_load_class, block_cont, kUnlikely);
-
-    // Failback routine to load the class object
-    irb_.SetInsertPoint(block_load_class);
-
-    llvm::Function* runtime_func = irb_.GetRuntime(InitializeType);
-
-    llvm::Constant* type_idx_value = irb_.getInt32(type_idx);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
-    EmitUpdateDexPC(dex_pc);
-
-    llvm::Value* loaded_type_object_addr =
-      irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-    llvm::BasicBlock* block_after_load_class = irb_.GetInsertBlock();
-
-    irb_.CreateBr(block_cont);
-
-    // Now the class object must be loaded
-    irb_.SetInsertPoint(block_cont);
-
-    llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2);
-
-    phi->addIncoming(type_object_addr, block_original);
-    phi->addIncoming(loaded_type_object_addr, block_after_load_class);
-
-    return phi;
-  }
-}
-
-llvm::Value* GBCExpanderPass::EmitLoadStaticStorage(uint32_t dex_pc,
-                                                    uint32_t type_idx) {
-  llvm::BasicBlock* block_load_static =
-    CreateBasicBlockWithDexPC(dex_pc, "load_static");
-
-  llvm::BasicBlock* block_check_init = CreateBasicBlockWithDexPC(dex_pc, "init");
-  llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-  // Load static storage from dex cache
-  llvm::Value* storage_field_addr = EmitLoadDexCacheResolvedTypeFieldAddr(type_idx);
-
-  llvm::Value* storage_object_addr = irb_.CreateLoad(storage_field_addr, kTBAARuntimeInfo);
-
-  // Test: Is the class resolved?
-  llvm::Value* equal_null = irb_.CreateICmpEQ(storage_object_addr, irb_.getJNull());
-
-  irb_.CreateCondBr(equal_null, block_load_static, block_check_init, kUnlikely);
-
-  // storage_object_addr != null, so check if its initialized.
-  irb_.SetInsertPoint(block_check_init);
-
-  llvm::Value* class_status =
-      irb_.LoadFromObjectOffset(storage_object_addr,
-                                art::mirror::Class::StatusOffset().Int32Value(),
-                                irb_.getJIntTy(), kTBAAHeapInstance);
-
-  llvm::Value* is_not_initialized =
-      irb_.CreateICmpULT(class_status, irb_.getInt32(art::mirror::Class::kStatusInitialized));
-
-  irb_.CreateCondBr(is_not_initialized, block_load_static, block_cont, kUnlikely);
-
-  // Failback routine to load the class object
-  irb_.SetInsertPoint(block_load_static);
-
-  llvm::Function* runtime_func = irb_.GetRuntime(InitializeStaticStorage);
-
-  llvm::Constant* type_idx_value = irb_.getInt32(type_idx);
-
-  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
-  EmitUpdateDexPC(dex_pc);
-
-  llvm::Value* loaded_storage_object_addr =
-    irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
-
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  llvm::BasicBlock* block_after_load_static = irb_.GetInsertBlock();
-
-  irb_.CreateBr(block_cont);
-
-  // Now the class object must be loaded
-  irb_.SetInsertPoint(block_cont);
-
-  llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2);
-
-  phi->addIncoming(storage_object_addr, block_check_init);
-  phi->addIncoming(loaded_storage_object_addr, block_after_load_static);
-
-  // Ensure load of status and load of value don't re-order.
-  irb_.CreateMemoryBarrier(art::kLoadAny);
-
-  return phi;
-}
-
-llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst,
-                                            JType field_jty) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t field_idx = LV2UInt(call_inst.getArgOperand(0));
-
-  art::MemberOffset field_offset(0u);
-  uint32_t ssb_index;
-  bool is_referrers_class;
-  bool is_volatile;
-  bool is_initialized;
-
-  bool is_fast_path = driver_->ComputeStaticFieldInfo(
-    field_idx, dex_compilation_unit_, false,
-    &field_offset, &ssb_index, &is_referrers_class, &is_volatile, &is_initialized);
-
-  llvm::Value* static_field_value;
-
-  if (!is_fast_path) {
-    llvm::Function* runtime_func;
-
-    if (field_jty == kObject) {
-      runtime_func = irb_.GetRuntime(GetObjectStatic);
-    } else if (field_jty == kLong || field_jty == kDouble) {
-      runtime_func = irb_.GetRuntime(Get64Static);
-    } else {
-      runtime_func = irb_.GetRuntime(Get32Static);
-    }
-
-    llvm::Constant* field_idx_value = irb_.getInt32(field_idx);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    EmitUpdateDexPC(dex_pc);
-
-    static_field_value =
-      irb_.CreateCall2(runtime_func, field_idx_value, method_object_addr);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-    if (field_jty == kFloat || field_jty == kDouble) {
-      static_field_value = irb_.CreateBitCast(static_field_value, irb_.getJType(field_jty));
-    }
-  } else {
-    DCHECK_GE(field_offset.Int32Value(), 0);
-
-    llvm::Value* static_storage_addr = NULL;
-
-    if (is_referrers_class) {
-      // Fast path, static storage base is this method's class
-      llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-      static_storage_addr =
-        irb_.LoadFromObjectOffset(method_object_addr,
-                                  art::mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                                  irb_.getJObjectTy(),
-                                  kTBAAConstJObject);
-    } else {
-      // Medium path, static storage base in a different class which
-      // requires checks that the other class is initialized
-      DCHECK_NE(ssb_index, art::DexFile::kDexNoIndex);
-      static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
-    }
-
-    llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
-
-    llvm::Value* static_field_addr =
-      irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
-                         irb_.getJType(field_jty)->getPointerTo());
-
-    static_field_value = irb_.CreateLoad(static_field_addr, kTBAAHeapStatic, field_jty);
-    static_field_value = SignOrZeroExtendCat1Types(static_field_value, field_jty);
-
-    if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kLoadAny);
-    }
-  }
-
-  return static_field_value;
-}
-
-void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst,
-                                    JType field_jty) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t field_idx = LV2UInt(call_inst.getArgOperand(0));
-  llvm::Value* new_value = call_inst.getArgOperand(1);
-
-  if (field_jty == kFloat || field_jty == kDouble) {
-    new_value = irb_.CreateBitCast(new_value, irb_.getJType(field_jty));
-  }
-
-  art::MemberOffset field_offset(0u);
-  uint32_t ssb_index;
-  bool is_referrers_class;
-  bool is_volatile;
-  bool is_initialized;
-
-  bool is_fast_path = driver_->ComputeStaticFieldInfo(
-    field_idx, dex_compilation_unit_, true,
-    &field_offset, &ssb_index, &is_referrers_class, &is_volatile, &is_initialized);
-
-  if (!is_fast_path) {
-    llvm::Function* runtime_func;
-
-    if (field_jty == kObject) {
-      runtime_func = irb_.GetRuntime(SetObjectStatic);
-    } else if (field_jty == kLong || field_jty == kDouble) {
-      runtime_func = irb_.GetRuntime(Set64Static);
-    } else {
-      runtime_func = irb_.GetRuntime(Set32Static);
-    }
-
-    if (field_jty == kFloat) {
-      new_value = irb_.CreateBitCast(new_value, irb_.getJType(kInt));
-    } else if (field_jty == kDouble) {
-      new_value = irb_.CreateBitCast(new_value, irb_.getJType(kLong));
-    }
-
-    llvm::Constant* field_idx_value = irb_.getInt32(field_idx);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    EmitUpdateDexPC(dex_pc);
-
-    irb_.CreateCall3(runtime_func, field_idx_value,
-                     method_object_addr, new_value);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-  } else {
-    DCHECK_GE(field_offset.Int32Value(), 0);
-
-    llvm::Value* static_storage_addr = NULL;
-
-    if (is_referrers_class) {
-      // Fast path, static storage base is this method's class
-      llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-      static_storage_addr =
-        irb_.LoadFromObjectOffset(method_object_addr,
-                                  art::mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                                  irb_.getJObjectTy(),
-                                  kTBAAConstJObject);
-    } else {
-      // Medium path, static storage base in a different class which
-      // requires checks that the other class is initialized
-      DCHECK_NE(ssb_index, art::DexFile::kDexNoIndex);
-      static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
-    }
-
-    if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kAnyStore);
-    }
-
-    llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
-
-    llvm::Value* static_field_addr =
-      irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
-                         irb_.getJType(field_jty)->getPointerTo());
-
-    new_value = TruncateCat1Types(new_value, field_jty);
-    irb_.CreateStore(new_value, static_field_addr, kTBAAHeapStatic, field_jty);
-
-    if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kAnyAny);
-    }
-
-    if (field_jty == kObject) {  // If put an object, mark the GC card table.
-      EmitMarkGCCard(new_value, static_storage_addr);
-    }
-  }
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::Expand_ConstString(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t string_idx = LV2UInt(call_inst.getArgOperand(0));
-
-  llvm::Value* string_field_addr = EmitLoadDexCacheStringFieldAddr(string_idx);
-
-  llvm::Value* string_addr = irb_.CreateLoad(string_field_addr, kTBAARuntimeInfo);
-
-  if (!driver_->CanAssumeStringIsPresentInDexCache(*dex_compilation_unit_->GetDexFile(),
-                                                   string_idx)) {
-    llvm::BasicBlock* block_str_exist =
-      CreateBasicBlockWithDexPC(dex_pc, "str_exist");
-
-    llvm::BasicBlock* block_str_resolve =
-      CreateBasicBlockWithDexPC(dex_pc, "str_resolve");
-
-    llvm::BasicBlock* block_cont =
-      CreateBasicBlockWithDexPC(dex_pc, "str_cont");
-
-    // Test: Is the string resolved and in the dex cache?
-    llvm::Value* equal_null = irb_.CreateICmpEQ(string_addr, irb_.getJNull());
-
-    irb_.CreateCondBr(equal_null, block_str_resolve, block_str_exist, kUnlikely);
-
-    // String is resolved, go to next basic block.
-    irb_.SetInsertPoint(block_str_exist);
-    irb_.CreateBr(block_cont);
-
-    // String is not resolved yet, resolve it now.
-    irb_.SetInsertPoint(block_str_resolve);
-
-    llvm::Function* runtime_func = irb_.GetRuntime(ResolveString);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    llvm::Value* string_idx_value = irb_.getInt32(string_idx);
-
-    EmitUpdateDexPC(dex_pc);
-
-    llvm::Value* result = irb_.CreateCall2(runtime_func, method_object_addr,
-                                           string_idx_value);
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-
-    irb_.CreateBr(block_cont);
-
-
-    llvm::BasicBlock* block_pre_cont = irb_.GetInsertBlock();
-
-    irb_.SetInsertPoint(block_cont);
-
-    llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2);
-
-    phi->addIncoming(string_addr, block_str_exist);
-    phi->addIncoming(result, block_pre_cont);
-
-    string_addr = phi;
-  }
-
-  return string_addr;
-}
-
-llvm::Value* GBCExpanderPass::Expand_ConstClass(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
-
-  llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx);
-
-  return type_object_addr;
-}
-
-void GBCExpanderPass::Expand_MonitorEnter(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  llvm::Value* object_addr = call_inst.getArgOperand(1);
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
-
-  EmitUpdateDexPC(dex_pc);
-
-  irb_.Runtime().EmitLockObject(object_addr);
-
-  return;
-}
-
-void GBCExpanderPass::Expand_MonitorExit(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  llvm::Value* object_addr = call_inst.getArgOperand(1);
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
-
-  EmitUpdateDexPC(dex_pc);
-
-  irb_.Runtime().EmitUnlockObject(object_addr);
-
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  return;
-}
-
-void GBCExpanderPass::Expand_HLCheckCast(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
-  llvm::Value* object_addr = call_inst.getArgOperand(1);
-
-  llvm::BasicBlock* block_test_class =
-    CreateBasicBlockWithDexPC(dex_pc, "test_class");
-
-  llvm::BasicBlock* block_test_sub_class =
-    CreateBasicBlockWithDexPC(dex_pc, "test_sub_class");
-
-  llvm::BasicBlock* block_cont =
-    CreateBasicBlockWithDexPC(dex_pc, "checkcast_cont");
-
-  // Test: Is the reference equal to null?  Act as no-op when it is null.
-  llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.getJNull());
-
-  irb_.CreateCondBr(equal_null, block_cont, block_test_class, kUnlikely);
-
-  // Test: Is the object instantiated from the given class?
-  irb_.SetInsertPoint(block_test_class);
-  llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx);
-  DCHECK_EQ(art::mirror::Object::ClassOffset().Int32Value(), 0);
-
-  llvm::PointerType* jobject_ptr_ty = irb_.getJObjectTy();
-
-  llvm::Value* object_type_field_addr =
-    irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo());
-
-  llvm::Value* object_type_object_addr =
-    irb_.CreateLoad(object_type_field_addr, kTBAAConstJObject);
-
-  llvm::Value* equal_class =
-    irb_.CreateICmpEQ(type_object_addr, object_type_object_addr);
-
-  irb_.CreateCondBr(equal_class, block_cont, block_test_sub_class, kLikely);
-
-  // Test: Is the object instantiated from the subclass of the given class?
-  irb_.SetInsertPoint(block_test_sub_class);
-
-  EmitUpdateDexPC(dex_pc);
-
-  irb_.CreateCall2(irb_.GetRuntime(CheckCast),
-                   type_object_addr, object_type_object_addr);
-
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  irb_.CreateBr(block_cont);
-
-  irb_.SetInsertPoint(block_cont);
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::Expand_InstanceOf(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
-  llvm::Value* object_addr = call_inst.getArgOperand(1);
-
-  llvm::BasicBlock* block_nullp =
-      CreateBasicBlockWithDexPC(dex_pc, "nullp");
-
-  llvm::BasicBlock* block_test_class =
-      CreateBasicBlockWithDexPC(dex_pc, "test_class");
-
-  llvm::BasicBlock* block_class_equals =
-      CreateBasicBlockWithDexPC(dex_pc, "class_eq");
-
-  llvm::BasicBlock* block_test_sub_class =
-      CreateBasicBlockWithDexPC(dex_pc, "test_sub_class");
-
-  llvm::BasicBlock* block_cont =
-      CreateBasicBlockWithDexPC(dex_pc, "instance_of_cont");
-
-  // Overview of the following code :
-  // We check for null, if so, then false, otherwise check for class == . If so
-  // then true, otherwise do callout slowpath.
-  //
-  // Test: Is the reference equal to null?  Set 0 when it is null.
-  llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.getJNull());
-
-  irb_.CreateCondBr(equal_null, block_nullp, block_test_class, kUnlikely);
-
-  irb_.SetInsertPoint(block_nullp);
-  irb_.CreateBr(block_cont);
-
-  // Test: Is the object instantiated from the given class?
-  irb_.SetInsertPoint(block_test_class);
-  llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx);
-  DCHECK_EQ(art::mirror::Object::ClassOffset().Int32Value(), 0);
-
-  llvm::PointerType* jobject_ptr_ty = irb_.getJObjectTy();
-
-  llvm::Value* object_type_field_addr =
-    irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo());
-
-  llvm::Value* object_type_object_addr =
-    irb_.CreateLoad(object_type_field_addr, kTBAAConstJObject);
-
-  llvm::Value* equal_class =
-    irb_.CreateICmpEQ(type_object_addr, object_type_object_addr);
-
-  irb_.CreateCondBr(equal_class, block_class_equals, block_test_sub_class, kLikely);
-
-  irb_.SetInsertPoint(block_class_equals);
-  irb_.CreateBr(block_cont);
-
-  // Test: Is the object instantiated from the subclass of the given class?
-  irb_.SetInsertPoint(block_test_sub_class);
-  llvm::Value* result =
-    irb_.CreateCall2(irb_.GetRuntime(IsAssignable),
-                     type_object_addr, object_type_object_addr);
-  irb_.CreateBr(block_cont);
-
-  irb_.SetInsertPoint(block_cont);
-
-  llvm::PHINode* phi = irb_.CreatePHI(irb_.getJIntTy(), 3);
-
-  phi->addIncoming(irb_.getJInt(0), block_nullp);
-  phi->addIncoming(irb_.getJInt(1), block_class_equals);
-  phi->addIncoming(result, block_test_sub_class);
-
-  return phi;
-}
-
-llvm::Value* GBCExpanderPass::Expand_NewInstance(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
-
-  llvm::Function* runtime_func;
-  if (driver_->CanAccessInstantiableTypeWithoutChecks(dex_compilation_unit_->GetDexMethodIndex(),
-                                                      *dex_compilation_unit_->GetDexFile(),
-                                                      type_idx)) {
-    runtime_func = irb_.GetRuntime(AllocObject);
-  } else {
-    runtime_func = irb_.GetRuntime(AllocObjectWithAccessCheck);
-  }
-
-  llvm::Constant* type_index_value = irb_.getInt32(type_idx);
-
-  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
-  EmitUpdateDexPC(dex_pc);
-
-  llvm::Value* object_addr =
-    irb_.CreateCall3(runtime_func, type_index_value, method_object_addr, thread_object_addr);
-
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  return object_addr;
-}
-
-llvm::Value* GBCExpanderPass::Expand_HLInvoke(llvm::CallInst& call_inst) {
-  art::InvokeType invoke_type = static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
-  bool is_static = (invoke_type == art::kStatic);
-
-  if (!is_static) {
-    // Test: Is *this* parameter equal to null?
-    uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-    llvm::Value* this_addr = call_inst.getArgOperand(3);
-    int opt_flags = LV2UInt(call_inst.getArgOperand(2));
-
-    EmitGuard_NullPointerException(dex_pc, this_addr, opt_flags);
-  }
-
-  llvm::Value* result = NULL;
-  if (EmitIntrinsic(call_inst, &result)) {
-    return result;
-  }
-
-  return EmitInvoke(call_inst);
-}
-
-llvm::Value* GBCExpanderPass::Expand_OptArrayLength(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  // Get the array object address
-  llvm::Value* array_addr = call_inst.getArgOperand(1);
-  int opt_flags = LV2UInt(call_inst.getArgOperand(0));
-
-  EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags);
-
-  // Get the array length and store it to the register
-  return EmitLoadArrayLength(array_addr);
-}
-
-llvm::Value* GBCExpanderPass::Expand_NewArray(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0));
-  llvm::Value* length = call_inst.getArgOperand(1);
-
-  return EmitAllocNewArray(dex_pc, length, type_idx, false);
-}
-
-llvm::Value* GBCExpanderPass::Expand_HLFilledNewArray(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  uint32_t type_idx = LV2UInt(call_inst.getArgOperand(1));
-  uint32_t length = call_inst.getNumArgOperands() - 3;
-
-  llvm::Value* object_addr =
-    EmitAllocNewArray(dex_pc, irb_.getInt32(length), type_idx, true);
-
-  if (length > 0) {
-    // Check for the element type
-    uint32_t type_desc_len = 0;
-    const char* type_desc =
-        dex_compilation_unit_->GetDexFile()->StringByTypeIdx(type_idx, &type_desc_len);
-
-    DCHECK_GE(type_desc_len, 2u);  // should be guaranteed by verifier
-    DCHECK_EQ(type_desc[0], '[');  // should be guaranteed by verifier
-    bool is_elem_int_ty = (type_desc[1] == 'I');
-
-    uint32_t alignment;
-    llvm::Constant* elem_size;
-    llvm::PointerType* field_type;
-
-    // NOTE: Currently filled-new-array only supports 'L', '[', and 'I'
-    // as the element, thus we are only checking 2 cases: primitive int and
-    // non-primitive type.
-    if (is_elem_int_ty) {
-      alignment = sizeof(int32_t);
-      elem_size = irb_.getPtrEquivInt(sizeof(int32_t));
-      field_type = irb_.getJIntTy()->getPointerTo();
-    } else {
-      alignment = irb_.getSizeOfPtrEquivInt();
-      elem_size = irb_.getSizeOfPtrEquivIntValue();
-      field_type = irb_.getJObjectTy()->getPointerTo();
-    }
-
-    llvm::Value* data_field_offset =
-      irb_.getPtrEquivInt(art::mirror::Array::DataOffset(alignment).Int32Value());
-
-    llvm::Value* data_field_addr =
-      irb_.CreatePtrDisp(object_addr, data_field_offset, field_type);
-
-    // TODO: Tune this code.  Currently we are generating one instruction for
-    // one element which may be very space consuming.  Maybe changing to use
-    // memcpy may help; however, since we can't guarantee that the alloca of
-    // dalvik register are continuous, we can't perform such optimization yet.
-    for (uint32_t i = 0; i < length; ++i) {
-      llvm::Value* reg_value = call_inst.getArgOperand(i+3);
-
-      irb_.CreateStore(reg_value, data_field_addr, kTBAAHeapArray);
-
-      data_field_addr =
-        irb_.CreatePtrDisp(data_field_addr, elem_size, field_type);
-    }
-  }
-
-  return object_addr;
-}
-
-void GBCExpanderPass::Expand_HLFillArrayData(llvm::CallInst& call_inst) {
-  uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-  int32_t payload_offset = static_cast<int32_t>(dex_pc) +
-                           LV2SInt(call_inst.getArgOperand(0));
-  llvm::Value* array_addr = call_inst.getArgOperand(1);
-
-  const art::Instruction::ArrayDataPayload* payload =
-    reinterpret_cast<const art::Instruction::ArrayDataPayload*>(
-        dex_compilation_unit_->GetCodeItem()->insns_ + payload_offset);
-
-  if (payload->element_count == 0) {
-    // When the number of the elements in the payload is zero, we don't have
-    // to copy any numbers.  However, we should check whether the array object
-    // address is equal to null or not.
-    EmitGuard_NullPointerException(dex_pc, array_addr, 0);
-  } else {
-    // To save the code size, we are going to call the runtime function to
-    // copy the content from DexFile.
-
-    // NOTE: We will check for the NullPointerException in the runtime.
-
-    llvm::Function* runtime_func = irb_.GetRuntime(FillArrayData);
-
-    llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-    EmitUpdateDexPC(dex_pc);
-
-    irb_.CreateCall4(runtime_func,
-                     method_object_addr, irb_.getInt32(dex_pc),
-                     array_addr, irb_.getInt32(payload_offset));
-
-    EmitGuard_ExceptionLandingPad(dex_pc);
-  }
-
-  return;
-}
-
-llvm::Value* GBCExpanderPass::EmitAllocNewArray(uint32_t dex_pc,
-                                                llvm::Value* array_length_value,
-                                                uint32_t type_idx,
-                                                bool is_filled_new_array) {
-  llvm::Function* runtime_func;
-
-  bool skip_access_check =
-    driver_->CanAccessTypeWithoutChecks(dex_compilation_unit_->GetDexMethodIndex(),
-                                        *dex_compilation_unit_->GetDexFile(), type_idx);
-
-
-  if (is_filled_new_array) {
-    runtime_func = skip_access_check ?
-      irb_.GetRuntime(CheckAndAllocArray) :
-      irb_.GetRuntime(CheckAndAllocArrayWithAccessCheck);
-  } else {
-    runtime_func = skip_access_check ?
-      irb_.GetRuntime(AllocArray) :
-      irb_.GetRuntime(AllocArrayWithAccessCheck);
-  }
-
-  llvm::Constant* type_index_value = irb_.getInt32(type_idx);
-
-  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
-  EmitUpdateDexPC(dex_pc);
-
-  llvm::Value* object_addr =
-    irb_.CreateCall4(runtime_func, type_index_value, method_object_addr,
-                     array_length_value, thread_object_addr);
-
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  return object_addr;
-}
-
-llvm::Value* GBCExpanderPass::
-EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
-                                         art::InvokeType invoke_type,
-                                         llvm::Value* this_addr,
-                                         uint32_t dex_pc,
-                                         bool is_fast_path) {
-  llvm::Function* runtime_func = NULL;
-
-  switch (invoke_type) {
-  case art::kStatic:
-    runtime_func = irb_.GetRuntime(FindStaticMethodWithAccessCheck);
-    break;
-
-  case art::kDirect:
-    runtime_func = irb_.GetRuntime(FindDirectMethodWithAccessCheck);
-    break;
-
-  case art::kVirtual:
-    runtime_func = irb_.GetRuntime(FindVirtualMethodWithAccessCheck);
-    break;
-
-  case art::kSuper:
-    runtime_func = irb_.GetRuntime(FindSuperMethodWithAccessCheck);
-    break;
-
-  case art::kInterface:
-    if (is_fast_path) {
-      runtime_func = irb_.GetRuntime(FindInterfaceMethod);
-    } else {
-      runtime_func = irb_.GetRuntime(FindInterfaceMethodWithAccessCheck);
-    }
-    break;
-  }
-
-  llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx);
-
-  if (this_addr == NULL) {
-    DCHECK_EQ(invoke_type, art::kStatic);
-    this_addr = irb_.getJNull();
-  }
-
-  llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
-
-  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
-  EmitUpdateDexPC(dex_pc);
-
-  llvm::Value* callee_method_object_addr =
-    irb_.CreateCall4(runtime_func,
-                     callee_method_idx_value,
-                     this_addr,
-                     caller_method_object_addr,
-                     thread_object_addr);
-
-  EmitGuard_ExceptionLandingPad(dex_pc);
-
-  return callee_method_object_addr;
-}
-
-void GBCExpanderPass::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) {
-  // Using runtime support, let the target can override by InlineAssembly.
-  irb_.Runtime().EmitMarkGCCard(value, target_addr);
-}
-
-void GBCExpanderPass::EmitUpdateDexPC(uint32_t dex_pc) {
-  if (shadow_frame_ == NULL) {
-    return;
-  }
-  irb_.StoreToObjectOffset(shadow_frame_,
-                           art::ShadowFrame::DexPCOffset(),
-                           irb_.getInt32(dex_pc),
-                           kTBAAShadowFrame);
-}
-
-void GBCExpanderPass::EmitGuard_DivZeroException(uint32_t dex_pc,
-                                                 llvm::Value* denominator,
-                                                 JType op_jty) {
-  DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
-
-  llvm::Constant* zero = irb_.getJZero(op_jty);
-
-  llvm::Value* equal_zero = irb_.CreateICmpEQ(denominator, zero);
-
-  llvm::BasicBlock* block_exception = CreateBasicBlockWithDexPC(dex_pc, "div0");
-
-  llvm::BasicBlock* block_continue = CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-  irb_.CreateCondBr(equal_zero, block_exception, block_continue, kUnlikely);
-
-  irb_.SetInsertPoint(block_exception);
-  EmitUpdateDexPC(dex_pc);
-  irb_.CreateCall(irb_.GetRuntime(ThrowDivZeroException));
-  EmitBranchExceptionLandingPad(dex_pc);
-
-  irb_.SetInsertPoint(block_continue);
-}
-
-void GBCExpanderPass::EmitGuard_NullPointerException(uint32_t dex_pc,
-                                                     llvm::Value* object,
-                                                     int opt_flags) {
-  bool ignore_null_check = ((opt_flags & MIR_IGNORE_NULL_CHECK) != 0);
-  if (ignore_null_check) {
-    llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc);
-    if (lpad) {
-      // There is at least one catch: create a "fake" conditional branch to
-      // keep the exception edge to the catch block.
-      landing_pad_phi_mapping_[lpad].push_back(
-          std::make_pair(current_bb_->getUniquePredecessor(),
-                         irb_.GetInsertBlock()));
-
-      llvm::BasicBlock* block_continue =
-          CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-      irb_.CreateCondBr(irb_.getFalse(), lpad, block_continue, kUnlikely);
-
-      irb_.SetInsertPoint(block_continue);
-    }
-  } else {
-    llvm::Value* equal_null = irb_.CreateICmpEQ(object, irb_.getJNull());
-
-    llvm::BasicBlock* block_exception =
-        CreateBasicBlockWithDexPC(dex_pc, "nullp");
-
-    llvm::BasicBlock* block_continue =
-        CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-    irb_.CreateCondBr(equal_null, block_exception, block_continue, kUnlikely);
-
-    irb_.SetInsertPoint(block_exception);
-    EmitUpdateDexPC(dex_pc);
-    irb_.CreateCall(irb_.GetRuntime(ThrowNullPointerException),
-                    irb_.getInt32(dex_pc));
-    EmitBranchExceptionLandingPad(dex_pc);
-
-    irb_.SetInsertPoint(block_continue);
-  }
-}
-
-void
-GBCExpanderPass::EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
-                                                          llvm::Value* array,
-                                                          llvm::Value* index,
-                                                          int opt_flags) {
-  bool ignore_range_check = ((opt_flags & MIR_IGNORE_RANGE_CHECK) != 0);
-  if (ignore_range_check) {
-    llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc);
-    if (lpad) {
-      // There is at least one catch: create a "fake" conditional branch to
-      // keep the exception edge to the catch block.
-      landing_pad_phi_mapping_[lpad].push_back(
-          std::make_pair(current_bb_->getUniquePredecessor(),
-                         irb_.GetInsertBlock()));
-
-      llvm::BasicBlock* block_continue =
-          CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-      irb_.CreateCondBr(irb_.getFalse(), lpad, block_continue, kUnlikely);
-
-      irb_.SetInsertPoint(block_continue);
-    }
-  } else {
-    llvm::Value* array_len = EmitLoadArrayLength(array);
-
-    llvm::Value* cmp = irb_.CreateICmpUGE(index, array_len);
-
-    llvm::BasicBlock* block_exception =
-        CreateBasicBlockWithDexPC(dex_pc, "overflow");
-
-    llvm::BasicBlock* block_continue =
-        CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-    irb_.CreateCondBr(cmp, block_exception, block_continue, kUnlikely);
-
-    irb_.SetInsertPoint(block_exception);
-
-    EmitUpdateDexPC(dex_pc);
-    irb_.CreateCall2(irb_.GetRuntime(ThrowIndexOutOfBounds), index, array_len);
-    EmitBranchExceptionLandingPad(dex_pc);
-
-    irb_.SetInsertPoint(block_continue);
-  }
-}
-
-llvm::FunctionType* GBCExpanderPass::GetFunctionType(llvm::Type* ret_type, uint32_t method_idx,
-                                                     bool is_static) {
-  // Get method signature
-  art::DexFile::MethodId const& method_id =
-      dex_compilation_unit_->GetDexFile()->GetMethodId(method_idx);
-
-  uint32_t shorty_size;
-  const char* shorty = dex_compilation_unit_->GetDexFile()->GetMethodShorty(method_id, &shorty_size);
-  CHECK_GE(shorty_size, 1u);
-
-  // Get argument type
-  std::vector<llvm::Type*> args_type;
-
-  args_type.push_back(irb_.getJObjectTy());  // method object pointer
-
-  if (!is_static) {
-    args_type.push_back(irb_.getJType('L'));  // "this" object pointer
-  }
-
-  for (uint32_t i = 1; i < shorty_size; ++i) {
-    char shorty_type = art::RemapShorty(shorty[i]);
-    args_type.push_back(irb_.getJType(shorty_type));
-  }
-
-  return llvm::FunctionType::get(ret_type, args_type, false);
-}
-
-
-llvm::BasicBlock* GBCExpanderPass::
-CreateBasicBlockWithDexPC(uint32_t dex_pc, const char* postfix) {
-  std::string name;
-
-#if !defined(NDEBUG)
-  art::StringAppendF(&name, "B%04x.%s", dex_pc, postfix);
-#endif
-
-  return llvm::BasicBlock::Create(context_, name, func_);
-}
-
-llvm::BasicBlock* GBCExpanderPass::GetBasicBlock(uint32_t dex_pc) {
-  DCHECK(dex_pc < dex_compilation_unit_->GetCodeItem()->insns_size_in_code_units_);
-  CHECK(basic_blocks_[dex_pc] != NULL);
-  return basic_blocks_[dex_pc];
-}
-
-int32_t GBCExpanderPass::GetTryItemOffset(uint32_t dex_pc) {
-  int32_t min = 0;
-  int32_t max = dex_compilation_unit_->GetCodeItem()->tries_size_ - 1;
-
-  while (min <= max) {
-    int32_t mid = min + (max - min) / 2;
-
-    const art::DexFile::TryItem* ti =
-        art::DexFile::GetTryItems(*dex_compilation_unit_->GetCodeItem(), mid);
-    uint32_t start = ti->start_addr_;
-    uint32_t end = start + ti->insn_count_;
-
-    if (dex_pc < start) {
-      max = mid - 1;
-    } else if (dex_pc >= end) {
-      min = mid + 1;
-    } else {
-      return mid;  // found
-    }
-  }
-
-  return -1;  // not found
-}
-
-llvm::BasicBlock* GBCExpanderPass::GetLandingPadBasicBlock(uint32_t dex_pc) {
-  // Find the try item for this address in this method
-  int32_t ti_offset = GetTryItemOffset(dex_pc);
-
-  if (ti_offset == -1) {
-    return NULL;  // No landing pad is available for this address.
-  }
-
-  // Check for the existing landing pad basic block
-  DCHECK_GT(basic_block_landing_pads_.size(), static_cast<size_t>(ti_offset));
-  llvm::BasicBlock* block_lpad = basic_block_landing_pads_[ti_offset];
-
-  if (block_lpad) {
-    // We have generated landing pad for this try item already.  Return the
-    // same basic block.
-    return block_lpad;
-  }
-
-  // Get try item from code item
-  const art::DexFile::TryItem* ti = art::DexFile::GetTryItems(*dex_compilation_unit_->GetCodeItem(),
-                                                              ti_offset);
-
-  std::string lpadname;
-
-#if !defined(NDEBUG)
-  art::StringAppendF(&lpadname, "lpad%d_%04x_to_%04x", ti_offset, ti->start_addr_, ti->handler_off_);
-#endif
-
-  // Create landing pad basic block
-  block_lpad = llvm::BasicBlock::Create(context_, lpadname, func_);
-
-  // Change IRBuilder insert point
-  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
-  irb_.SetInsertPoint(block_lpad);
-
-  // Find catch block with matching type
-  llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
-  llvm::Value* ti_offset_value = irb_.getInt32(ti_offset);
-
-  llvm::Value* catch_handler_index_value =
-    irb_.CreateCall2(irb_.GetRuntime(FindCatchBlock),
-                     method_object_addr, ti_offset_value);
-
-  // Switch instruction (Go to unwind basic block by default)
-  llvm::SwitchInst* sw =
-    irb_.CreateSwitch(catch_handler_index_value, GetUnwindBasicBlock());
-
-  // Cases with matched catch block
-  art::CatchHandlerIterator iter(*dex_compilation_unit_->GetCodeItem(), ti->start_addr_);
-
-  for (uint32_t c = 0; iter.HasNext(); iter.Next(), ++c) {
-    sw->addCase(irb_.getInt32(c), GetBasicBlock(iter.GetHandlerAddress()));
-  }
-
-  // Restore the orignal insert point for IRBuilder
-  irb_.restoreIP(irb_ip_original);
-
-  // Cache this landing pad
-  DCHECK_GT(basic_block_landing_pads_.size(), static_cast<size_t>(ti_offset));
-  basic_block_landing_pads_[ti_offset] = block_lpad;
-
-  return block_lpad;
-}
-
-llvm::BasicBlock* GBCExpanderPass::GetUnwindBasicBlock() {
-  // Check the existing unwinding baisc block block
-  if (basic_block_unwind_ != NULL) {
-    return basic_block_unwind_;
-  }
-
-  // Create new basic block for unwinding
-  basic_block_unwind_ =
-    llvm::BasicBlock::Create(context_, "exception_unwind", func_);
-
-  // Change IRBuilder insert point
-  llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
-  irb_.SetInsertPoint(basic_block_unwind_);
-
-  // Pop the shadow frame
-  Expand_PopShadowFrame();
-
-  // Emit the code to return default value (zero) for the given return type.
-  char ret_shorty = dex_compilation_unit_->GetShorty()[0];
-  ret_shorty = art::RemapShorty(ret_shorty);
-  if (ret_shorty == 'V') {
-    irb_.CreateRetVoid();
-  } else {
-    irb_.CreateRet(irb_.getJZero(ret_shorty));
-  }
-
-  // Restore the orignal insert point for IRBuilder
-  irb_.restoreIP(irb_ip_original);
-
-  return basic_block_unwind_;
-}
-
-void GBCExpanderPass::EmitBranchExceptionLandingPad(uint32_t dex_pc) {
-  if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
-    landing_pad_phi_mapping_[lpad].push_back(std::make_pair(current_bb_->getUniquePredecessor(),
-                                                            irb_.GetInsertBlock()));
-    irb_.CreateBr(lpad);
-  } else {
-    irb_.CreateBr(GetUnwindBasicBlock());
-  }
-}
-
-void GBCExpanderPass::EmitGuard_ExceptionLandingPad(uint32_t dex_pc) {
-  llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
-
-  llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
-
-  if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
-    landing_pad_phi_mapping_[lpad].push_back(std::make_pair(current_bb_->getUniquePredecessor(),
-                                                            irb_.GetInsertBlock()));
-    irb_.CreateCondBr(exception_pending, lpad, block_cont, kUnlikely);
-  } else {
-    irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont, kUnlikely);
-  }
-
-  irb_.SetInsertPoint(block_cont);
-}
-
-llvm::Value*
-GBCExpanderPass::ExpandIntrinsic(IntrinsicHelper::IntrinsicId intr_id,
-                                 llvm::CallInst& call_inst) {
-  switch (intr_id) {
-    //==- Thread -----------------------------------------------------------==//
-    case IntrinsicHelper::GetCurrentThread: {
-      return irb_.Runtime().EmitGetCurrentThread();
-    }
-    case IntrinsicHelper::CheckSuspend: {
-      Expand_TestSuspend(call_inst);
-      return NULL;
-    }
-    case IntrinsicHelper::TestSuspend: {
-      Expand_TestSuspend(call_inst);
-      return NULL;
-    }
-    case IntrinsicHelper::MarkGCCard: {
-      Expand_MarkGCCard(call_inst);
-      return NULL;
-    }
-
-    //==- Exception --------------------------------------------------------==//
-    case IntrinsicHelper::ThrowException: {
-      return ExpandToRuntime(ThrowException, call_inst);
-    }
-    case IntrinsicHelper::HLThrowException: {
-      uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
-
-      EmitUpdateDexPC(dex_pc);
-
-      irb_.CreateCall(irb_.GetRuntime(ThrowException),
-                      call_inst.getArgOperand(0));
-
-      EmitGuard_ExceptionLandingPad(dex_pc);
-      return NULL;
-    }
-    case IntrinsicHelper::GetException: {
-      return irb_.Runtime().EmitGetAndClearException();
-    }
-    case IntrinsicHelper::IsExceptionPending: {
-      return irb_.Runtime().EmitIsExceptionPending();
-    }
-    case IntrinsicHelper::FindCatchBlock: {
-      return ExpandToRuntime(FindCatchBlock, call_inst);
-    }
-    case IntrinsicHelper::ThrowDivZeroException: {
-      return ExpandToRuntime(ThrowDivZeroException, call_inst);
-    }
-    case IntrinsicHelper::ThrowNullPointerException: {
-      return ExpandToRuntime(ThrowNullPointerException, call_inst);
-    }
-    case IntrinsicHelper::ThrowIndexOutOfBounds: {
-      return ExpandToRuntime(ThrowIndexOutOfBounds, call_inst);
-    }
-
-    //==- Const String -----------------------------------------------------==//
-    case IntrinsicHelper::ConstString: {
-      return Expand_ConstString(call_inst);
-    }
-    case IntrinsicHelper::LoadStringFromDexCache: {
-      return Expand_LoadStringFromDexCache(call_inst.getArgOperand(0));
-    }
-    case IntrinsicHelper::ResolveString: {
-      return ExpandToRuntime(ResolveString, call_inst);
-    }
-
-    //==- Const Class ------------------------------------------------------==//
-    case IntrinsicHelper::ConstClass: {
-      return Expand_ConstClass(call_inst);
-    }
-    case IntrinsicHelper::InitializeTypeAndVerifyAccess: {
-      return ExpandToRuntime(InitializeTypeAndVerifyAccess, call_inst);
-    }
-    case IntrinsicHelper::LoadTypeFromDexCache: {
-      return Expand_LoadTypeFromDexCache(call_inst.getArgOperand(0));
-    }
-    case IntrinsicHelper::InitializeType: {
-      return ExpandToRuntime(InitializeType, call_inst);
-    }
-
-    //==- Lock -------------------------------------------------------------==//
-    case IntrinsicHelper::LockObject: {
-      Expand_LockObject(call_inst.getArgOperand(0));
-      return NULL;
-    }
-    case IntrinsicHelper::UnlockObject: {
-      Expand_UnlockObject(call_inst.getArgOperand(0));
-      return NULL;
-    }
-
-    //==- Cast -------------------------------------------------------------==//
-    case IntrinsicHelper::CheckCast: {
-      return ExpandToRuntime(CheckCast, call_inst);
-    }
-    case IntrinsicHelper::HLCheckCast: {
-      Expand_HLCheckCast(call_inst);
-      return NULL;
-    }
-    case IntrinsicHelper::IsAssignable: {
-      return ExpandToRuntime(IsAssignable, call_inst);
-    }
-
-    //==- Alloc ------------------------------------------------------------==//
-    case IntrinsicHelper::AllocObject: {
-      return ExpandToRuntime(AllocObject, call_inst);
-    }
-    case IntrinsicHelper::AllocObjectWithAccessCheck: {
-      return ExpandToRuntime(AllocObjectWithAccessCheck, call_inst);
-    }
-
-    //==- Instance ---------------------------------------------------------==//
-    case IntrinsicHelper::NewInstance: {
-      return Expand_NewInstance(call_inst);
-    }
-    case IntrinsicHelper::InstanceOf: {
-      return Expand_InstanceOf(call_inst);
-    }
-
-    //==- Array ------------------------------------------------------------==//
-    case IntrinsicHelper::NewArray: {
-      return Expand_NewArray(call_inst);
-    }
-    case IntrinsicHelper::OptArrayLength: {
-      return Expand_OptArrayLength(call_inst);
-    }
-    case IntrinsicHelper::ArrayLength: {
-      return EmitLoadArrayLength(call_inst.getArgOperand(0));
-    }
-    case IntrinsicHelper::AllocArray: {
-      return ExpandToRuntime(AllocArray, call_inst);
-    }
-    case IntrinsicHelper::AllocArrayWithAccessCheck: {
-      return ExpandToRuntime(AllocArrayWithAccessCheck,
-                             call_inst);
-    }
-    case IntrinsicHelper::CheckAndAllocArray: {
-      return ExpandToRuntime(CheckAndAllocArray, call_inst);
-    }
-    case IntrinsicHelper::CheckAndAllocArrayWithAccessCheck: {
-      return ExpandToRuntime(CheckAndAllocArrayWithAccessCheck,
-                             call_inst);
-    }
-    case IntrinsicHelper::ArrayGet: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kInt);
-    }
-    case IntrinsicHelper::ArrayGetWide: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kLong);
-    }
-    case IntrinsicHelper::ArrayGetObject: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kObject);
-    }
-    case IntrinsicHelper::ArrayGetBoolean: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kBoolean);
-    }
-    case IntrinsicHelper::ArrayGetByte: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kByte);
-    }
-    case IntrinsicHelper::ArrayGetChar: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kChar);
-    }
-    case IntrinsicHelper::ArrayGetShort: {
-      return Expand_ArrayGet(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             kShort);
-    }
-    case IntrinsicHelper::ArrayPut: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kInt);
-      return NULL;
-    }
-    case IntrinsicHelper::ArrayPutWide: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kLong);
-      return NULL;
-    }
-    case IntrinsicHelper::ArrayPutObject: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kObject);
-      return NULL;
-    }
-    case IntrinsicHelper::ArrayPutBoolean: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kBoolean);
-      return NULL;
-    }
-    case IntrinsicHelper::ArrayPutByte: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kByte);
-      return NULL;
-    }
-    case IntrinsicHelper::ArrayPutChar: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kChar);
-      return NULL;
-    }
-    case IntrinsicHelper::ArrayPutShort: {
-      Expand_ArrayPut(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      kShort);
-      return NULL;
-    }
-    case IntrinsicHelper::CheckPutArrayElement: {
-      return ExpandToRuntime(CheckPutArrayElement, call_inst);
-    }
-    case IntrinsicHelper::FilledNewArray: {
-      Expand_FilledNewArray(call_inst);
-      return NULL;
-    }
-    case IntrinsicHelper::FillArrayData: {
-      return ExpandToRuntime(FillArrayData, call_inst);
-    }
-    case IntrinsicHelper::HLFillArrayData: {
-      Expand_HLFillArrayData(call_inst);
-      return NULL;
-    }
-    case IntrinsicHelper::HLFilledNewArray: {
-      return Expand_HLFilledNewArray(call_inst);
-    }
-
-    //==- Instance Field ---------------------------------------------------==//
-    case IntrinsicHelper::InstanceFieldGet:
-    case IntrinsicHelper::InstanceFieldGetBoolean:
-    case IntrinsicHelper::InstanceFieldGetByte:
-    case IntrinsicHelper::InstanceFieldGetChar:
-    case IntrinsicHelper::InstanceFieldGetShort: {
-      return ExpandToRuntime(Get32Instance, call_inst);
-    }
-    case IntrinsicHelper::InstanceFieldGetWide: {
-      return ExpandToRuntime(Get64Instance, call_inst);
-    }
-    case IntrinsicHelper::InstanceFieldGetObject: {
-      return ExpandToRuntime(GetObjectInstance, call_inst);
-    }
-    case IntrinsicHelper::InstanceFieldGetFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kInt);
-    }
-    case IntrinsicHelper::InstanceFieldGetWideFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kLong);
-    }
-    case IntrinsicHelper::InstanceFieldGetObjectFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kObject);
-    }
-    case IntrinsicHelper::InstanceFieldGetBooleanFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kBoolean);
-    }
-    case IntrinsicHelper::InstanceFieldGetByteFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kByte);
-    }
-    case IntrinsicHelper::InstanceFieldGetCharFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kChar);
-    }
-    case IntrinsicHelper::InstanceFieldGetShortFast: {
-      return Expand_IGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kShort);
-    }
-    case IntrinsicHelper::InstanceFieldPut:
-    case IntrinsicHelper::InstanceFieldPutBoolean:
-    case IntrinsicHelper::InstanceFieldPutByte:
-    case IntrinsicHelper::InstanceFieldPutChar:
-    case IntrinsicHelper::InstanceFieldPutShort: {
-      return ExpandToRuntime(Set32Instance, call_inst);
-    }
-    case IntrinsicHelper::InstanceFieldPutWide: {
-      return ExpandToRuntime(Set64Instance, call_inst);
-    }
-    case IntrinsicHelper::InstanceFieldPutObject: {
-      return ExpandToRuntime(SetObjectInstance, call_inst);
-    }
-    case IntrinsicHelper::InstanceFieldPutFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kInt);
-      return NULL;
-    }
-    case IntrinsicHelper::InstanceFieldPutWideFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kLong);
-      return NULL;
-    }
-    case IntrinsicHelper::InstanceFieldPutObjectFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kObject);
-      return NULL;
-    }
-    case IntrinsicHelper::InstanceFieldPutBooleanFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kBoolean);
-      return NULL;
-    }
-    case IntrinsicHelper::InstanceFieldPutByteFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kByte);
-      return NULL;
-    }
-    case IntrinsicHelper::InstanceFieldPutCharFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kChar);
-      return NULL;
-    }
-    case IntrinsicHelper::InstanceFieldPutShortFast: {
-      Expand_IPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kShort);
-      return NULL;
-    }
-
-    //==- Static Field -----------------------------------------------------==//
-    case IntrinsicHelper::StaticFieldGet:
-    case IntrinsicHelper::StaticFieldGetBoolean:
-    case IntrinsicHelper::StaticFieldGetByte:
-    case IntrinsicHelper::StaticFieldGetChar:
-    case IntrinsicHelper::StaticFieldGetShort: {
-      return ExpandToRuntime(Get32Static, call_inst);
-    }
-    case IntrinsicHelper::StaticFieldGetWide: {
-      return ExpandToRuntime(Get64Static, call_inst);
-    }
-    case IntrinsicHelper::StaticFieldGetObject: {
-      return ExpandToRuntime(GetObjectStatic, call_inst);
-    }
-    case IntrinsicHelper::StaticFieldGetFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kInt);
-    }
-    case IntrinsicHelper::StaticFieldGetWideFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kLong);
-    }
-    case IntrinsicHelper::StaticFieldGetObjectFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kObject);
-    }
-    case IntrinsicHelper::StaticFieldGetBooleanFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kBoolean);
-    }
-    case IntrinsicHelper::StaticFieldGetByteFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kByte);
-    }
-    case IntrinsicHelper::StaticFieldGetCharFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kChar);
-    }
-    case IntrinsicHelper::StaticFieldGetShortFast: {
-      return Expand_SGetFast(call_inst.getArgOperand(0),
-                             call_inst.getArgOperand(1),
-                             call_inst.getArgOperand(2),
-                             kShort);
-    }
-    case IntrinsicHelper::StaticFieldPut:
-    case IntrinsicHelper::StaticFieldPutBoolean:
-    case IntrinsicHelper::StaticFieldPutByte:
-    case IntrinsicHelper::StaticFieldPutChar:
-    case IntrinsicHelper::StaticFieldPutShort: {
-      return ExpandToRuntime(Set32Static, call_inst);
-    }
-    case IntrinsicHelper::StaticFieldPutWide: {
-      return ExpandToRuntime(Set64Static, call_inst);
-    }
-    case IntrinsicHelper::StaticFieldPutObject: {
-      return ExpandToRuntime(SetObjectStatic, call_inst);
-    }
-    case IntrinsicHelper::StaticFieldPutFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kInt);
-      return NULL;
-    }
-    case IntrinsicHelper::StaticFieldPutWideFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kLong);
-      return NULL;
-    }
-    case IntrinsicHelper::StaticFieldPutObjectFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kObject);
-      return NULL;
-    }
-    case IntrinsicHelper::StaticFieldPutBooleanFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kBoolean);
-      return NULL;
-    }
-    case IntrinsicHelper::StaticFieldPutByteFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kByte);
-      return NULL;
-    }
-    case IntrinsicHelper::StaticFieldPutCharFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kChar);
-      return NULL;
-    }
-    case IntrinsicHelper::StaticFieldPutShortFast: {
-      Expand_SPutFast(call_inst.getArgOperand(0),
-                      call_inst.getArgOperand(1),
-                      call_inst.getArgOperand(2),
-                      call_inst.getArgOperand(3),
-                      kShort);
-      return NULL;
-    }
-    case IntrinsicHelper::LoadDeclaringClassSSB: {
-      return Expand_LoadDeclaringClassSSB(call_inst.getArgOperand(0));
-    }
-    case IntrinsicHelper::InitializeAndLoadClassSSB: {
-      return ExpandToRuntime(InitializeStaticStorage, call_inst);
-    }
-
-    //==- High-level Array -------------------------------------------------==//
-    case IntrinsicHelper::HLArrayGet: {
-      return Expand_HLArrayGet(call_inst, kInt);
-    }
-    case IntrinsicHelper::HLArrayGetBoolean: {
-      return Expand_HLArrayGet(call_inst, kBoolean);
-    }
-    case IntrinsicHelper::HLArrayGetByte: {
-      return Expand_HLArrayGet(call_inst, kByte);
-    }
-    case IntrinsicHelper::HLArrayGetChar: {
-      return Expand_HLArrayGet(call_inst, kChar);
-    }
-    case IntrinsicHelper::HLArrayGetShort: {
-      return Expand_HLArrayGet(call_inst, kShort);
-    }
-    case IntrinsicHelper::HLArrayGetFloat: {
-      return Expand_HLArrayGet(call_inst, kFloat);
-    }
-    case IntrinsicHelper::HLArrayGetWide: {
-      return Expand_HLArrayGet(call_inst, kLong);
-    }
-    case IntrinsicHelper::HLArrayGetDouble: {
-      return Expand_HLArrayGet(call_inst, kDouble);
-    }
-    case IntrinsicHelper::HLArrayGetObject: {
-      return Expand_HLArrayGet(call_inst, kObject);
-    }
-    case IntrinsicHelper::HLArrayPut: {
-      Expand_HLArrayPut(call_inst, kInt);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutBoolean: {
-      Expand_HLArrayPut(call_inst, kBoolean);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutByte: {
-      Expand_HLArrayPut(call_inst, kByte);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutChar: {
-      Expand_HLArrayPut(call_inst, kChar);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutShort: {
-      Expand_HLArrayPut(call_inst, kShort);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutFloat: {
-      Expand_HLArrayPut(call_inst, kFloat);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutWide: {
-      Expand_HLArrayPut(call_inst, kLong);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutDouble: {
-      Expand_HLArrayPut(call_inst, kDouble);
-      return NULL;
-    }
-    case IntrinsicHelper::HLArrayPutObject: {
-      Expand_HLArrayPut(call_inst, kObject);
-      return NULL;
-    }
-
-    //==- High-level Instance ----------------------------------------------==//
-    case IntrinsicHelper::HLIGet: {
-      return Expand_HLIGet(call_inst, kInt);
-    }
-    case IntrinsicHelper::HLIGetBoolean: {
-      return Expand_HLIGet(call_inst, kBoolean);
-    }
-    case IntrinsicHelper::HLIGetByte: {
-      return Expand_HLIGet(call_inst, kByte);
-    }
-    case IntrinsicHelper::HLIGetChar: {
-      return Expand_HLIGet(call_inst, kChar);
-    }
-    case IntrinsicHelper::HLIGetShort: {
-      return Expand_HLIGet(call_inst, kShort);
-    }
-    case IntrinsicHelper::HLIGetFloat: {
-      return Expand_HLIGet(call_inst, kFloat);
-    }
-    case IntrinsicHelper::HLIGetWide: {
-      return Expand_HLIGet(call_inst, kLong);
-    }
-    case IntrinsicHelper::HLIGetDouble: {
-      return Expand_HLIGet(call_inst, kDouble);
-    }
-    case IntrinsicHelper::HLIGetObject: {
-      return Expand_HLIGet(call_inst, kObject);
-    }
-    case IntrinsicHelper::HLIPut: {
-      Expand_HLIPut(call_inst, kInt);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutBoolean: {
-      Expand_HLIPut(call_inst, kBoolean);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutByte: {
-      Expand_HLIPut(call_inst, kByte);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutChar: {
-      Expand_HLIPut(call_inst, kChar);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutShort: {
-      Expand_HLIPut(call_inst, kShort);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutFloat: {
-      Expand_HLIPut(call_inst, kFloat);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutWide: {
-      Expand_HLIPut(call_inst, kLong);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutDouble: {
-      Expand_HLIPut(call_inst, kDouble);
-      return NULL;
-    }
-    case IntrinsicHelper::HLIPutObject: {
-      Expand_HLIPut(call_inst, kObject);
-      return NULL;
-    }
-
-    //==- High-level Invoke ------------------------------------------------==//
-    case IntrinsicHelper::HLInvokeVoid:
-    case IntrinsicHelper::HLInvokeObj:
-    case IntrinsicHelper::HLInvokeInt:
-    case IntrinsicHelper::HLInvokeFloat:
-    case IntrinsicHelper::HLInvokeLong:
-    case IntrinsicHelper::HLInvokeDouble: {
-      return Expand_HLInvoke(call_inst);
-    }
-
-    //==- Invoke -----------------------------------------------------------==//
-    case IntrinsicHelper::FindStaticMethodWithAccessCheck: {
-      return ExpandToRuntime(FindStaticMethodWithAccessCheck, call_inst);
-    }
-    case IntrinsicHelper::FindDirectMethodWithAccessCheck: {
-      return ExpandToRuntime(FindDirectMethodWithAccessCheck, call_inst);
-    }
-    case IntrinsicHelper::FindVirtualMethodWithAccessCheck: {
-      return ExpandToRuntime(FindVirtualMethodWithAccessCheck, call_inst);
-    }
-    case IntrinsicHelper::FindSuperMethodWithAccessCheck: {
-      return ExpandToRuntime(FindSuperMethodWithAccessCheck, call_inst);
-    }
-    case IntrinsicHelper::FindInterfaceMethodWithAccessCheck: {
-      return ExpandToRuntime(FindInterfaceMethodWithAccessCheck, call_inst);
-    }
-    case IntrinsicHelper::GetSDCalleeMethodObjAddrFast: {
-      return Expand_GetSDCalleeMethodObjAddrFast(call_inst.getArgOperand(0));
-    }
-    case IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast: {
-      return Expand_GetVirtualCalleeMethodObjAddrFast(
-                call_inst.getArgOperand(0), call_inst.getArgOperand(1));
-    }
-    case IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast: {
-      return ExpandToRuntime(FindInterfaceMethod, call_inst);
-    }
-    case IntrinsicHelper::InvokeRetVoid:
-    case IntrinsicHelper::InvokeRetBoolean:
-    case IntrinsicHelper::InvokeRetByte:
-    case IntrinsicHelper::InvokeRetChar:
-    case IntrinsicHelper::InvokeRetShort:
-    case IntrinsicHelper::InvokeRetInt:
-    case IntrinsicHelper::InvokeRetLong:
-    case IntrinsicHelper::InvokeRetFloat:
-    case IntrinsicHelper::InvokeRetDouble:
-    case IntrinsicHelper::InvokeRetObject: {
-      return Expand_Invoke(call_inst);
-    }
-
-    //==- Math -------------------------------------------------------------==//
-    case IntrinsicHelper::DivInt: {
-      return Expand_DivRem(call_inst, /* is_div */true, kInt);
-    }
-    case IntrinsicHelper::RemInt: {
-      return Expand_DivRem(call_inst, /* is_div */false, kInt);
-    }
-    case IntrinsicHelper::DivLong: {
-      return Expand_DivRem(call_inst, /* is_div */true, kLong);
-    }
-    case IntrinsicHelper::RemLong: {
-      return Expand_DivRem(call_inst, /* is_div */false, kLong);
-    }
-    case IntrinsicHelper::D2L: {
-      return ExpandToRuntime(art_d2l, call_inst);
-    }
-    case IntrinsicHelper::D2I: {
-      return ExpandToRuntime(art_d2i, call_inst);
-    }
-    case IntrinsicHelper::F2L: {
-      return ExpandToRuntime(art_f2l, call_inst);
-    }
-    case IntrinsicHelper::F2I: {
-      return ExpandToRuntime(art_f2i, call_inst);
-    }
-
-    //==- High-level Static ------------------------------------------------==//
-    case IntrinsicHelper::HLSget: {
-      return Expand_HLSget(call_inst, kInt);
-    }
-    case IntrinsicHelper::HLSgetBoolean: {
-      return Expand_HLSget(call_inst, kBoolean);
-    }
-    case IntrinsicHelper::HLSgetByte: {
-      return Expand_HLSget(call_inst, kByte);
-    }
-    case IntrinsicHelper::HLSgetChar: {
-      return Expand_HLSget(call_inst, kChar);
-    }
-    case IntrinsicHelper::HLSgetShort: {
-      return Expand_HLSget(call_inst, kShort);
-    }
-    case IntrinsicHelper::HLSgetFloat: {
-      return Expand_HLSget(call_inst, kFloat);
-    }
-    case IntrinsicHelper::HLSgetWide: {
-      return Expand_HLSget(call_inst, kLong);
-    }
-    case IntrinsicHelper::HLSgetDouble: {
-      return Expand_HLSget(call_inst, kDouble);
-    }
-    case IntrinsicHelper::HLSgetObject: {
-      return Expand_HLSget(call_inst, kObject);
-    }
-    case IntrinsicHelper::HLSput: {
-      Expand_HLSput(call_inst, kInt);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputBoolean: {
-      Expand_HLSput(call_inst, kBoolean);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputByte: {
-      Expand_HLSput(call_inst, kByte);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputChar: {
-      Expand_HLSput(call_inst, kChar);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputShort: {
-      Expand_HLSput(call_inst, kShort);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputFloat: {
-      Expand_HLSput(call_inst, kFloat);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputWide: {
-      Expand_HLSput(call_inst, kLong);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputDouble: {
-      Expand_HLSput(call_inst, kDouble);
-      return NULL;
-    }
-    case IntrinsicHelper::HLSputObject: {
-      Expand_HLSput(call_inst, kObject);
-      return NULL;
-    }
-
-    //==- High-level Monitor -----------------------------------------------==//
-    case IntrinsicHelper::MonitorEnter: {
-      Expand_MonitorEnter(call_inst);
-      return NULL;
-    }
-    case IntrinsicHelper::MonitorExit: {
-      Expand_MonitorExit(call_inst);
-      return NULL;
-    }
-
-    //==- Shadow Frame -----------------------------------------------------==//
-    case IntrinsicHelper::AllocaShadowFrame: {
-      Expand_AllocaShadowFrame(call_inst.getArgOperand(0));
-      return NULL;
-    }
-    case IntrinsicHelper::SetVReg: {
-      Expand_SetVReg(call_inst.getArgOperand(0),
-                     call_inst.getArgOperand(1));
-      return NULL;
-    }
-    case IntrinsicHelper::PopShadowFrame: {
-      Expand_PopShadowFrame();
-      return NULL;
-    }
-    case IntrinsicHelper::UpdateDexPC: {
-      Expand_UpdateDexPC(call_inst.getArgOperand(0));
-      return NULL;
-    }
-
-    //==- Comparison -------------------------------------------------------==//
-    case IntrinsicHelper::CmplFloat:
-    case IntrinsicHelper::CmplDouble: {
-      return Expand_FPCompare(call_inst.getArgOperand(0),
-                              call_inst.getArgOperand(1),
-                              false);
-    }
-    case IntrinsicHelper::CmpgFloat:
-    case IntrinsicHelper::CmpgDouble: {
-      return Expand_FPCompare(call_inst.getArgOperand(0),
-                              call_inst.getArgOperand(1),
-                              true);
-    }
-    case IntrinsicHelper::CmpLong: {
-      return Expand_LongCompare(call_inst.getArgOperand(0),
-                                call_inst.getArgOperand(1));
-    }
-
-    //==- Const ------------------------------------------------------------==//
-    case IntrinsicHelper::ConstInt:
-    case IntrinsicHelper::ConstLong: {
-      return call_inst.getArgOperand(0);
-    }
-    case IntrinsicHelper::ConstFloat: {
-      return irb_.CreateBitCast(call_inst.getArgOperand(0),
-                                irb_.getJFloatTy());
-    }
-    case IntrinsicHelper::ConstDouble: {
-      return irb_.CreateBitCast(call_inst.getArgOperand(0),
-                                irb_.getJDoubleTy());
-    }
-    case IntrinsicHelper::ConstObj: {
-      CHECK_EQ(LV2UInt(call_inst.getArgOperand(0)), 0U);
-      return irb_.getJNull();
-    }
-
-    //==- Method Info ------------------------------------------------------==//
-    case IntrinsicHelper::MethodInfo: {
-      // Nothing to be done, because MethodInfo carries optional hints that are
-      // not needed by the portable path.
-      return NULL;
-    }
-
-    //==- Copy -------------------------------------------------------------==//
-    case IntrinsicHelper::CopyInt:
-    case IntrinsicHelper::CopyFloat:
-    case IntrinsicHelper::CopyLong:
-    case IntrinsicHelper::CopyDouble:
-    case IntrinsicHelper::CopyObj: {
-      return call_inst.getArgOperand(0);
-    }
-
-    //==- Shift ------------------------------------------------------------==//
-    case IntrinsicHelper::SHLLong: {
-      return Expand_IntegerShift(call_inst.getArgOperand(0),
-                                 call_inst.getArgOperand(1),
-                                 kIntegerSHL, kLong);
-    }
-    case IntrinsicHelper::SHRLong: {
-      return Expand_IntegerShift(call_inst.getArgOperand(0),
-                                 call_inst.getArgOperand(1),
-                                 kIntegerSHR, kLong);
-    }
-    case IntrinsicHelper::USHRLong: {
-      return Expand_IntegerShift(call_inst.getArgOperand(0),
-                                 call_inst.getArgOperand(1),
-                                 kIntegerUSHR, kLong);
-    }
-    case IntrinsicHelper::SHLInt: {
-      return Expand_IntegerShift(call_inst.getArgOperand(0),
-                                 call_inst.getArgOperand(1),
-                                 kIntegerSHL, kInt);
-    }
-    case IntrinsicHelper::SHRInt: {
-      return Expand_IntegerShift(call_inst.getArgOperand(0),
-                                 call_inst.getArgOperand(1),
-                                 kIntegerSHR, kInt);
-    }
-    case IntrinsicHelper::USHRInt: {
-      return Expand_IntegerShift(call_inst.getArgOperand(0),
-                                 call_inst.getArgOperand(1),
-                                 kIntegerUSHR, kInt);
-    }
-
-    //==- Conversion -------------------------------------------------------==//
-    case IntrinsicHelper::IntToChar: {
-      return irb_.CreateZExt(irb_.CreateTrunc(call_inst.getArgOperand(0), irb_.getJCharTy()),
-                             irb_.getJIntTy());
-    }
-    case IntrinsicHelper::IntToShort: {
-      return irb_.CreateSExt(irb_.CreateTrunc(call_inst.getArgOperand(0), irb_.getJShortTy()),
-                             irb_.getJIntTy());
-    }
-    case IntrinsicHelper::IntToByte: {
-      return irb_.CreateSExt(irb_.CreateTrunc(call_inst.getArgOperand(0), irb_.getJByteTy()),
-                             irb_.getJIntTy());
-    }
-
-    //==- Exception --------------------------------------------------------==//
-    case IntrinsicHelper::CatchTargets: {
-      UpdatePhiInstruction(current_bb_, irb_.GetInsertBlock());
-      llvm::SwitchInst* si = llvm::dyn_cast<llvm::SwitchInst>(call_inst.getNextNode());
-      CHECK(si != NULL);
-      irb_.CreateBr(si->getDefaultDest());
-      si->eraseFromParent();
-      return call_inst.getArgOperand(0);
-    }
-
-    //==- Constructor barrier-----------------------------------------------==//
-    case IntrinsicHelper::ConstructorBarrier: {
-      irb_.CreateMemoryBarrier(art::kStoreStore);
-      return NULL;
-    }
-
-    //==- Unknown Cases ----------------------------------------------------==//
-    case IntrinsicHelper::MaxIntrinsicId:
-    case IntrinsicHelper::UnknownId:
-    // default:
-      // NOTE: "default" is intentionally commented so that C/C++ compiler will
-      // give some warning on unmatched cases.
-      // NOTE: We should not implement these cases.
-      break;
-  }
-  UNIMPLEMENTED(FATAL) << "Unexpected GBC intrinsic: " << static_cast<int>(intr_id);
-  return NULL;
-}  // NOLINT(readability/fn_size)
-
-}  // anonymous namespace
-
-namespace art {
-namespace llvm {
-
-::llvm::FunctionPass*
-CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb,
-                      CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit) {
-  return new GBCExpanderPass(intrinsic_helper, irb, driver, dex_compilation_unit);
-}
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/generated/art_module.cc b/compiler/llvm/generated/art_module.cc
deleted file mode 100644
index f3c5a5a..0000000
--- a/compiler/llvm/generated/art_module.cc
+++ /dev/null
@@ -1,1096 +0,0 @@
-// Generated with ./gen_art_module_cc.sh
-
-
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
-// TODO: Remove this pragma after llc can generate makeLLVMModuleContents()
-// with smaller frame size.
-
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/Type.h>
-
-#include <vector>
-
-using namespace llvm;
-
-namespace art {
-namespace llvm {
-
-
-// Generated by llvm2cpp - DO NOT MODIFY!
-
-
-Module* makeLLVMModuleContents(Module *mod) {
-
-mod->setModuleIdentifier("art_module.ll");
-
-// Type Definitions
-std::vector<Type*>FuncTy_0_args;
-StructType *StructTy_JavaObject = mod->getTypeByName("JavaObject");
-if (!StructTy_JavaObject) {
-StructTy_JavaObject = StructType::create(mod->getContext(), "JavaObject");
-}
-std::vector<Type*>StructTy_JavaObject_fields;
-if (StructTy_JavaObject->isOpaque()) {
-StructTy_JavaObject->setBody(StructTy_JavaObject_fields, /*isPacked=*/false);
-}
-
-PointerType* PointerTy_1 = PointerType::get(StructTy_JavaObject, 0);
-
-FuncTy_0_args.push_back(PointerTy_1);
-StructType *StructTy_ShadowFrame = mod->getTypeByName("ShadowFrame");
-if (!StructTy_ShadowFrame) {
-StructTy_ShadowFrame = StructType::create(mod->getContext(), "ShadowFrame");
-}
-std::vector<Type*>StructTy_ShadowFrame_fields;
-StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
-PointerType* PointerTy_2 = PointerType::get(StructTy_ShadowFrame, 0);
-
-StructTy_ShadowFrame_fields.push_back(PointerTy_2);
-StructTy_ShadowFrame_fields.push_back(PointerTy_1);
-StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
-if (StructTy_ShadowFrame->isOpaque()) {
-StructTy_ShadowFrame->setBody(StructTy_ShadowFrame_fields, /*isPacked=*/false);
-}
-
-
-FuncTy_0_args.push_back(PointerTy_2);
-FunctionType* FuncTy_0 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_0_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_3_args;
-FunctionType* FuncTy_3 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_3_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_4_args;
-FuncTy_4_args.push_back(PointerTy_1);
-FunctionType* FuncTy_4 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_4_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_5_args;
-FuncTy_5_args.push_back(PointerTy_1);
-FuncTy_5_args.push_back(PointerTy_1);
-FunctionType* FuncTy_5 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_5_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_6_args;
-FuncTy_6_args.push_back(PointerTy_1);
-FunctionType* FuncTy_6 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_6_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_7_args;
-FuncTy_7_args.push_back(PointerTy_1);
-FuncTy_7_args.push_back(PointerTy_2);
-FuncTy_7_args.push_back(PointerTy_1);
-FuncTy_7_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_7 = FunctionType::get(
- /*Result=*/PointerTy_2,
- /*Params=*/FuncTy_7_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_8_args;
-FuncTy_8_args.push_back(PointerTy_2);
-FunctionType* FuncTy_8 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_8_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_9_args;
-FunctionType* FuncTy_9 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_9_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_10_args;
-FuncTy_10_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_10_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_10 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_10_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_11_args;
-FuncTy_11_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_11 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_11_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_12_args;
-FuncTy_12_args.push_back(PointerTy_1);
-FuncTy_12_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_12 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_12_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_13_args;
-FuncTy_13_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_13_args.push_back(PointerTy_1);
-FuncTy_13_args.push_back(PointerTy_1);
-FunctionType* FuncTy_13 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_13_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_14_args;
-FuncTy_14_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_14_args.push_back(PointerTy_1);
-FuncTy_14_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_14_args.push_back(PointerTy_1);
-FunctionType* FuncTy_14 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_14_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_15_args;
-FuncTy_15_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_15_args.push_back(PointerTy_1);
-FunctionType* FuncTy_15 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_15_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_16_args;
-FuncTy_16_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_16_args.push_back(PointerTy_1);
-FuncTy_16_args.push_back(PointerTy_1);
-FuncTy_16_args.push_back(PointerTy_1);
-FunctionType* FuncTy_16 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_16_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_17_args;
-FuncTy_17_args.push_back(PointerTy_1);
-FuncTy_17_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_17 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_17_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_18_args;
-FuncTy_18_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_18_args.push_back(PointerTy_1);
-FuncTy_18_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_18 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_18_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_19_args;
-FuncTy_19_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_19_args.push_back(PointerTy_1);
-FuncTy_19_args.push_back(IntegerType::get(mod->getContext(), 64));
-FunctionType* FuncTy_19 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_19_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_20_args;
-FuncTy_20_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_20_args.push_back(PointerTy_1);
-FuncTy_20_args.push_back(PointerTy_1);
-FunctionType* FuncTy_20 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_20_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_21_args;
-FuncTy_21_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_21_args.push_back(PointerTy_1);
-FunctionType* FuncTy_21 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_21_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_22_args;
-FuncTy_22_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_22_args.push_back(PointerTy_1);
-FunctionType* FuncTy_22 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 64),
- /*Params=*/FuncTy_22_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_23_args;
-FuncTy_23_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_23_args.push_back(PointerTy_1);
-FunctionType* FuncTy_23 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_23_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_24_args;
-FuncTy_24_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_24_args.push_back(PointerTy_1);
-FuncTy_24_args.push_back(PointerTy_1);
-FuncTy_24_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_24 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_24_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_25_args;
-FuncTy_25_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_25_args.push_back(PointerTy_1);
-FuncTy_25_args.push_back(PointerTy_1);
-FuncTy_25_args.push_back(IntegerType::get(mod->getContext(), 64));
-FunctionType* FuncTy_25 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_25_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_26_args;
-FuncTy_26_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_26_args.push_back(PointerTy_1);
-FuncTy_26_args.push_back(PointerTy_1);
-FuncTy_26_args.push_back(PointerTy_1);
-FunctionType* FuncTy_26 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_26_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_27_args;
-FuncTy_27_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_27_args.push_back(PointerTy_1);
-FuncTy_27_args.push_back(PointerTy_1);
-FunctionType* FuncTy_27 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 64),
- /*Params=*/FuncTy_27_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_28_args;
-FuncTy_28_args.push_back(PointerTy_1);
-FuncTy_28_args.push_back(PointerTy_1);
-FunctionType* FuncTy_28 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_28_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_29_args;
-FuncTy_29_args.push_back(PointerTy_1);
-FuncTy_29_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_29_args.push_back(PointerTy_1);
-FuncTy_29_args.push_back(IntegerType::get(mod->getContext(), 32));
-FunctionType* FuncTy_29 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_29_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_30_args;
-FuncTy_30_args.push_back(PointerTy_1);
-FuncTy_30_args.push_back(PointerTy_1);
-FunctionType* FuncTy_30 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_30_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_31_args;
-FuncTy_31_args.push_back(Type::getDoubleTy(mod->getContext()));
-FunctionType* FuncTy_31 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 64),
- /*Params=*/FuncTy_31_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_32_args;
-FuncTy_32_args.push_back(Type::getDoubleTy(mod->getContext()));
-FunctionType* FuncTy_32 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_32_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_33_args;
-FuncTy_33_args.push_back(Type::getFloatTy(mod->getContext()));
-FunctionType* FuncTy_33 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 64),
- /*Params=*/FuncTy_33_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_34_args;
-FuncTy_34_args.push_back(Type::getFloatTy(mod->getContext()));
-FunctionType* FuncTy_34 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_34_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_35_args;
-FuncTy_35_args.push_back(PointerTy_1);
-FunctionType* FuncTy_35 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
- /*Params=*/FuncTy_35_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_36_args;
-FuncTy_36_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_36_args.push_back(PointerTy_1);
-FuncTy_36_args.push_back(PointerTy_1);
-FunctionType* FuncTy_36 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_36_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_37_args;
-FuncTy_37_args.push_back(PointerTy_1);
-FuncTy_37_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_37_args.push_back(PointerTy_1);
-FunctionType* FuncTy_37 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_37_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_38_args;
-FuncTy_38_args.push_back(PointerTy_1);
-FuncTy_38_args.push_back(IntegerType::get(mod->getContext(), 32));
-FuncTy_38_args.push_back(PointerTy_1);
-FuncTy_38_args.push_back(PointerTy_1);
-FunctionType* FuncTy_38 = FunctionType::get(
- /*Result=*/PointerTy_1,
- /*Params=*/FuncTy_38_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_39_args;
-FunctionType* FuncTy_39 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 1),
- /*Params=*/FuncTy_39_args,
- /*isVarArg=*/false);
-
-std::vector<Type*>FuncTy_40_args;
-FuncTy_40_args.push_back(PointerTy_1);
-FunctionType* FuncTy_40 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
- /*Params=*/FuncTy_40_args,
- /*isVarArg=*/true);
-
-
-// Function Declarations
-
-Function* func___art_type_list = mod->getFunction("__art_type_list");
-if (!func___art_type_list) {
-func___art_type_list = Function::Create(
- /*Type=*/FuncTy_0,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"__art_type_list", mod);  // (external, no body)
-func___art_type_list->setCallingConv(CallingConv::C);
-}
-AttributeSet func___art_type_list_PAL;
-func___art_type_list->setAttributes(func___art_type_list_PAL);
-
-Function* func_art_portable_get_current_thread_from_code = mod->getFunction("art_portable_get_current_thread_from_code");
-if (!func_art_portable_get_current_thread_from_code) {
-func_art_portable_get_current_thread_from_code = Function::Create(
- /*Type=*/FuncTy_3,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get_current_thread_from_code", mod);  // (external, no body)
-func_art_portable_get_current_thread_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get_current_thread_from_code_PAL;
-func_art_portable_get_current_thread_from_code->setAttributes(func_art_portable_get_current_thread_from_code_PAL);
-
-Function* func_art_portable_set_current_thread_from_code = mod->getFunction("art_portable_set_current_thread_from_code");
-if (!func_art_portable_set_current_thread_from_code) {
-func_art_portable_set_current_thread_from_code = Function::Create(
- /*Type=*/FuncTy_4,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set_current_thread_from_code", mod);  // (external, no body)
-func_art_portable_set_current_thread_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set_current_thread_from_code_PAL;
-func_art_portable_set_current_thread_from_code->setAttributes(func_art_portable_set_current_thread_from_code_PAL);
-
-Function* func_art_portable_lock_object_from_code = mod->getFunction("art_portable_lock_object_from_code");
-if (!func_art_portable_lock_object_from_code) {
-func_art_portable_lock_object_from_code = Function::Create(
- /*Type=*/FuncTy_5,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_lock_object_from_code", mod);  // (external, no body)
-func_art_portable_lock_object_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_lock_object_from_code_PAL;
-func_art_portable_lock_object_from_code->setAttributes(func_art_portable_lock_object_from_code_PAL);
-
-Function* func_art_portable_unlock_object_from_code = mod->getFunction("art_portable_unlock_object_from_code");
-if (!func_art_portable_unlock_object_from_code) {
-func_art_portable_unlock_object_from_code = Function::Create(
- /*Type=*/FuncTy_5,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_unlock_object_from_code", mod);  // (external, no body)
-func_art_portable_unlock_object_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_unlock_object_from_code_PAL;
-func_art_portable_unlock_object_from_code->setAttributes(func_art_portable_unlock_object_from_code_PAL);
-
-Function* func_art_portable_test_suspend_from_code = mod->getFunction("art_portable_test_suspend_from_code");
-if (!func_art_portable_test_suspend_from_code) {
-func_art_portable_test_suspend_from_code = Function::Create(
- /*Type=*/FuncTy_6,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_test_suspend_from_code", mod);  // (external, no body)
-func_art_portable_test_suspend_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_test_suspend_from_code_PAL;
-func_art_portable_test_suspend_from_code->setAttributes(func_art_portable_test_suspend_from_code_PAL);
-
-Function* func_art_portable_push_shadow_frame_from_code = mod->getFunction("art_portable_push_shadow_frame_from_code");
-if (!func_art_portable_push_shadow_frame_from_code) {
-func_art_portable_push_shadow_frame_from_code = Function::Create(
- /*Type=*/FuncTy_7,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_push_shadow_frame_from_code", mod);  // (external, no body)
-func_art_portable_push_shadow_frame_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_push_shadow_frame_from_code_PAL;
-func_art_portable_push_shadow_frame_from_code->setAttributes(func_art_portable_push_shadow_frame_from_code_PAL);
-
-Function* func_art_portable_pop_shadow_frame_from_code = mod->getFunction("art_portable_pop_shadow_frame_from_code");
-if (!func_art_portable_pop_shadow_frame_from_code) {
-func_art_portable_pop_shadow_frame_from_code = Function::Create(
- /*Type=*/FuncTy_8,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_pop_shadow_frame_from_code", mod);  // (external, no body)
-func_art_portable_pop_shadow_frame_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_pop_shadow_frame_from_code_PAL;
-func_art_portable_pop_shadow_frame_from_code->setAttributes(func_art_portable_pop_shadow_frame_from_code_PAL);
-
-Function* func_art_portable_get_and_clear_exception = mod->getFunction("art_portable_get_and_clear_exception");
-if (!func_art_portable_get_and_clear_exception) {
-func_art_portable_get_and_clear_exception = Function::Create(
- /*Type=*/FuncTy_4,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get_and_clear_exception", mod);  // (external, no body)
-func_art_portable_get_and_clear_exception->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get_and_clear_exception_PAL;
-func_art_portable_get_and_clear_exception->setAttributes(func_art_portable_get_and_clear_exception_PAL);
-
-Function* func_art_portable_throw_div_zero_from_code = mod->getFunction("art_portable_throw_div_zero_from_code");
-if (!func_art_portable_throw_div_zero_from_code) {
-func_art_portable_throw_div_zero_from_code = Function::Create(
- /*Type=*/FuncTy_9,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_throw_div_zero_from_code", mod);  // (external, no body)
-func_art_portable_throw_div_zero_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_throw_div_zero_from_code_PAL;
-func_art_portable_throw_div_zero_from_code->setAttributes(func_art_portable_throw_div_zero_from_code_PAL);
-
-Function* func_art_portable_throw_array_bounds_from_code = mod->getFunction("art_portable_throw_array_bounds_from_code");
-if (!func_art_portable_throw_array_bounds_from_code) {
-func_art_portable_throw_array_bounds_from_code = Function::Create(
- /*Type=*/FuncTy_10,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_throw_array_bounds_from_code", mod);  // (external, no body)
-func_art_portable_throw_array_bounds_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_throw_array_bounds_from_code_PAL;
-func_art_portable_throw_array_bounds_from_code->setAttributes(func_art_portable_throw_array_bounds_from_code_PAL);
-
-Function* func_art_portable_throw_no_such_method_from_code = mod->getFunction("art_portable_throw_no_such_method_from_code");
-if (!func_art_portable_throw_no_such_method_from_code) {
-func_art_portable_throw_no_such_method_from_code = Function::Create(
- /*Type=*/FuncTy_11,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_throw_no_such_method_from_code", mod);  // (external, no body)
-func_art_portable_throw_no_such_method_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_throw_no_such_method_from_code_PAL;
-func_art_portable_throw_no_such_method_from_code->setAttributes(func_art_portable_throw_no_such_method_from_code_PAL);
-
-Function* func_art_portable_throw_null_pointer_exception_from_code = mod->getFunction("art_portable_throw_null_pointer_exception_from_code");
-if (!func_art_portable_throw_null_pointer_exception_from_code) {
-func_art_portable_throw_null_pointer_exception_from_code = Function::Create(
- /*Type=*/FuncTy_11,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_throw_null_pointer_exception_from_code", mod);  // (external, no body)
-func_art_portable_throw_null_pointer_exception_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_throw_null_pointer_exception_from_code_PAL;
-func_art_portable_throw_null_pointer_exception_from_code->setAttributes(func_art_portable_throw_null_pointer_exception_from_code_PAL);
-
-Function* func_art_portable_throw_stack_overflow_from_code = mod->getFunction("art_portable_throw_stack_overflow_from_code");
-if (!func_art_portable_throw_stack_overflow_from_code) {
-func_art_portable_throw_stack_overflow_from_code = Function::Create(
- /*Type=*/FuncTy_9,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_throw_stack_overflow_from_code", mod);  // (external, no body)
-func_art_portable_throw_stack_overflow_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_throw_stack_overflow_from_code_PAL;
-func_art_portable_throw_stack_overflow_from_code->setAttributes(func_art_portable_throw_stack_overflow_from_code_PAL);
-
-Function* func_art_portable_throw_exception_from_code = mod->getFunction("art_portable_throw_exception_from_code");
-if (!func_art_portable_throw_exception_from_code) {
-func_art_portable_throw_exception_from_code = Function::Create(
- /*Type=*/FuncTy_6,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_throw_exception_from_code", mod);  // (external, no body)
-func_art_portable_throw_exception_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_throw_exception_from_code_PAL;
-func_art_portable_throw_exception_from_code->setAttributes(func_art_portable_throw_exception_from_code_PAL);
-
-Function* func_art_portable_find_catch_block_from_code = mod->getFunction("art_portable_find_catch_block_from_code");
-if (!func_art_portable_find_catch_block_from_code) {
-func_art_portable_find_catch_block_from_code = Function::Create(
- /*Type=*/FuncTy_12,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_catch_block_from_code", mod);  // (external, no body)
-func_art_portable_find_catch_block_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_catch_block_from_code_PAL;
-func_art_portable_find_catch_block_from_code->setAttributes(func_art_portable_find_catch_block_from_code_PAL);
-
-Function* func_art_portable_alloc_object_from_code = mod->getFunction("art_portable_alloc_object_from_code");
-if (!func_art_portable_alloc_object_from_code) {
-func_art_portable_alloc_object_from_code = Function::Create(
- /*Type=*/FuncTy_13,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_alloc_object_from_code", mod);  // (external, no body)
-func_art_portable_alloc_object_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_alloc_object_from_code_PAL;
-func_art_portable_alloc_object_from_code->setAttributes(func_art_portable_alloc_object_from_code_PAL);
-
-Function* func_art_portable_alloc_object_from_code_with_access_check = mod->getFunction("art_portable_alloc_object_from_code_with_access_check");
-if (!func_art_portable_alloc_object_from_code_with_access_check) {
-func_art_portable_alloc_object_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_13,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_alloc_object_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_alloc_object_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_alloc_object_from_code_with_access_check_PAL;
-func_art_portable_alloc_object_from_code_with_access_check->setAttributes(func_art_portable_alloc_object_from_code_with_access_check_PAL);
-
-Function* func_art_portable_alloc_array_from_code = mod->getFunction("art_portable_alloc_array_from_code");
-if (!func_art_portable_alloc_array_from_code) {
-func_art_portable_alloc_array_from_code = Function::Create(
- /*Type=*/FuncTy_14,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_alloc_array_from_code", mod);  // (external, no body)
-func_art_portable_alloc_array_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_alloc_array_from_code_PAL;
-func_art_portable_alloc_array_from_code->setAttributes(func_art_portable_alloc_array_from_code_PAL);
-
-Function* func_art_portable_alloc_array_from_code_with_access_check = mod->getFunction("art_portable_alloc_array_from_code_with_access_check");
-if (!func_art_portable_alloc_array_from_code_with_access_check) {
-func_art_portable_alloc_array_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_14,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_alloc_array_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_alloc_array_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_alloc_array_from_code_with_access_check_PAL;
-func_art_portable_alloc_array_from_code_with_access_check->setAttributes(func_art_portable_alloc_array_from_code_with_access_check_PAL);
-
-Function* func_art_portable_check_and_alloc_array_from_code = mod->getFunction("art_portable_check_and_alloc_array_from_code");
-if (!func_art_portable_check_and_alloc_array_from_code) {
-func_art_portable_check_and_alloc_array_from_code = Function::Create(
- /*Type=*/FuncTy_14,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_check_and_alloc_array_from_code", mod);  // (external, no body)
-func_art_portable_check_and_alloc_array_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_check_and_alloc_array_from_code_PAL;
-func_art_portable_check_and_alloc_array_from_code->setAttributes(func_art_portable_check_and_alloc_array_from_code_PAL);
-
-Function* func_art_portable_check_and_alloc_array_from_code_with_access_check = mod->getFunction("art_portable_check_and_alloc_array_from_code_with_access_check");
-if (!func_art_portable_check_and_alloc_array_from_code_with_access_check) {
-func_art_portable_check_and_alloc_array_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_14,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_check_and_alloc_array_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_check_and_alloc_array_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_check_and_alloc_array_from_code_with_access_check_PAL;
-func_art_portable_check_and_alloc_array_from_code_with_access_check->setAttributes(func_art_portable_check_and_alloc_array_from_code_with_access_check_PAL);
-
-Function* func_art_portable_find_instance_field_from_code = mod->getFunction("art_portable_find_instance_field_from_code");
-if (!func_art_portable_find_instance_field_from_code) {
-func_art_portable_find_instance_field_from_code = Function::Create(
- /*Type=*/FuncTy_15,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_instance_field_from_code", mod);  // (external, no body)
-func_art_portable_find_instance_field_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_instance_field_from_code_PAL;
-func_art_portable_find_instance_field_from_code->setAttributes(func_art_portable_find_instance_field_from_code_PAL);
-
-Function* func_art_portable_find_static_field_from_code = mod->getFunction("art_portable_find_static_field_from_code");
-if (!func_art_portable_find_static_field_from_code) {
-func_art_portable_find_static_field_from_code = Function::Create(
- /*Type=*/FuncTy_15,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_static_field_from_code", mod);  // (external, no body)
-func_art_portable_find_static_field_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_static_field_from_code_PAL;
-func_art_portable_find_static_field_from_code->setAttributes(func_art_portable_find_static_field_from_code_PAL);
-
-Function* func_art_portable_find_static_method_from_code_with_access_check = mod->getFunction("art_portable_find_static_method_from_code_with_access_check");
-if (!func_art_portable_find_static_method_from_code_with_access_check) {
-func_art_portable_find_static_method_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_16,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_static_method_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_find_static_method_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_static_method_from_code_with_access_check_PAL;
-func_art_portable_find_static_method_from_code_with_access_check->setAttributes(func_art_portable_find_static_method_from_code_with_access_check_PAL);
-
-Function* func_art_portable_find_direct_method_from_code_with_access_check = mod->getFunction("art_portable_find_direct_method_from_code_with_access_check");
-if (!func_art_portable_find_direct_method_from_code_with_access_check) {
-func_art_portable_find_direct_method_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_16,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_direct_method_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_find_direct_method_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_direct_method_from_code_with_access_check_PAL;
-func_art_portable_find_direct_method_from_code_with_access_check->setAttributes(func_art_portable_find_direct_method_from_code_with_access_check_PAL);
-
-Function* func_art_portable_find_virtual_method_from_code_with_access_check = mod->getFunction("art_portable_find_virtual_method_from_code_with_access_check");
-if (!func_art_portable_find_virtual_method_from_code_with_access_check) {
-func_art_portable_find_virtual_method_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_16,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_virtual_method_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_find_virtual_method_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_virtual_method_from_code_with_access_check_PAL;
-func_art_portable_find_virtual_method_from_code_with_access_check->setAttributes(func_art_portable_find_virtual_method_from_code_with_access_check_PAL);
-
-Function* func_art_portable_find_super_method_from_code_with_access_check = mod->getFunction("art_portable_find_super_method_from_code_with_access_check");
-if (!func_art_portable_find_super_method_from_code_with_access_check) {
-func_art_portable_find_super_method_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_16,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_super_method_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_find_super_method_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_super_method_from_code_with_access_check_PAL;
-func_art_portable_find_super_method_from_code_with_access_check->setAttributes(func_art_portable_find_super_method_from_code_with_access_check_PAL);
-
-Function* func_art_portable_find_interface_method_from_code_with_access_check = mod->getFunction("art_portable_find_interface_method_from_code_with_access_check");
-if (!func_art_portable_find_interface_method_from_code_with_access_check) {
-func_art_portable_find_interface_method_from_code_with_access_check = Function::Create(
- /*Type=*/FuncTy_16,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_interface_method_from_code_with_access_check", mod);  // (external, no body)
-func_art_portable_find_interface_method_from_code_with_access_check->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_interface_method_from_code_with_access_check_PAL;
-func_art_portable_find_interface_method_from_code_with_access_check->setAttributes(func_art_portable_find_interface_method_from_code_with_access_check_PAL);
-
-Function* func_art_portable_find_interface_method_from_code = mod->getFunction("art_portable_find_interface_method_from_code");
-if (!func_art_portable_find_interface_method_from_code) {
-func_art_portable_find_interface_method_from_code = Function::Create(
- /*Type=*/FuncTy_16,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_find_interface_method_from_code", mod);  // (external, no body)
-func_art_portable_find_interface_method_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_find_interface_method_from_code_PAL;
-func_art_portable_find_interface_method_from_code->setAttributes(func_art_portable_find_interface_method_from_code_PAL);
-
-Function* func_art_portable_initialize_static_storage_from_code = mod->getFunction("art_portable_initialize_static_storage_from_code");
-if (!func_art_portable_initialize_static_storage_from_code) {
-func_art_portable_initialize_static_storage_from_code = Function::Create(
- /*Type=*/FuncTy_13,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_initialize_static_storage_from_code", mod);  // (external, no body)
-func_art_portable_initialize_static_storage_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_initialize_static_storage_from_code_PAL;
-func_art_portable_initialize_static_storage_from_code->setAttributes(func_art_portable_initialize_static_storage_from_code_PAL);
-
-Function* func_art_portable_initialize_type_from_code = mod->getFunction("art_portable_initialize_type_from_code");
-if (!func_art_portable_initialize_type_from_code) {
-func_art_portable_initialize_type_from_code = Function::Create(
- /*Type=*/FuncTy_13,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_initialize_type_from_code", mod);  // (external, no body)
-func_art_portable_initialize_type_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_initialize_type_from_code_PAL;
-func_art_portable_initialize_type_from_code->setAttributes(func_art_portable_initialize_type_from_code_PAL);
-
-Function* func_art_portable_initialize_type_and_verify_access_from_code = mod->getFunction("art_portable_initialize_type_and_verify_access_from_code");
-if (!func_art_portable_initialize_type_and_verify_access_from_code) {
-func_art_portable_initialize_type_and_verify_access_from_code = Function::Create(
- /*Type=*/FuncTy_13,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_initialize_type_and_verify_access_from_code", mod);  // (external, no body)
-func_art_portable_initialize_type_and_verify_access_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_initialize_type_and_verify_access_from_code_PAL;
-func_art_portable_initialize_type_and_verify_access_from_code->setAttributes(func_art_portable_initialize_type_and_verify_access_from_code_PAL);
-
-Function* func_art_portable_resolve_string_from_code = mod->getFunction("art_portable_resolve_string_from_code");
-if (!func_art_portable_resolve_string_from_code) {
-func_art_portable_resolve_string_from_code = Function::Create(
- /*Type=*/FuncTy_17,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_resolve_string_from_code", mod);  // (external, no body)
-func_art_portable_resolve_string_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_resolve_string_from_code_PAL;
-func_art_portable_resolve_string_from_code->setAttributes(func_art_portable_resolve_string_from_code_PAL);
-
-Function* func_art_portable_set32_static_from_code = mod->getFunction("art_portable_set32_static_from_code");
-if (!func_art_portable_set32_static_from_code) {
-func_art_portable_set32_static_from_code = Function::Create(
- /*Type=*/FuncTy_18,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set32_static_from_code", mod);  // (external, no body)
-func_art_portable_set32_static_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set32_static_from_code_PAL;
-func_art_portable_set32_static_from_code->setAttributes(func_art_portable_set32_static_from_code_PAL);
-
-Function* func_art_portable_set64_static_from_code = mod->getFunction("art_portable_set64_static_from_code");
-if (!func_art_portable_set64_static_from_code) {
-func_art_portable_set64_static_from_code = Function::Create(
- /*Type=*/FuncTy_19,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set64_static_from_code", mod);  // (external, no body)
-func_art_portable_set64_static_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set64_static_from_code_PAL;
-func_art_portable_set64_static_from_code->setAttributes(func_art_portable_set64_static_from_code_PAL);
-
-Function* func_art_portable_set_obj_static_from_code = mod->getFunction("art_portable_set_obj_static_from_code");
-if (!func_art_portable_set_obj_static_from_code) {
-func_art_portable_set_obj_static_from_code = Function::Create(
- /*Type=*/FuncTy_20,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set_obj_static_from_code", mod);  // (external, no body)
-func_art_portable_set_obj_static_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set_obj_static_from_code_PAL;
-func_art_portable_set_obj_static_from_code->setAttributes(func_art_portable_set_obj_static_from_code_PAL);
-
-Function* func_art_portable_get32_static_from_code = mod->getFunction("art_portable_get32_static_from_code");
-if (!func_art_portable_get32_static_from_code) {
-func_art_portable_get32_static_from_code = Function::Create(
- /*Type=*/FuncTy_21,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get32_static_from_code", mod);  // (external, no body)
-func_art_portable_get32_static_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get32_static_from_code_PAL;
-func_art_portable_get32_static_from_code->setAttributes(func_art_portable_get32_static_from_code_PAL);
-
-Function* func_art_portable_get64_static_from_code = mod->getFunction("art_portable_get64_static_from_code");
-if (!func_art_portable_get64_static_from_code) {
-func_art_portable_get64_static_from_code = Function::Create(
- /*Type=*/FuncTy_22,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get64_static_from_code", mod);  // (external, no body)
-func_art_portable_get64_static_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get64_static_from_code_PAL;
-func_art_portable_get64_static_from_code->setAttributes(func_art_portable_get64_static_from_code_PAL);
-
-Function* func_art_portable_get_obj_static_from_code = mod->getFunction("art_portable_get_obj_static_from_code");
-if (!func_art_portable_get_obj_static_from_code) {
-func_art_portable_get_obj_static_from_code = Function::Create(
- /*Type=*/FuncTy_23,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get_obj_static_from_code", mod);  // (external, no body)
-func_art_portable_get_obj_static_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get_obj_static_from_code_PAL;
-func_art_portable_get_obj_static_from_code->setAttributes(func_art_portable_get_obj_static_from_code_PAL);
-
-Function* func_art_portable_set32_instance_from_code = mod->getFunction("art_portable_set32_instance_from_code");
-if (!func_art_portable_set32_instance_from_code) {
-func_art_portable_set32_instance_from_code = Function::Create(
- /*Type=*/FuncTy_24,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set32_instance_from_code", mod);  // (external, no body)
-func_art_portable_set32_instance_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set32_instance_from_code_PAL;
-func_art_portable_set32_instance_from_code->setAttributes(func_art_portable_set32_instance_from_code_PAL);
-
-Function* func_art_portable_set64_instance_from_code = mod->getFunction("art_portable_set64_instance_from_code");
-if (!func_art_portable_set64_instance_from_code) {
-func_art_portable_set64_instance_from_code = Function::Create(
- /*Type=*/FuncTy_25,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set64_instance_from_code", mod);  // (external, no body)
-func_art_portable_set64_instance_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set64_instance_from_code_PAL;
-func_art_portable_set64_instance_from_code->setAttributes(func_art_portable_set64_instance_from_code_PAL);
-
-Function* func_art_portable_set_obj_instance_from_code = mod->getFunction("art_portable_set_obj_instance_from_code");
-if (!func_art_portable_set_obj_instance_from_code) {
-func_art_portable_set_obj_instance_from_code = Function::Create(
- /*Type=*/FuncTy_26,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_set_obj_instance_from_code", mod);  // (external, no body)
-func_art_portable_set_obj_instance_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_set_obj_instance_from_code_PAL;
-func_art_portable_set_obj_instance_from_code->setAttributes(func_art_portable_set_obj_instance_from_code_PAL);
-
-Function* func_art_portable_get32_instance_from_code = mod->getFunction("art_portable_get32_instance_from_code");
-if (!func_art_portable_get32_instance_from_code) {
-func_art_portable_get32_instance_from_code = Function::Create(
- /*Type=*/FuncTy_20,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get32_instance_from_code", mod);  // (external, no body)
-func_art_portable_get32_instance_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get32_instance_from_code_PAL;
-func_art_portable_get32_instance_from_code->setAttributes(func_art_portable_get32_instance_from_code_PAL);
-
-Function* func_art_portable_get64_instance_from_code = mod->getFunction("art_portable_get64_instance_from_code");
-if (!func_art_portable_get64_instance_from_code) {
-func_art_portable_get64_instance_from_code = Function::Create(
- /*Type=*/FuncTy_27,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get64_instance_from_code", mod);  // (external, no body)
-func_art_portable_get64_instance_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get64_instance_from_code_PAL;
-func_art_portable_get64_instance_from_code->setAttributes(func_art_portable_get64_instance_from_code_PAL);
-
-Function* func_art_portable_get_obj_instance_from_code = mod->getFunction("art_portable_get_obj_instance_from_code");
-if (!func_art_portable_get_obj_instance_from_code) {
-func_art_portable_get_obj_instance_from_code = Function::Create(
- /*Type=*/FuncTy_13,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_get_obj_instance_from_code", mod);  // (external, no body)
-func_art_portable_get_obj_instance_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_get_obj_instance_from_code_PAL;
-func_art_portable_get_obj_instance_from_code->setAttributes(func_art_portable_get_obj_instance_from_code_PAL);
-
-Function* func_art_portable_decode_jobject_in_thread = mod->getFunction("art_portable_decode_jobject_in_thread");
-if (!func_art_portable_decode_jobject_in_thread) {
-func_art_portable_decode_jobject_in_thread = Function::Create(
- /*Type=*/FuncTy_28,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_decode_jobject_in_thread", mod);  // (external, no body)
-func_art_portable_decode_jobject_in_thread->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_decode_jobject_in_thread_PAL;
-func_art_portable_decode_jobject_in_thread->setAttributes(func_art_portable_decode_jobject_in_thread_PAL);
-
-Function* func_art_portable_fill_array_data_from_code = mod->getFunction("art_portable_fill_array_data_from_code");
-if (!func_art_portable_fill_array_data_from_code) {
-func_art_portable_fill_array_data_from_code = Function::Create(
- /*Type=*/FuncTy_29,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_fill_array_data_from_code", mod);  // (external, no body)
-func_art_portable_fill_array_data_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_fill_array_data_from_code_PAL;
-func_art_portable_fill_array_data_from_code->setAttributes(func_art_portable_fill_array_data_from_code_PAL);
-
-Function* func_art_portable_is_assignable_from_code = mod->getFunction("art_portable_is_assignable_from_code");
-if (!func_art_portable_is_assignable_from_code) {
-func_art_portable_is_assignable_from_code = Function::Create(
- /*Type=*/FuncTy_30,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_is_assignable_from_code", mod);  // (external, no body)
-func_art_portable_is_assignable_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_is_assignable_from_code_PAL;
-func_art_portable_is_assignable_from_code->setAttributes(func_art_portable_is_assignable_from_code_PAL);
-
-Function* func_art_portable_check_cast_from_code = mod->getFunction("art_portable_check_cast_from_code");
-if (!func_art_portable_check_cast_from_code) {
-func_art_portable_check_cast_from_code = Function::Create(
- /*Type=*/FuncTy_5,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_check_cast_from_code", mod);  // (external, no body)
-func_art_portable_check_cast_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_check_cast_from_code_PAL;
-func_art_portable_check_cast_from_code->setAttributes(func_art_portable_check_cast_from_code_PAL);
-
-Function* func_art_portable_check_put_array_element_from_code = mod->getFunction("art_portable_check_put_array_element_from_code");
-if (!func_art_portable_check_put_array_element_from_code) {
-func_art_portable_check_put_array_element_from_code = Function::Create(
- /*Type=*/FuncTy_5,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_check_put_array_element_from_code", mod);  // (external, no body)
-func_art_portable_check_put_array_element_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_check_put_array_element_from_code_PAL;
-func_art_portable_check_put_array_element_from_code->setAttributes(func_art_portable_check_put_array_element_from_code_PAL);
-
-Function* func_art_d2l = mod->getFunction("art_d2l");
-if (!func_art_d2l) {
-func_art_d2l = Function::Create(
- /*Type=*/FuncTy_31,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_d2l", mod);  // (external, no body)
-func_art_d2l->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_d2l_PAL;
-func_art_d2l->setAttributes(func_art_d2l_PAL);
-
-Function* func_art_d2i = mod->getFunction("art_d2i");
-if (!func_art_d2i) {
-func_art_d2i = Function::Create(
- /*Type=*/FuncTy_32,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_d2i", mod);  // (external, no body)
-func_art_d2i->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_d2i_PAL;
-func_art_d2i->setAttributes(func_art_d2i_PAL);
-
-Function* func_art_f2l = mod->getFunction("art_f2l");
-if (!func_art_f2l) {
-func_art_f2l = Function::Create(
- /*Type=*/FuncTy_33,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_f2l", mod);  // (external, no body)
-func_art_f2l->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_f2l_PAL;
-func_art_f2l->setAttributes(func_art_f2l_PAL);
-
-Function* func_art_f2i = mod->getFunction("art_f2i");
-if (!func_art_f2i) {
-func_art_f2i = Function::Create(
- /*Type=*/FuncTy_34,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_f2i", mod);  // (external, no body)
-func_art_f2i->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_f2i_PAL;
-func_art_f2i->setAttributes(func_art_f2i_PAL);
-
-Function* func_art_portable_jni_method_start = mod->getFunction("art_portable_jni_method_start");
-if (!func_art_portable_jni_method_start) {
-func_art_portable_jni_method_start = Function::Create(
- /*Type=*/FuncTy_35,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_jni_method_start", mod);  // (external, no body)
-func_art_portable_jni_method_start->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_jni_method_start_PAL;
-func_art_portable_jni_method_start->setAttributes(func_art_portable_jni_method_start_PAL);
-
-Function* func_art_portable_jni_method_start_synchronized = mod->getFunction("art_portable_jni_method_start_synchronized");
-if (!func_art_portable_jni_method_start_synchronized) {
-func_art_portable_jni_method_start_synchronized = Function::Create(
- /*Type=*/FuncTy_30,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_jni_method_start_synchronized", mod);  // (external, no body)
-func_art_portable_jni_method_start_synchronized->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_jni_method_start_synchronized_PAL;
-func_art_portable_jni_method_start_synchronized->setAttributes(func_art_portable_jni_method_start_synchronized_PAL);
-
-Function* func_art_portable_jni_method_end = mod->getFunction("art_portable_jni_method_end");
-if (!func_art_portable_jni_method_end) {
-func_art_portable_jni_method_end = Function::Create(
- /*Type=*/FuncTy_15,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_jni_method_end", mod);  // (external, no body)
-func_art_portable_jni_method_end->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_jni_method_end_PAL;
-func_art_portable_jni_method_end->setAttributes(func_art_portable_jni_method_end_PAL);
-
-Function* func_art_portable_jni_method_end_synchronized = mod->getFunction("art_portable_jni_method_end_synchronized");
-if (!func_art_portable_jni_method_end_synchronized) {
-func_art_portable_jni_method_end_synchronized = Function::Create(
- /*Type=*/FuncTy_36,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_jni_method_end_synchronized", mod);  // (external, no body)
-func_art_portable_jni_method_end_synchronized->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_jni_method_end_synchronized_PAL;
-func_art_portable_jni_method_end_synchronized->setAttributes(func_art_portable_jni_method_end_synchronized_PAL);
-
-Function* func_art_portable_jni_method_end_with_reference = mod->getFunction("art_portable_jni_method_end_with_reference");
-if (!func_art_portable_jni_method_end_with_reference) {
-func_art_portable_jni_method_end_with_reference = Function::Create(
- /*Type=*/FuncTy_37,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_jni_method_end_with_reference", mod);  // (external, no body)
-func_art_portable_jni_method_end_with_reference->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_jni_method_end_with_reference_PAL;
-func_art_portable_jni_method_end_with_reference->setAttributes(func_art_portable_jni_method_end_with_reference_PAL);
-
-Function* func_art_portable_jni_method_end_with_reference_synchronized = mod->getFunction("art_portable_jni_method_end_with_reference_synchronized");
-if (!func_art_portable_jni_method_end_with_reference_synchronized) {
-func_art_portable_jni_method_end_with_reference_synchronized = Function::Create(
- /*Type=*/FuncTy_38,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_jni_method_end_with_reference_synchronized", mod);  // (external, no body)
-func_art_portable_jni_method_end_with_reference_synchronized->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_jni_method_end_with_reference_synchronized_PAL;
-func_art_portable_jni_method_end_with_reference_synchronized->setAttributes(func_art_portable_jni_method_end_with_reference_synchronized_PAL);
-
-Function* func_art_portable_is_exception_pending_from_code = mod->getFunction("art_portable_is_exception_pending_from_code");
-if (!func_art_portable_is_exception_pending_from_code) {
-func_art_portable_is_exception_pending_from_code = Function::Create(
- /*Type=*/FuncTy_39,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_is_exception_pending_from_code", mod);  // (external, no body)
-func_art_portable_is_exception_pending_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_is_exception_pending_from_code_PAL;
-func_art_portable_is_exception_pending_from_code->setAttributes(func_art_portable_is_exception_pending_from_code_PAL);
-
-Function* func_art_portable_mark_gc_card_from_code = mod->getFunction("art_portable_mark_gc_card_from_code");
-if (!func_art_portable_mark_gc_card_from_code) {
-func_art_portable_mark_gc_card_from_code = Function::Create(
- /*Type=*/FuncTy_5,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_mark_gc_card_from_code", mod);  // (external, no body)
-func_art_portable_mark_gc_card_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_mark_gc_card_from_code_PAL;
-func_art_portable_mark_gc_card_from_code->setAttributes(func_art_portable_mark_gc_card_from_code_PAL);
-
-Function* func_art_portable_proxy_invoke_handler_from_code = mod->getFunction("art_portable_proxy_invoke_handler_from_code");
-if (!func_art_portable_proxy_invoke_handler_from_code) {
-func_art_portable_proxy_invoke_handler_from_code = Function::Create(
- /*Type=*/FuncTy_40,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_portable_proxy_invoke_handler_from_code", mod);  // (external, no body)
-func_art_portable_proxy_invoke_handler_from_code->setCallingConv(CallingConv::C);
-}
-AttributeSet func_art_portable_proxy_invoke_handler_from_code_PAL;
-func_art_portable_proxy_invoke_handler_from_code->setAttributes(func_art_portable_proxy_invoke_handler_from_code_PAL);
-
-// Global Variable Declarations
-
-
-// Constant Definitions
-
-// Global Variable Definitions
-
-// Function Definitions
-
-return mod;
-
-}
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/intrinsic_func_list.def b/compiler/llvm/intrinsic_func_list.def
deleted file mode 100644
index 887a626..0000000
--- a/compiler/llvm/intrinsic_func_list.def
+++ /dev/null
@@ -1,1796 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE,
-//                     ARG1_TYPE, ARG2_TYPE, ARG3_TYPE, ARG4_TYPE, ARG5_TYPE)
-#ifndef DEF_INTRINSICS_FUNC
-#  error "missing DEF_INTRINSICS_FUNC definition!"
-#endif
-
-#define _EVAL_DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, ...) \
-    DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, __VA_ARGS__)
-
-#define _EXPAND_ARG0()                         kNone, kNone, kNone, kNone, kNone
-#define _EXPAND_ARG1(ARG1)                      ARG1, kNone, kNone, kNone, kNone
-#define _EXPAND_ARG2(ARG1, ARG2)                ARG1,  ARG2, kNone, kNone, kNone
-#define _EXPAND_ARG3(ARG1, ARG2, ARG3)          ARG1,  ARG2,  ARG3, kNone, kNone
-#define _EXPAND_ARG4(ARG1, ARG2, ARG3, ARG4)    ARG1,  ARG2,  ARG3,  ARG4, kNone
-#define _EXPAND_ARG5(ARG1, ARG2, ARG3, ARG4, ARG5) \
-                                                ARG1,  ARG2,  ARG3,  ARG4,  ARG5
-
-#define _JTYPE(TYPE, SPACE) _JTYPE_OF_ ## TYPE ## _UNDER_ ## SPACE
-
-// Note: These should be consistent with the type return from
-// IRBuilder::GetJType([type], kArray).
-#define _JTYPE_OF_kInt1Ty_UNDER_kArray        kInt8Ty
-#define _JTYPE_OF_kInt8Ty_UNDER_kArray        kInt8Ty
-#define _JTYPE_OF_kInt16Ty_UNDER_kArray       kInt16Ty
-#define _JTYPE_OF_kInt32Ty_UNDER_kArray       kInt32Ty
-#define _JTYPE_OF_kInt64Ty_UNDER_kArray       kInt64Ty
-#define _JTYPE_OF_kJavaObjectTy_UNDER_kArray  kJavaObjectTy
-
-// Note: These should be consistent with the type return from
-// IRBuilder::GetJType([type], kField).
-#define _JTYPE_OF_kInt1Ty_UNDER_kField        kInt32Ty
-#define _JTYPE_OF_kInt8Ty_UNDER_kField        kInt32Ty
-#define _JTYPE_OF_kInt16Ty_UNDER_kField       kInt32Ty
-#define _JTYPE_OF_kInt32Ty_UNDER_kField       kInt32Ty
-#define _JTYPE_OF_kInt64Ty_UNDER_kField       kInt64Ty
-#define _JTYPE_OF_kJavaObjectTy_UNDER_kField  kJavaObjectTy
-
-//----------------------------------------------------------------------------
-// Thread
-//----------------------------------------------------------------------------
-
-// Thread* art_portable_get_current_thread()
-_EVAL_DEF_INTRINSICS_FUNC(GetCurrentThread,
-                          art_portable_get_current_thread,
-                          kAttrReadNone | kAttrNoThrow,
-                          kJavaThreadTy,
-                          _EXPAND_ARG0())
-
-// void art_portable_test_suspend(Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(TestSuspend,
-                          art_portable_test_suspend,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG1(kJavaThreadTy))
-
-// void art_portable_check_suspend() /* Expands to GetCurrentThread/TestSuspend */
-_EVAL_DEF_INTRINSICS_FUNC(CheckSuspend,
-                          art_portable_check_suspend,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG0())
-
-// void art_portable_mark_gc_card(Object* new_value, Object* object)
-_EVAL_DEF_INTRINSICS_FUNC(MarkGCCard,
-                          art_portable_mark_gc_card,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
-
-//----------------------------------------------------------------------------
-// Exception
-//----------------------------------------------------------------------------
-
-// Should not expand - introduces the catch targets for a potentially
-// throwing instruction.  The result is a switch key and this
-// instruction will be followed by a switch statement.  The catch
-// targets will be enumerated as cases of the switch, with the fallthrough
-// designating the block containing the potentially throwing instruction.
-// bool art_portable_catch_targets(int dex_pc)
-_EVAL_DEF_INTRINSICS_FUNC(CatchTargets,
-                          art_portable_catch_targets,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// void art_portable_throw_exception(JavaObject* exception)
-_EVAL_DEF_INTRINSICS_FUNC(ThrowException,
-                          art_portable_throw_exception,
-                          kAttrDoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG1(kJavaObjectTy))
-
-// void art_portable_hl_throw_exception(JavaObject* exception)
-_EVAL_DEF_INTRINSICS_FUNC(HLThrowException,
-                          art_portable_hl_throw_exception,
-                          kAttrDoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG1(kJavaObjectTy))
-
-// JavaObject* art_portable_get_current_exception()
-_EVAL_DEF_INTRINSICS_FUNC(GetException,
-                          art_portable_get_current_exception,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG0())
-
-// bool art_portable_is_exception_pending()
-_EVAL_DEF_INTRINSICS_FUNC(IsExceptionPending,
-                          art_portable_is_exception_pending,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt1Ty,
-                          _EXPAND_ARG0())
-
-// int art_portable_find_catch_block(Method* method, int try_item_offset)
-_EVAL_DEF_INTRINSICS_FUNC(FindCatchBlock,
-                          art_portable_find_catch_block,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy))
-
-// void art_portable_throw_div_zero()
-_EVAL_DEF_INTRINSICS_FUNC(ThrowDivZeroException,
-                          art_portable_throw_div_zero,
-                          kAttrDoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG0())
-
-// void art_portable_throw_null_pointer_exception(uint32_t dex_pc)
-_EVAL_DEF_INTRINSICS_FUNC(ThrowNullPointerException,
-                          art_portable_throw_null_pointer_exception,
-                          kAttrDoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// void art_portable_throw_array_bounds(int index, int array_len)
-_EVAL_DEF_INTRINSICS_FUNC(ThrowIndexOutOfBounds,
-                          art_portable_throw_array_bounds,
-                          kAttrDoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-//----------------------------------------------------------------------------
-// ConstString
-//----------------------------------------------------------------------------
-
-// JavaObject* art_portable_const_string(uint32_t string_idx)
-_EVAL_DEF_INTRINSICS_FUNC(ConstString,
-                          art_portable_const_string,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// JavaObject* art_portable_load_string_from_dex_cache(Method* method, uint32_t string_idx)
-_EVAL_DEF_INTRINSICS_FUNC(LoadStringFromDexCache,
-                          art_portable_load_string_from_dex_cache,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// JavaObject* art_portable_resolve_string(Method* method, uint32_t string_idx)
-_EVAL_DEF_INTRINSICS_FUNC(ResolveString,
-                          art_portable_resolve_string,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy))
-
-//----------------------------------------------------------------------------
-// ConstClass
-//----------------------------------------------------------------------------
-
-// JavaObject* art_portable_const_class(uint32_t type_idx)
-_EVAL_DEF_INTRINSICS_FUNC(ConstClass,
-                          art_portable_const_class,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// JavaObject* art_portable_initialize_type_and_verify_access(uint32_t type_idx,
-//                                                        Method* referrer,
-//                                                        Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(InitializeTypeAndVerifyAccess,
-                          art_portable_initialize_type_and_verify_access,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
-
-// JavaObject* art_portable_load_type_from_dex_cache(uint32_t type_idx)
-_EVAL_DEF_INTRINSICS_FUNC(LoadTypeFromDexCache,
-                          art_portable_load_type_from_dex_cache,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// JavaObject* art_portable_initialize_type(uint32_t type_idx,
-//                                      Method* referrer,
-//                                      Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(InitializeType,
-                          art_portable_initialize_type,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
-
-//----------------------------------------------------------------------------
-// Lock
-//----------------------------------------------------------------------------
-
-// void art_portable_lock_object(JavaObject* obj, Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(LockObject,
-                          art_portable_lock_object,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy))
-
-// void art_portable_unlock_object(JavaObject* obj, Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(UnlockObject,
-                          art_portable_unlock_object,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy))
-
-//----------------------------------------------------------------------------
-// Cast
-//----------------------------------------------------------------------------
-
-// void art_portable_check_cast(JavaObject* dest_type, JavaObject* src_type)
-_EVAL_DEF_INTRINSICS_FUNC(CheckCast,
-                          art_portable_check_cast,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
-
-// void art_portable_hl_check_cast(uint32_t type_idx, JavaObject* obj)
-_EVAL_DEF_INTRINSICS_FUNC(HLCheckCast,
-                          art_portable_hl_check_cast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
-
-// int art_portable_is_assignable(JavaObject* dest_type, JavaObject* src_type)
-_EVAL_DEF_INTRINSICS_FUNC(IsAssignable,
-                          art_portable_is_assignable,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
-
-//----------------------------------------------------------------------------
-// Allocation
-//----------------------------------------------------------------------------
-
-// JavaObject* art_portable_alloc_object(uint32_t type_idx,
-//                                   Method* referrer,
-//                                   Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(AllocObject,
-                          art_portable_alloc_object,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
-
-// JavaObject* art_portable_alloc_object_with_access_check(uint32_t type_idx,
-//                                                     Method* referrer,
-//                                                     Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(AllocObjectWithAccessCheck,
-                          art_portable_alloc_object_with_access_check,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
-
-//----------------------------------------------------------------------------
-// Instance
-//----------------------------------------------------------------------------
-
-// JavaObject* art_portable_new_instance(uint32_t type_idx)
-_EVAL_DEF_INTRINSICS_FUNC(NewInstance,
-                          art_portable_new_instance,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// bool art_portable_instance_of(uint32_t type_idx, JavaObject* ref)
-_EVAL_DEF_INTRINSICS_FUNC(InstanceOf,
-                          art_portable_instance_of,
-                          kAttrNone,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
-
-//----------------------------------------------------------------------------
-// Array
-//----------------------------------------------------------------------------
-
-// JavaObject* art_portable_new_array(uint32_t type_idx, uint32_t array_size)
-_EVAL_DEF_INTRINSICS_FUNC(NewArray,
-                          art_portable_new_array,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG2(kInt32ConstantTy, kInt32Ty))
-
-// uint32_t art_portable_opt_array_length(int32_t opt_flags, JavaObject* array)
-_EVAL_DEF_INTRINSICS_FUNC(OptArrayLength,
-                          art_portable_opt_array_length,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
-
-// uint32_t art_portable_array_length(JavaObject* array)
-_EVAL_DEF_INTRINSICS_FUNC(ArrayLength,
-                          art_portable_array_length,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kJavaObjectTy))
-
-// JavaObject* art_portable_alloc_array(uint32_t type_idx,
-//                                  Method* referrer,
-//                                  uint32_t length,
-//                                  Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(AllocArray,
-                          art_portable_alloc_array,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy))
-
-// JavaObject* art_portable_alloc_array_with_access_check(uint32_t type_idx,
-//                                                    Method* referrer,
-//                                                    uint32_t length,
-//                                                    Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(AllocArrayWithAccessCheck,
-                          art_portable_alloc_array_with_access_check,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy))
-
-// JavaObject* art_portable_check_and_alloc_array(uint32_t type_idx,
-//                                            Method* referrer,
-//                                            uint32_t length,
-//                                            Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArray,
-                          art_portable_check_and_alloc_array,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy))
-
-// JavaObject* art_portable_check_and_alloc_array_with_access_check(uint32_t type_idx,
-//                                                              Method* referrer,
-//                                                              uint32_t length,
-//                                                              Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArrayWithAccessCheck,
-                          art_portable_check_and_alloc_array_with_access_check,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy))
-
-// art_portable_aget_* and art_portable_aput_* never generate exception since the
-// necessary checking on arguments (e.g., array and index) has already done
-// before invocation of these intrinsics.
-//
-// [type] void art_portable_aget_[type](JavaObject* array, uint32_t index)
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGet,
-                          art_portable_aget,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt32Ty, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGetWide,
-                          art_portable_aget_wide,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt64Ty, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGetObject,
-                          art_portable_aget_object,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kJavaObjectTy, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGetBoolean,
-                          art_portable_aget_boolean,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt1Ty, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGetByte,
-                          art_portable_aget_byte,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt8Ty, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGetChar,
-                          art_portable_aget_char,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt16Ty, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayGetShort,
-                          art_portable_aget_short,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt16Ty, kArray),
-                          _EXPAND_ARG2(kJavaObjectTy, kInt32Ty))
-
-// void art_portable_aput_[type]([type] value, JavaObject* array, uint32_t index)
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPut,
-                          art_portable_aput,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kInt32Ty, kArray), kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPutWide,
-                          art_portable_aput_wide,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kInt64Ty, kArray), kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPutObject,
-                          art_portable_aput_object,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kJavaObjectTy, kArray), kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPutBoolean,
-                          art_portable_aput_boolean,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kInt1Ty, kArray), kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPutByte,
-                          art_portable_aput_byte,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kInt8Ty, kArray), kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPutChar,
-                          art_portable_aput_char,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kInt16Ty, kArray), kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(ArrayPutShort,
-                          art_portable_aput_short,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(_JTYPE(kInt16Ty, kArray), kJavaObjectTy, kInt32Ty))
-
-// void art_portable_check_put_array_element(JavaObject* value, JavaObject* array)
-_EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement,
-                          art_portable_check_put_array_element,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy))
-
-// void art_portable_filled_new_array(Array* array,
-//                                uint32_t elem_jty, ...)
-_EVAL_DEF_INTRINSICS_FUNC(FilledNewArray,
-                          art_portable_filled_new_array,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kVarArgTy))
-
-// void art_portable_fill_array_data(Method* referrer,
-//                               uint32_t dex_pc,
-//                               Array* array,
-//                               uint32_t payload_offset)
-_EVAL_DEF_INTRINSICS_FUNC(FillArrayData,
-                          art_portable_fill_array_data,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaMethodTy, kInt32ConstantTy, kJavaObjectTy, kInt32ConstantTy))
-
-// void art_portable_hl_fill_array_data(int32_t offset, JavaObject* array)
-_EVAL_DEF_INTRINSICS_FUNC(HLFillArrayData,
-                          art_portable_hl_fill_array_data,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
-
-//----------------------------------------------------------------------------
-// Instance Field
-//----------------------------------------------------------------------------
-
-// [type] art_portable_iget_[type](uint32_t field_idx,
-//                             Method* referrer,
-//                             JavaObject* obj)
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGet,
-                          art_portable_iget,
-                          kAttrNone,
-                          _JTYPE(kInt32Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWide,
-                          art_portable_iget_wide,
-                          kAttrNone,
-                          _JTYPE(kInt64Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObject,
-                          art_portable_iget_object,
-                          kAttrNone,
-                          _JTYPE(kJavaObjectTy, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBoolean,
-                          art_portable_iget_boolean,
-                          kAttrNone,
-                          _JTYPE(kInt1Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByte,
-                          art_portable_iget_byte,
-                          kAttrNone,
-                          _JTYPE(kInt8Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetChar,
-                          art_portable_iget_char,
-                          kAttrNone,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShort,
-                          art_portable_iget_short,
-                          kAttrNone,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy))
-
-// [type] art_portable_iget_[type].fast(int field_offset,
-//                                  bool is_volatile,
-//                                  JavaObject* obj)
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetFast,
-                          art_portable_iget.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt32Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWideFast,
-                          art_portable_iget_wide.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt64Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObjectFast,
-                          art_portable_iget_object.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kJavaObjectTy, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBooleanFast,
-                          art_portable_iget_boolean.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt1Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByteFast,
-                          art_portable_iget_byte.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt8Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetCharFast,
-                          art_portable_iget_char.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShortFast,
-                          art_portable_iget_short.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy))
-
-// void art_portable_iput_[type](uint32_t field_idx,
-//                           Method* referrer,
-//                           JavaObject* obj,
-//                           [type] new_value)
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPut,
-                          art_portable_iput,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWide,
-                          art_portable_iput_wide,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObject,
-                          art_portable_iput_object,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBoolean,
-                          art_portable_iput_boolean,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByte,
-                          art_portable_iput_byte,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutChar,
-                          art_portable_iput_char,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShort,
-                          art_portable_iput_short,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
-
-// void art_portable_iput_[type].fast(int field_offset,
-//                                bool is_volatile,
-//                                JavaObject* obj,
-//                                [type] new_value)
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutFast,
-                          art_portable_iput.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWideFast,
-                          art_portable_iput_wide.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObjectFast,
-                          art_portable_iput_object.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBooleanFast,
-                          art_portable_iput_boolean.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByteFast,
-                          art_portable_iput_byte.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutCharFast,
-                          art_portable_iput_char.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShortFast,
-                          art_portable_iput_short.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField)))
-
-//----------------------------------------------------------------------------
-// Static Field
-//----------------------------------------------------------------------------
-
-// [type] art_portable_sget_[type](uint32_t field_idx, Method* referrer)
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGet,
-                          art_portable_sget,
-                          kAttrNone,
-                          _JTYPE(kInt32Ty, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWide,
-                          art_portable_sget_wide,
-                          kAttrNone,
-                          _JTYPE(kInt64Ty, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObject,
-                          art_portable_sget_object,
-                          kAttrNone,
-                          _JTYPE(kJavaObjectTy, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBoolean,
-                          art_portable_sget_boolean,
-                          kAttrNone,
-                          _JTYPE(kInt1Ty, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByte,
-                          art_portable_sget_byte,
-                          kAttrNone,
-                          _JTYPE(kInt8Ty, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetChar,
-                          art_portable_sget_char,
-                          kAttrNone,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShort,
-                          art_portable_sget_short,
-                          kAttrNone,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy))
-
-// [type] art_portable_sget_[type].fast(JavaObject* ssb,
-//                                  int field_offset,
-//                                  bool is_volatile)
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetFast,
-                          art_portable_sget.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt32Ty, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWideFast,
-                          art_portable_sget_wide.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt64Ty, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObjectFast,
-                          art_portable_sget_object.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kJavaObjectTy, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBooleanFast,
-                          art_portable_sget_boolean.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt1Ty, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByteFast,
-                          art_portable_sget_byte.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt8Ty, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetCharFast,
-                          art_portable_sget_char.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShortFast,
-                          art_portable_sget_short.fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          _JTYPE(kInt16Ty, kField),
-                          _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy))
-
-// void art_portable_sput_[type](uint32_t field_idx,
-//                           Method* referrer,
-//                           [type] new_value)
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPut,
-                          art_portable_sput,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt32Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutWide,
-                          art_portable_sput_wide,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt64Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutObject,
-                          art_portable_sput_object,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kJavaObjectTy, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutBoolean,
-                          art_portable_sput_boolean,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt1Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutByte,
-                          art_portable_sput_byte,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt8Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutChar,
-                          art_portable_sput_char,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt16Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutShort,
-                          art_portable_sput_short,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt16Ty, kField)))
-
-// void art_portable_sput_[type].fast(JavaObject* ssb,
-//                                int field_offset,
-//                                bool is_volatile,
-//                                [type] new_value)
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutFast,
-                          art_portable_sput.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt32Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutWideFast,
-                          art_portable_sput_wide.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt64Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutObjectFast,
-                          art_portable_sput_object.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kJavaObjectTy, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutBooleanFast,
-                          art_portable_sput_boolean.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt1Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutByteFast,
-                          art_portable_sput_byte.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt8Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutCharFast,
-                          art_portable_sput_char.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt16Ty, kField)))
-
-_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutShortFast,
-                          art_portable_sput_short.fast,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt16Ty, kField)))
-
-// JavaObject* art_portable_load_declaring_class_ssb(Method* method)
-// Load the static storage base of the class that given method resides
-_EVAL_DEF_INTRINSICS_FUNC(LoadDeclaringClassSSB,
-                          art_portable_load_declaring_class_ssb,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kJavaMethodTy))
-
-// JavaObject* art_portable_init_and_load_class_ssb(uint32_t type_idx,
-//                                              Method* referrer,
-//                                              Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(InitializeAndLoadClassSSB,
-                          art_portable_init_and_load_class_ssb,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy))
-
-//----------------------------------------------------------------------------
-// High-level Array get/put
-//
-// Similar to art_portable_aget/aput_xxx, but checks not yet performed.
-// OptFlags contain info describing whether frontend has determined that
-// null check and/or array bounds check may be skipped.
-//
-// [type] void art_portable_hl_aget_[type](int optFlags, JavaObject* array, uint32_t index)
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGet,
-                          art_portable_hl_aget,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetFloat,
-                          art_portable_hl_aget_float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kFloatTy,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetWide,
-                          art_portable_hl_aget_wide,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetDouble,
-                          art_portable_hl_aget_double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kDoubleTy,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetObject,
-                          art_portable_hl_aget_object,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetBoolean,
-                          art_portable_hl_aget_boolean,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetByte,
-                          art_portable_hl_aget_byte,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetChar,
-                          art_portable_hl_aget_char,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetShort,
-                          art_portable_hl_aget_short,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-// void art_portable_aput_[type](int optFlags, [type] value, JavaObject* array, uint32_t index)
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPut,
-                          art_portable_hl_aput,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutFloat,
-                          art_portable_hl_aput_float,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kFloatTy, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutWide,
-                          art_portable_hl_aput_wide,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt64Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutDouble,
-                          art_portable_hl_aput_double,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kDoubleTy, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutObject,
-                          art_portable_hl_aput_object,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kJavaObjectTy, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutBoolean,
-                          art_portable_hl_aput_boolean,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutByte,
-                          art_portable_hl_aput_byte,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutChar,
-                          art_portable_hl_aput_char,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutShort,
-                          art_portable_hl_aput_short,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-//----------------------------------------------------------------------------
-// High-level Instance get/put
-//
-// Similar to art_portable_iget/iput_xxx, but checks not yet performed.
-// OptFlags contain info describing whether frontend has determined that
-// null check may be skipped.
-//
-// [type] void art_portable_hl_iget_[type](int optFlags, JavaObject* obj, uint32_t field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLIGet,
-                          art_portable_hl_iget,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetFloat,
-                          art_portable_hl_iget_float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kFloatTy,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetWide,
-                          art_portable_hl_iget_wide,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetDouble,
-                          art_portable_hl_iget_double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kDoubleTy,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetObject,
-                          art_portable_hl_iget_object,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetBoolean,
-                          art_portable_hl_iget_boolean,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetByte,
-                          art_portable_hl_iget_byte,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetChar,
-                          art_portable_hl_iget_char,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIGetShort,
-                          art_portable_hl_iget_short,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-// void art_portable_iput_[type](int optFlags, [type] value, JavaObject* obj, uint32_t field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLIPut,
-                          art_portable_hl_iput,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutFloat,
-                          art_portable_hl_iput_float,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kFloatTy, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutWide,
-                          art_portable_hl_iput_wide,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt64Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutDouble,
-                          art_portable_hl_iput_double,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kDoubleTy, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutObject,
-                          art_portable_hl_iput_object,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kJavaObjectTy, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutBoolean,
-                          art_portable_hl_iput_boolean,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutByte,
-                          art_portable_hl_iput_byte,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutChar,
-                          art_portable_hl_iput_char,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(HLIPutShort,
-                          art_portable_hl_iput_short,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty))
-
-//----------------------------------------------------------------------------
-// High-level Invokes (fast-path determination not yet performed)
-//
-// NOTE: We expect these intrinsics to be temporary.  Once calling conventions are
-//       fully merged, the unified front end will lower down to the
-//       InvokeRetxxx() intrinsics in the next section and these will be
-//       removed.
-//
-// arg0: InvokeType [ignored if FilledNewArray]
-// arg1: method_idx [ignored if FilledNewArray]
-// arg2: optimization_flags (primary to note whether null checking is needed)
-// [arg3..argN]: actual arguments
-//----------------------------------------------------------------------------
-// INVOKE method returns void
-_EVAL_DEF_INTRINSICS_FUNC(HLInvokeVoid,
-                          art_portable_hl_invoke.void,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG1(kVarArgTy))
-
-// INVOKE method returns object
-_EVAL_DEF_INTRINSICS_FUNC(HLInvokeObj,
-                          art_portable_hl_invoke.obj,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kVarArgTy))
-
-// INVOKE method returns int
-_EVAL_DEF_INTRINSICS_FUNC(HLInvokeInt,
-                          art_portable_hl_invoke.i32,
-                          kAttrNone,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kVarArgTy))
-
-// INVOKE method returns float
-_EVAL_DEF_INTRINSICS_FUNC(HLInvokeFloat,
-                          art_portable_hl_invoke.f32,
-                          kAttrNone,
-                          kFloatTy,
-                          _EXPAND_ARG1(kVarArgTy))
-
-// INVOKE method returns long
-_EVAL_DEF_INTRINSICS_FUNC(HLInvokeLong,
-                          art_portable_hl_invoke.i64,
-                          kAttrNone,
-                          kInt64Ty,
-                          _EXPAND_ARG1(kVarArgTy))
-
-// INVOKE method returns double
-_EVAL_DEF_INTRINSICS_FUNC(HLInvokeDouble,
-                          art_portable_hl_invoke.f64,
-                          kAttrNone,
-                          kDoubleTy,
-                          _EXPAND_ARG1(kVarArgTy))
-
-// FILLED_NEW_ARRAY returns object
-_EVAL_DEF_INTRINSICS_FUNC(HLFilledNewArray,
-                          art_portable_hl_filled_new_array,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kVarArgTy))
-
-//----------------------------------------------------------------------------
-// Invoke
-//----------------------------------------------------------------------------
-
-// Method* art_portable_find_static_method_with_access_check(uint32_t method_idx,
-//                                                       JavaObject* this,
-//                                                       Method* referrer,
-//                                                       Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(FindStaticMethodWithAccessCheck,
-                          art_portable_find_static_method_with_access_check,
-                          kAttrNone,
-                          kJavaMethodTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
-
-// Method* art_portable_find_direct_method_with_access_check(uint32_t method_idx,
-//                                                       JavaObject* this,
-//                                                       Method* referrer,
-//                                                       Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(FindDirectMethodWithAccessCheck,
-                          art_portable_find_direct_method_with_access_check,
-                          kAttrNone,
-                          kJavaMethodTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
-
-// Method* art_portable_find_virtual_method_with_access_check(uint32_t method_idx,
-//                                                        JavaObject* this,
-//                                                        Method* referrer,
-//                                                        Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(FindVirtualMethodWithAccessCheck,
-                          art_portable_find_virtual_method_with_access_check,
-                          kAttrNone,
-                          kJavaMethodTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
-
-// Method* art_portable_find_super_method_with_access_check(uint32_t method_idx,
-//                                                      JavaObject* this,
-//                                                      Method* referrer,
-//                                                      Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(FindSuperMethodWithAccessCheck,
-                          art_portable_find_super_method_with_access_check,
-                          kAttrNone,
-                          kJavaMethodTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
-
-// Method* art_portable_find_interface_method_with_access_check(uint32_t method_idx,
-//                                                          JavaObject* this,
-//                                                          Method* referrer,
-//                                                          Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(FindInterfaceMethodWithAccessCheck,
-                          art_portable_find_interface_method_with_access_check,
-                          kAttrNone,
-                          kJavaMethodTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
-
-// Method* art_portable_get_sd_callee_method_obj_addr(uint32_t method_idx)
-_EVAL_DEF_INTRINSICS_FUNC(GetSDCalleeMethodObjAddrFast,
-                          art_portable_get_sd_callee_method_obj_addr_fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaMethodTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// Method* art_portable_get_virtual_callee_method_obj_addr(uint32_t vtable_idx,
-//                                                     JavaObject* this)
-_EVAL_DEF_INTRINSICS_FUNC(GetVirtualCalleeMethodObjAddrFast,
-                          art_portable_get_virtual_callee_method_obj_addr_fast,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaMethodTy,
-                          _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy))
-
-// Method* art_portable_get_interface_callee_method_obj_addr(uint32_t method_idx,
-//                                                       JavaObject* this,
-//                                                       Method* referrer,
-//                                                       Thread* thread)
-_EVAL_DEF_INTRINSICS_FUNC(GetInterfaceCalleeMethodObjAddrFast,
-                          art_portable_get_interface_callee_method_obj_addr_fast,
-                          kAttrNone,
-                          kJavaMethodTy,
-                          _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy))
-
-// [type] art_portable_invoke.[type](Method* callee, ...)
-// INVOKE method returns void
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetVoid,
-                          art_portable_invoke.void,
-                          kAttrNone,
-                          kVoidTy,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type boolean
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetBoolean,
-                          art_portable_invoke.bool,
-                          kAttrNone,
-                          kInt1Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type byte
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetByte,
-                          art_portable_invoke.byte,
-                          kAttrNone,
-                          kInt8Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type char
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetChar,
-                          art_portable_invoke.char,
-                          kAttrNone,
-                          kInt16Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type short
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetShort,
-                          art_portable_invoke.short,
-                          kAttrNone,
-                          kInt16Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type int
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetInt,
-                          art_portable_invoke.int,
-                          kAttrNone,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type long
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetLong,
-                          art_portable_invoke.long,
-                          kAttrNone,
-                          kInt64Ty,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type float
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetFloat,
-                          art_portable_invoke.float,
-                          kAttrNone,
-                          kFloatTy,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type double
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetDouble,
-                          art_portable_invoke.double,
-                          kAttrNone,
-                          kDoubleTy,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-// INVOKE method returns the value of type "object"
-_EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject,
-                          art_portable_invoke.object,
-                          kAttrNone,
-                          kJavaObjectTy,
-                          _EXPAND_ARG2(kJavaMethodTy, kVarArgTy))
-
-//----------------------------------------------------------------------------
-// Math
-//----------------------------------------------------------------------------
-
-// int art_portable_{div,rem}_int(int a, int b)
-_EVAL_DEF_INTRINSICS_FUNC(DivInt,
-                          art_portable_div_int,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(RemInt,
-                          art_portable_rem_int,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-// long art_portable_{div,rem}_long(long a, long b)
-_EVAL_DEF_INTRINSICS_FUNC(DivLong,
-                          art_portable_div_long,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG2(kInt64Ty, kInt64Ty))
-
-_EVAL_DEF_INTRINSICS_FUNC(RemLong,
-                          art_portable_rem_long,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG2(kInt64Ty, kInt64Ty))
-
-// int64_t art_portable_d2l(double f)
-_EVAL_DEF_INTRINSICS_FUNC(D2L,
-                          art_portable_d2l,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG1(kDoubleTy))
-
-// int32_t art_portable_d2l(double f)
-_EVAL_DEF_INTRINSICS_FUNC(D2I,
-                          art_portable_d2i,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kDoubleTy))
-
-// int64_t art_portable_f2l(float f)
-_EVAL_DEF_INTRINSICS_FUNC(F2L,
-                          art_portable_f2l,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG1(kFloatTy))
-
-// int32_t art_portable_f2i(float f)
-_EVAL_DEF_INTRINSICS_FUNC(F2I,
-                          art_portable_f2i,
-                          kAttrReadNone | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kFloatTy))
-
-//----------------------------------------------------------------------------
-// sput intrinsics to assist MIR to Greenland_ir conversion.
-// "HL" versions - will be deprecated when fast/slow path handling done
-// in the common frontend.
-//----------------------------------------------------------------------------
-
-// void sput_hl(int field_idx, int val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSput,
-                          art_portable_hl_sput,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-// void sput_hl_object(int field_idx, object* val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputObject,
-                          art_portable_hl_sput_object,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
-
-// void sput_hl_boolean(int field_idx, kInt1Ty)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputBoolean,
-                          art_portable_hl_sput_boolean,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-// void sput_hl_byte(int field_idx, int val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputByte,
-                          art_portable_hl_sput_byte,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-// void sput_hl_char(int field_idx, kInt16Ty val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputChar,
-                          art_portable_hl_sput_char,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-// void sput_hl_short(int field_idx, int val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputShort,
-                          art_portable_hl_sput_short,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt32Ty))
-
-// void sput_hl_wide(int field_idx, long val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputWide,
-                          art_portable_hl_sput_wide,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kInt64Ty))
-
-// void sput_hl_double(int field_idx, double val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputDouble,
-                          art_portable_hl_sput_double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kDoubleTy))
-
-// void sput_hl_float(int field_idx, float val)
-_EVAL_DEF_INTRINSICS_FUNC(HLSputFloat,
-                          art_portable_hl_sput_float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kFloatTy))
-
-//----------------------------------------------------------------------------
-// sget intrinsics to assist MIR to Greenland_ir conversion.
-// "HL" versions - will be deprecated when fast/slow path handling done
-// in the common frontend.
-//----------------------------------------------------------------------------
-
-// int sget_hl(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSget,
-                          art_portable_hl_sget,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// object* sget_hl_object(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetObject,
-                          art_portable_hl_sget_object,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// boolean sget_hl_boolean(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetBoolean,
-                          art_portable_hl_sget_boolean,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// byte sget_hl_byte(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetByte,
-                          art_portable_hl_sget_byte,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// char sget_hl_char(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetChar,
-                          art_portable_hl_sget_char,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// char sget_hl_short(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetShort,
-                          art_portable_hl_sget_short,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// char sget_hl_wide(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetWide,
-                          art_portable_hl_sget_wide,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// char sget_hl_double(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetDouble,
-                          art_portable_hl_sget_double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kDoubleTy,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// char sget_hl_float(int field_idx)
-_EVAL_DEF_INTRINSICS_FUNC(HLSgetFloat,
-                          art_portable_hl_sget_float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kFloatTy,
-                          _EXPAND_ARG1(kInt32Ty))
-//----------------------------------------------------------------------------
-// Monitor enter/exit
-//----------------------------------------------------------------------------
-// uint32_t art_portable_monitor_enter(int optFlags, JavaObject* obj)
-_EVAL_DEF_INTRINSICS_FUNC(MonitorEnter,
-                          art_portable_monitor_enter,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
-
-// uint32_t art_portable_monitor_exit(int optFlags, JavaObject* obj)
-_EVAL_DEF_INTRINSICS_FUNC(MonitorExit,
-                          art_portable_monitor_exit,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32Ty, kJavaObjectTy))
-
-//----------------------------------------------------------------------------
-// Shadow Frame
-//----------------------------------------------------------------------------
-
-// void art_portable_alloca_shadow_frame(int num_entry)
-_EVAL_DEF_INTRINSICS_FUNC(AllocaShadowFrame,
-                          art_portable_alloca_shadow_frame,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-// void art_portable_set_vreg(int entry_idx, ...)
-_EVAL_DEF_INTRINSICS_FUNC(SetVReg,
-                          art_portable_set_vreg,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG2(kInt32ConstantTy, kVarArgTy))
-
-// void art_portable_pop_shadow_frame()
-_EVAL_DEF_INTRINSICS_FUNC(PopShadowFrame,
-                          art_portable_pop_shadow_frame,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG0())
-
-// void art_portable_update_dex_pc(uint32_t dex_pc)
-_EVAL_DEF_INTRINSICS_FUNC(UpdateDexPC,
-                          art_portable_update_dex_pc,
-                          kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG1(kInt32ConstantTy))
-
-//----------------------------------------------------------------------------
-// FP Comparison
-//----------------------------------------------------------------------------
-// int cmpl_float(float, float)
-_EVAL_DEF_INTRINSICS_FUNC(CmplFloat,
-                          art_portable_cmpl_float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kFloatTy, kFloatTy))
-
-// int cmpg_float(float, float)
-_EVAL_DEF_INTRINSICS_FUNC(CmpgFloat,
-                          art_portable_cmpg_float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kFloatTy, kFloatTy))
-
-// int cmpl_double(double, double)
-_EVAL_DEF_INTRINSICS_FUNC(CmplDouble,
-                          art_portable_cmpl_double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kDoubleTy, kDoubleTy))
-
-// int cmpg_double(double, double)
-_EVAL_DEF_INTRINSICS_FUNC(CmpgDouble,
-                          art_portable_cmpg_double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kDoubleTy, kDoubleTy))
-
-//----------------------------------------------------------------------------
-// Long Comparison
-//----------------------------------------------------------------------------
-// int cmp_long(long, long)
-_EVAL_DEF_INTRINSICS_FUNC(CmpLong,
-                          art_portable_cmp_long,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt64Ty, kInt64Ty))
-
-//----------------------------------------------------------------------------
-// Const intrinsics to assist MIR to Greenland_ir conversion.  Should not materialize
-// For simplicity, all use integer input
-//----------------------------------------------------------------------------
-// int const_int(int)
-_EVAL_DEF_INTRINSICS_FUNC(ConstInt,
-                          art_portable_const_int,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// JavaObject* const_obj(int)
-_EVAL_DEF_INTRINSICS_FUNC(ConstObj,
-                          art_portable_const_obj,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// long const_long(long)
-_EVAL_DEF_INTRINSICS_FUNC(ConstLong,
-                          art_portable_const_long,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG1(kInt64Ty))
-
-// float const_float(int)
-_EVAL_DEF_INTRINSICS_FUNC(ConstFloat,
-                          art_portable_const_Float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kFloatTy,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// double const_double(long)
-_EVAL_DEF_INTRINSICS_FUNC(ConstDouble,
-                          art_portable_const_Double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kDoubleTy,
-                          _EXPAND_ARG1(kInt64Ty))
-
-
-//----------------------------------------------------------------------------
-// Copy intrinsics to assist MIR to Greenland_ir conversion.  Should not materialize
-//----------------------------------------------------------------------------
-
-// void method_info(void)
-_EVAL_DEF_INTRINSICS_FUNC(MethodInfo,
-                          art_portable_method_info,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG0())
-
-// int copy_int(int)
-_EVAL_DEF_INTRINSICS_FUNC(CopyInt,
-                          art_portable_copy_int,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// JavaObject* copy_obj(obj)
-_EVAL_DEF_INTRINSICS_FUNC(CopyObj,
-                          art_portable_copy_obj,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kJavaObjectTy,
-                          _EXPAND_ARG1(kJavaObjectTy))
-
-// long copy_long(long)
-_EVAL_DEF_INTRINSICS_FUNC(CopyLong,
-                          art_portable_copy_long,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG1(kInt64Ty))
-
-// float copy_float(float)
-_EVAL_DEF_INTRINSICS_FUNC(CopyFloat,
-                          art_portable_copy_Float,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kFloatTy,
-                          _EXPAND_ARG1(kFloatTy))
-
-// double copy_double(double)
-_EVAL_DEF_INTRINSICS_FUNC(CopyDouble,
-                          art_portable_copy_Double,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kDoubleTy,
-                          _EXPAND_ARG1(kDoubleTy))
-
-//----------------------------------------------------------------------------
-// Shift intrinsics.  Shift semantics for Dalvik are a bit different than
-// the llvm shift operators.  For 32-bit shifts, the shift count is constrained
-// to the range of 0..31, while for 64-bit shifts we limit to 0..63.
-// Further, the shift count for Long shifts in Dalvik is 32 bits, while
-// llvm requires a 64-bit shift count. For GBC, we represent shifts as an
-//  intrinsic to allow most efficient target-dependent lowering.
-//----------------------------------------------------------------------------
-// long shl_long(long,int)
-_EVAL_DEF_INTRINSICS_FUNC(SHLLong,
-                          art_portable_shl_long,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG2(kInt64Ty,kInt32Ty))
-// long shr_long(long,int)
-_EVAL_DEF_INTRINSICS_FUNC(SHRLong,
-                          art_portable_shr_long,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG2(kInt64Ty,kInt32Ty))
-// long ushr_long(long,int)
-_EVAL_DEF_INTRINSICS_FUNC(USHRLong,
-                          art_portable_ushl_long,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt64Ty,
-                          _EXPAND_ARG2(kInt64Ty,kInt32Ty))
-// int shl_int(int,int)
-_EVAL_DEF_INTRINSICS_FUNC(SHLInt,
-                          art_portable_shl_int,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty,kInt32Ty))
-// long shr_int(int,int)
-_EVAL_DEF_INTRINSICS_FUNC(SHRInt,
-                          art_portable_shr_int,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty,kInt32Ty))
-// int ushr_long(int,int)
-_EVAL_DEF_INTRINSICS_FUNC(USHRInt,
-                          art_portable_ushl_int,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG2(kInt32Ty,kInt32Ty))
-//----------------------------------------------------------------------------
-// Conversion instrinsics.  Note: these should eventually be removed.  We
-// can express these directly in bitcode, but by using intrinsics the
-// Quick compiler can be more efficient.  Some extra optimization infrastructure
-// will have to be developed to undo the bitcode verbosity when these are
-// done inline.
-//----------------------------------------------------------------------------
-// int int_to_byte(int)
-_EVAL_DEF_INTRINSICS_FUNC(IntToByte,
-                          art_portable_int_to_byte,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// int int_to_char(int)
-_EVAL_DEF_INTRINSICS_FUNC(IntToChar,
-                          art_portable_int_to_char,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-// int int_to_short(int)
-_EVAL_DEF_INTRINSICS_FUNC(IntToShort,
-                          art_portable_int_to_short,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kInt32Ty,
-                          _EXPAND_ARG1(kInt32Ty))
-
-//----------------------------------------------------------------------------
-// Memory barrier
-//----------------------------------------------------------------------------
-// void constructor_barrier()
-_EVAL_DEF_INTRINSICS_FUNC(ConstructorBarrier,
-                          art_portable_constructor_barrier,
-                          kAttrReadOnly | kAttrNoThrow,
-                          kVoidTy,
-                          _EXPAND_ARG0())
-
-// Clean up all internal used macros
-#undef _EXPAND_ARG0
-#undef _EXPAND_ARG1
-#undef _EXPAND_ARG2
-#undef _EXPAND_ARG3
-#undef _EXPAND_ARG4
-#undef _EXPAND_ARG5
-
-#undef _JTYPE_OF_kInt1Ty_UNDER_kArray
-#undef _JTYPE_OF_kInt8Ty_UNDER_kArray
-#undef _JTYPE_OF_kInt16Ty_UNDER_kArray
-#undef _JTYPE_OF_kInt32Ty_UNDER_kArray
-#undef _JTYPE_OF_kInt64Ty_UNDER_kArray
-#undef _JTYPE_OF_kJavaObjectTy_UNDER_kArray
-
-#undef _JTYPE_OF_kInt1Ty_UNDER_kField
-#undef _JTYPE_OF_kInt8Ty_UNDER_kField
-#undef _JTYPE_OF_kInt16Ty_UNDER_kField
-#undef _JTYPE_OF_kInt32Ty_UNDER_kField
-#undef _JTYPE_OF_kInt64Ty_UNDER_kField
-#undef _JTYPE_OF_kJavaObjectTy_UNDER_kField
-
-#undef DEF_INTRINSICS_FUNC
diff --git a/compiler/llvm/intrinsic_helper.cc b/compiler/llvm/intrinsic_helper.cc
deleted file mode 100644
index e5e7998..0000000
--- a/compiler/llvm/intrinsic_helper.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "intrinsic_helper.h"
-
-#include "ir_builder.h"
-
-#include <llvm/IR/Attributes.h>
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/IRBuilder.h>
-#include <llvm/IR/Intrinsics.h>
-
-namespace art {
-namespace llvm {
-
-const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[] = {
-#define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \
-                                                     ARG3_TYPE, ARG4_TYPE, \
-                                                     ARG5_TYPE) \
-  { #NAME, ATTR, RET_TYPE, { ARG1_TYPE, ARG2_TYPE, \
-                             ARG3_TYPE, ARG4_TYPE, \
-                             ARG5_TYPE} },
-#include "intrinsic_func_list.def"
-};
-
-static ::llvm::Type* GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
-                                                   IntrinsicHelper::IntrinsicValType type) {
-  switch (type) {
-    case IntrinsicHelper::kVoidTy: {
-      return irb.getVoidTy();
-    }
-    case IntrinsicHelper::kJavaObjectTy: {
-      return irb.getJObjectTy();
-    }
-    case IntrinsicHelper::kJavaMethodTy: {
-      return irb.getJMethodTy();
-    }
-    case IntrinsicHelper::kJavaThreadTy: {
-      return irb.getJThreadTy();
-    }
-    case IntrinsicHelper::kInt1Ty:
-    case IntrinsicHelper::kInt1ConstantTy: {
-      return irb.getInt1Ty();
-    }
-    case IntrinsicHelper::kInt8Ty:
-    case IntrinsicHelper::kInt8ConstantTy: {
-      return irb.getInt8Ty();
-    }
-    case IntrinsicHelper::kInt16Ty:
-    case IntrinsicHelper::kInt16ConstantTy: {
-      return irb.getInt16Ty();
-    }
-    case IntrinsicHelper::kInt32Ty:
-    case IntrinsicHelper::kInt32ConstantTy: {
-      return irb.getInt32Ty();
-    }
-    case IntrinsicHelper::kInt64Ty:
-    case IntrinsicHelper::kInt64ConstantTy: {
-      return irb.getInt64Ty();
-    }
-    case IntrinsicHelper::kFloatTy:
-    case IntrinsicHelper::kFloatConstantTy: {
-      return irb.getFloatTy();
-    }
-    case IntrinsicHelper::kDoubleTy:
-    case IntrinsicHelper::kDoubleConstantTy: {
-      return irb.getDoubleTy();
-    }
-    case IntrinsicHelper::kNone:
-    case IntrinsicHelper::kVarArgTy:
-    default: {
-      LOG(FATAL) << "Invalid intrinsic type " << type << "to get LLVM type!";
-      return NULL;
-    }
-  }
-  // unreachable
-}
-
-IntrinsicHelper::IntrinsicHelper(::llvm::LLVMContext& context,
-                                 ::llvm::Module& module) {
-  IRBuilder irb(context, module, *this);
-
-  ::memset(intrinsic_funcs_, 0, sizeof(intrinsic_funcs_));
-
-  // This loop does the following things:
-  // 1. Introduce the intrinsic function into the module
-  // 2. Add "nocapture" and "noalias" attribute to the arguments in all
-  //    intrinsics functions.
-  // 3. Initialize intrinsic_funcs_map_.
-  for (unsigned i = 0; i < MaxIntrinsicId; i++) {
-    IntrinsicId id = static_cast<IntrinsicId>(i);
-    const IntrinsicInfo& info = Info[i];
-
-    // Parse and construct the argument type from IntrinsicInfo
-    ::llvm::Type* arg_type[kIntrinsicMaxArgc];
-    unsigned num_args = 0;
-    bool is_var_arg = false;
-    for (unsigned arg_iter = 0; arg_iter < kIntrinsicMaxArgc; arg_iter++) {
-      IntrinsicValType type = info.arg_type_[arg_iter];
-
-      if (type == kNone) {
-        break;
-      } else if (type == kVarArgTy) {
-        // Variable argument type must be the last argument
-        is_var_arg = true;
-        break;
-      }
-
-      arg_type[num_args++] = GetLLVMTypeOfIntrinsicValType(irb, type);
-    }
-
-    // Construct the function type
-    ::llvm::Type* ret_type =
-        GetLLVMTypeOfIntrinsicValType(irb, info.ret_val_type_);
-
-    ::llvm::FunctionType* type =
-        ::llvm::FunctionType::get(ret_type,
-                                  ::llvm::ArrayRef< ::llvm::Type*>(arg_type, num_args),
-                                  is_var_arg);
-
-    // Declare the function
-    ::llvm::Function *fn = ::llvm::Function::Create(type,
-                                                    ::llvm::Function::ExternalLinkage,
-                                                     info.name_, &module);
-
-    if (info.attr_ & kAttrReadOnly) {
-        fn->setOnlyReadsMemory();
-    }
-    if (info.attr_ & kAttrReadNone) {
-        fn->setDoesNotAccessMemory();
-    }
-    // None of the intrinsics throws exception
-    fn->setDoesNotThrow();
-
-    intrinsic_funcs_[id] = fn;
-
-    DCHECK_NE(fn, static_cast< ::llvm::Function*>(NULL)) << "Intrinsic `"
-        << GetName(id) << "' was not defined!";
-
-    // Add "noalias" and "nocapture" attribute to all arguments of pointer type
-    for (::llvm::Function::arg_iterator arg_iter = fn->arg_begin(),
-            arg_end = fn->arg_end(); arg_iter != arg_end; arg_iter++) {
-      if (arg_iter->getType()->isPointerTy()) {
-        std::vector< ::llvm::Attribute::AttrKind> attributes;
-        attributes.push_back(::llvm::Attribute::NoCapture);
-        attributes.push_back(::llvm::Attribute::NoAlias);
-        ::llvm::AttributeSet attribute_set = ::llvm::AttributeSet::get(fn->getContext(),
-                                                                       arg_iter->getArgNo(),
-                                                                       attributes);
-        arg_iter->addAttr(attribute_set);
-      }
-    }
-
-    // Insert the newly created intrinsic to intrinsic_funcs_map_
-    if (!intrinsic_funcs_map_.insert(std::make_pair(fn, id)).second) {
-      LOG(FATAL) << "Duplicate entry in intrinsic functions map?";
-    }
-  }
-
-  return;
-}
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/intrinsic_helper.h b/compiler/llvm/intrinsic_helper.h
deleted file mode 100644
index 657db40..0000000
--- a/compiler/llvm/intrinsic_helper.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_INTRINSIC_HELPER_H_
-#define ART_COMPILER_LLVM_INTRINSIC_HELPER_H_
-
-#include "base/logging.h"
-
-#include <llvm/ADT/DenseMap.h>
-
-namespace llvm {
-  class Function;
-  class FunctionType;
-  class LLVMContext;
-  class Module;
-}  // namespace llvm
-
-namespace art {
-namespace llvm {
-
-class IRBuilder;
-
-class IntrinsicHelper {
- public:
-  enum IntrinsicId {
-#define DEF_INTRINSICS_FUNC(ID, ...) ID,
-#include "intrinsic_func_list.def"
-    MaxIntrinsicId,
-
-    // Pseudo-intrinsics Id
-    UnknownId
-  };
-
-  enum IntrinsicAttribute {
-    kAttrNone     = 0,
-
-    // Intrinsic that neither modified the memory state nor refer to the global
-    // state
-    kAttrReadNone = 1 << 0,
-
-    // Intrinsic that doesn't modify the memory state. Note that one should set
-    // this flag carefully when the intrinsic may throw exception. Since the
-    // thread state is implicitly modified when an exception is thrown.
-    kAttrReadOnly = 1 << 1,
-
-    // Note that intrinsic without kAttrNoThrow and kAttrDoThrow set means that
-    // intrinsic generates exception in some cases
-
-    // Intrinsic that never generates exception
-    kAttrNoThrow  = 1 << 2,
-    // Intrinsic that always generate exception
-    kAttrDoThrow  = 1 << 3,
-  };
-
-  enum IntrinsicValType {
-    kNone,
-
-    kVoidTy,
-
-    kJavaObjectTy,
-    kJavaMethodTy,
-    kJavaThreadTy,
-
-    kInt1Ty,
-    kInt8Ty,
-    kInt16Ty,
-    kInt32Ty,
-    kInt64Ty,
-    kFloatTy,
-    kDoubleTy,
-
-    kInt1ConstantTy,
-    kInt8ConstantTy,
-    kInt16ConstantTy,
-    kInt32ConstantTy,
-    kInt64ConstantTy,
-    kFloatConstantTy,
-    kDoubleConstantTy,
-
-    kVarArgTy,
-  };
-
-  enum {
-    kIntrinsicMaxArgc = 5
-  };
-
-  typedef struct IntrinsicInfo {
-    const char* name_;
-    unsigned attr_;
-    IntrinsicValType ret_val_type_;
-    IntrinsicValType arg_type_[kIntrinsicMaxArgc];
-  } IntrinsicInfo;
-
- private:
-  static const IntrinsicInfo Info[];
-
- public:
-  static const IntrinsicInfo& GetInfo(IntrinsicId id) {
-    DCHECK(id >= 0 && id < MaxIntrinsicId) << "Unknown ART intrinsics ID: "
-                                           << id;
-    return Info[id];
-  }
-
-  static const char* GetName(IntrinsicId id) {
-    return (id <= MaxIntrinsicId) ? GetInfo(id).name_ : "InvalidIntrinsic";
-  }
-
-  static unsigned GetAttr(IntrinsicId id) {
-    return GetInfo(id).attr_;
-  }
-
- public:
-  IntrinsicHelper(::llvm::LLVMContext& context, ::llvm::Module& module);
-
-  ::llvm::Function* GetIntrinsicFunction(IntrinsicId id) {
-    DCHECK(id >= 0 && id < MaxIntrinsicId) << "Unknown ART intrinsics ID: "
-                                           << id;
-    return intrinsic_funcs_[id];
-  }
-
-  IntrinsicId GetIntrinsicId(const ::llvm::Function* func) const {
-    ::llvm::DenseMap<const ::llvm::Function*, IntrinsicId>::const_iterator
-        i = intrinsic_funcs_map_.find(func);
-    if (i == intrinsic_funcs_map_.end()) {
-      return UnknownId;
-    } else {
-      return i->second;
-    }
-  }
-
- private:
-  // FIXME: "+1" is to workaround the GCC bugs:
-  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
-  // Remove this when uses newer GCC (> 4.4.3)
-  ::llvm::Function* intrinsic_funcs_[MaxIntrinsicId + 1];
-
-  // Map a llvm::Function to its intrinsic id
-  ::llvm::DenseMap<const ::llvm::Function*, IntrinsicId> intrinsic_funcs_map_;
-};
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_INTRINSIC_HELPER_H_
diff --git a/compiler/llvm/ir_builder.cc b/compiler/llvm/ir_builder.cc
deleted file mode 100644
index 9644ebd..0000000
--- a/compiler/llvm/ir_builder.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ir_builder.h"
-
-#include "base/stringprintf.h"
-
-#include <llvm/IR/Module.h>
-
-namespace art {
-namespace llvm {
-
-
-//----------------------------------------------------------------------------
-// General
-//----------------------------------------------------------------------------
-
-IRBuilder::IRBuilder(::llvm::LLVMContext& context, ::llvm::Module& module,
-                     IntrinsicHelper& intrinsic_helper)
-    : LLVMIRBuilder(context), module_(&module), mdb_(context), java_object_type_(NULL),
-      java_method_type_(NULL), java_thread_type_(NULL), intrinsic_helper_(intrinsic_helper) {
-  // Get java object type from module
-  ::llvm::Type* jobject_struct_type = module.getTypeByName("JavaObject");
-  CHECK(jobject_struct_type != NULL);
-  java_object_type_ = jobject_struct_type->getPointerTo();
-
-  // If type of Method is not explicitly defined in the module, use JavaObject*
-  ::llvm::Type* type = module.getTypeByName("Method");
-  if (type != NULL) {
-    java_method_type_ = type->getPointerTo();
-  } else {
-    java_method_type_ = java_object_type_;
-  }
-
-  // If type of Thread is not explicitly defined in the module, use JavaObject*
-  type = module.getTypeByName("Thread");
-  if (type != NULL) {
-    java_thread_type_ = type->getPointerTo();
-  } else {
-    java_thread_type_ = java_object_type_;
-  }
-
-  // Create JEnv* type
-  ::llvm::Type* jenv_struct_type = ::llvm::StructType::create(context, "JEnv");
-  jenv_type_ = jenv_struct_type->getPointerTo();
-
-  // Get Art shadow frame struct type from module
-  art_frame_type_ = module.getTypeByName("ShadowFrame");
-  CHECK(art_frame_type_ != NULL);
-
-  runtime_support_ = NULL;
-}
-
-
-//----------------------------------------------------------------------------
-// Type Helper Function
-//----------------------------------------------------------------------------
-
-::llvm::Type* IRBuilder::getJType(JType jty) {
-  switch (jty) {
-  case kVoid:
-    return getJVoidTy();
-
-  case kBoolean:
-    return getJBooleanTy();
-
-  case kByte:
-    return getJByteTy();
-
-  case kChar:
-    return getJCharTy();
-
-  case kShort:
-    return getJShortTy();
-
-  case kInt:
-    return getJIntTy();
-
-  case kLong:
-    return getJLongTy();
-
-  case kFloat:
-    return getJFloatTy();
-
-  case kDouble:
-    return getJDoubleTy();
-
-  case kObject:
-    return getJObjectTy();
-
-  default:
-    LOG(FATAL) << "Unknown java type: " << jty;
-    return NULL;
-  }
-}
-
-::llvm::StructType* IRBuilder::getShadowFrameTy(uint32_t vreg_size) {
-  std::string name(StringPrintf("ShadowFrame%u", vreg_size));
-
-  // Try to find the existing struct type definition
-  if (::llvm::Type* type = module_->getTypeByName(name)) {
-    CHECK(::llvm::isa< ::llvm::StructType>(type));
-    return static_cast< ::llvm::StructType*>(type);
-  }
-
-  // Create new struct type definition
-  ::llvm::Type* elem_types[] = {
-    art_frame_type_,
-    ::llvm::ArrayType::get(getInt32Ty(), vreg_size),
-  };
-
-  return ::llvm::StructType::create(elem_types, name);
-}
-
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/ir_builder.h b/compiler/llvm/ir_builder.h
deleted file mode 100644
index 03498ef..0000000
--- a/compiler/llvm/ir_builder.h
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_IR_BUILDER_H_
-#define ART_COMPILER_LLVM_IR_BUILDER_H_
-
-#include "backend_types.h"
-#include "dex/compiler_enums.h"
-#include "intrinsic_helper.h"
-#include "md_builder.h"
-#include "runtime_support_builder.h"
-#include "runtime_support_llvm_func.h"
-
-#include <llvm/IR/Constants.h>
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/IRBuilder.h>
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/IR/Type.h>
-#include <llvm/Support/NoFolder.h>
-
-#include <stdint.h>
-
-
-namespace art {
-namespace llvm {
-
-class InserterWithDexOffset : public ::llvm::IRBuilderDefaultInserter<true> {
-  public:
-    InserterWithDexOffset() : node_(NULL) {}
-
-    void InsertHelper(::llvm::Instruction *I, const ::llvm::Twine &Name,
-                      ::llvm::BasicBlock *BB,
-                      ::llvm::BasicBlock::iterator InsertPt) const {
-      ::llvm::IRBuilderDefaultInserter<true>::InsertHelper(I, Name, BB, InsertPt);
-      if (node_ != NULL) {
-        I->setMetadata("DexOff", node_);
-      }
-    }
-
-    void SetDexOffset(::llvm::MDNode* node) {
-      node_ = node;
-    }
-  private:
-    ::llvm::MDNode* node_;
-};
-
-typedef ::llvm::IRBuilder<true, ::llvm::ConstantFolder, InserterWithDexOffset> LLVMIRBuilder;
-// NOTE: Here we define our own LLVMIRBuilder type alias, so that we can
-// switch "preserveNames" template parameter easily.
-
-
-class IRBuilder : public LLVMIRBuilder {
- public:
-  //--------------------------------------------------------------------------
-  // General
-  //--------------------------------------------------------------------------
-
-  IRBuilder(::llvm::LLVMContext& context, ::llvm::Module& module,
-            IntrinsicHelper& intrinsic_helper);
-
-
-  //--------------------------------------------------------------------------
-  // Extend load & store for TBAA
-  //--------------------------------------------------------------------------
-
-  ::llvm::LoadInst* CreateLoad(::llvm::Value* ptr, ::llvm::MDNode* tbaa_info) {
-    ::llvm::LoadInst* inst = LLVMIRBuilder::CreateLoad(ptr);
-    inst->setMetadata(::llvm::LLVMContext::MD_tbaa, tbaa_info);
-    return inst;
-  }
-
-  ::llvm::StoreInst* CreateStore(::llvm::Value* val, ::llvm::Value* ptr, ::llvm::MDNode* tbaa_info) {
-    ::llvm::StoreInst* inst = LLVMIRBuilder::CreateStore(val, ptr);
-    inst->setMetadata(::llvm::LLVMContext::MD_tbaa, tbaa_info);
-    return inst;
-  }
-
-  ::llvm::AtomicCmpXchgInst*
-  CreateAtomicCmpXchgInst(::llvm::Value* ptr, ::llvm::Value* cmp, ::llvm::Value* val,
-                          ::llvm::MDNode* tbaa_info) {
-    ::llvm::AtomicCmpXchgInst* inst =
-        LLVMIRBuilder::CreateAtomicCmpXchg(ptr, cmp, val, ::llvm::Acquire);
-    inst->setMetadata(::llvm::LLVMContext::MD_tbaa, tbaa_info);
-    return inst;
-  }
-
-  //--------------------------------------------------------------------------
-  // Extend memory barrier
-  //--------------------------------------------------------------------------
-  void CreateMemoryBarrier(MemBarrierKind barrier_kind) {
-#if ANDROID_SMP
-    // TODO: select atomic ordering according to given barrier kind.
-    CreateFence(::llvm::SequentiallyConsistent);
-#endif
-  }
-
-  //--------------------------------------------------------------------------
-  // TBAA
-  //--------------------------------------------------------------------------
-
-  // TODO: After we design the non-special TBAA info, re-design the TBAA interface.
-  ::llvm::LoadInst* CreateLoad(::llvm::Value* ptr, TBAASpecialType special_ty) {
-    return CreateLoad(ptr, mdb_.GetTBAASpecialType(special_ty));
-  }
-
-  ::llvm::StoreInst* CreateStore(::llvm::Value* val, ::llvm::Value* ptr, TBAASpecialType special_ty) {
-    DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
-    return CreateStore(val, ptr, mdb_.GetTBAASpecialType(special_ty));
-  }
-
-  ::llvm::LoadInst* CreateLoad(::llvm::Value* ptr, TBAASpecialType special_ty, JType j_ty) {
-    return CreateLoad(ptr, mdb_.GetTBAAMemoryJType(special_ty, j_ty));
-  }
-
-  ::llvm::StoreInst* CreateStore(::llvm::Value* val, ::llvm::Value* ptr,
-                               TBAASpecialType special_ty, JType j_ty) {
-    DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
-    return CreateStore(val, ptr, mdb_.GetTBAAMemoryJType(special_ty, j_ty));
-  }
-
-  ::llvm::LoadInst* LoadFromObjectOffset(::llvm::Value* object_addr,
-                                       int64_t offset,
-                                       ::llvm::Type* type,
-                                       TBAASpecialType special_ty) {
-    return LoadFromObjectOffset(object_addr, offset, type, mdb_.GetTBAASpecialType(special_ty));
-  }
-
-  void StoreToObjectOffset(::llvm::Value* object_addr,
-                           int64_t offset,
-                           ::llvm::Value* new_value,
-                           TBAASpecialType special_ty) {
-    DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
-    StoreToObjectOffset(object_addr, offset, new_value, mdb_.GetTBAASpecialType(special_ty));
-  }
-
-  ::llvm::LoadInst* LoadFromObjectOffset(::llvm::Value* object_addr,
-                                       int64_t offset,
-                                       ::llvm::Type* type,
-                                       TBAASpecialType special_ty, JType j_ty) {
-    return LoadFromObjectOffset(object_addr, offset, type, mdb_.GetTBAAMemoryJType(special_ty, j_ty));
-  }
-
-  void StoreToObjectOffset(::llvm::Value* object_addr,
-                           int64_t offset,
-                           ::llvm::Value* new_value,
-                           TBAASpecialType special_ty, JType j_ty) {
-    DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
-    StoreToObjectOffset(object_addr, offset, new_value, mdb_.GetTBAAMemoryJType(special_ty, j_ty));
-  }
-
-  ::llvm::AtomicCmpXchgInst*
-  CompareExchangeObjectOffset(::llvm::Value* object_addr,
-                              int64_t offset,
-                              ::llvm::Value* cmp_value,
-                              ::llvm::Value* new_value,
-                              TBAASpecialType special_ty) {
-    DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
-    return CompareExchangeObjectOffset(object_addr, offset, cmp_value, new_value,
-                                       mdb_.GetTBAASpecialType(special_ty));
-  }
-
-  void SetTBAA(::llvm::Instruction* inst, TBAASpecialType special_ty) {
-    inst->setMetadata(::llvm::LLVMContext::MD_tbaa, mdb_.GetTBAASpecialType(special_ty));
-  }
-
-
-  //--------------------------------------------------------------------------
-  // Static Branch Prediction
-  //--------------------------------------------------------------------------
-
-  // Import the orignal conditional branch
-  using LLVMIRBuilder::CreateCondBr;
-  ::llvm::BranchInst* CreateCondBr(::llvm::Value *cond,
-                                 ::llvm::BasicBlock* true_bb,
-                                 ::llvm::BasicBlock* false_bb,
-                                 ExpectCond expect) {
-    ::llvm::BranchInst* branch_inst = CreateCondBr(cond, true_bb, false_bb);
-    if (false) {
-      // TODO: http://b/8511695 Restore branch weight metadata
-      branch_inst->setMetadata(::llvm::LLVMContext::MD_prof, mdb_.GetBranchWeights(expect));
-    }
-    return branch_inst;
-  }
-
-
-  //--------------------------------------------------------------------------
-  // Pointer Arithmetic Helper Function
-  //--------------------------------------------------------------------------
-
-  ::llvm::IntegerType* getPtrEquivIntTy() {
-    return getInt32Ty();
-  }
-
-  size_t getSizeOfPtrEquivInt() {
-    return 4;
-  }
-
-  ::llvm::ConstantInt* getSizeOfPtrEquivIntValue() {
-    return getPtrEquivInt(getSizeOfPtrEquivInt());
-  }
-
-  ::llvm::ConstantInt* getPtrEquivInt(int64_t i) {
-    return ::llvm::ConstantInt::get(getPtrEquivIntTy(), i);
-  }
-
-  ::llvm::Value* CreatePtrDisp(::llvm::Value* base,
-                             ::llvm::Value* offset,
-                             ::llvm::PointerType* ret_ty) {
-    ::llvm::Value* base_int = CreatePtrToInt(base, getPtrEquivIntTy());
-    ::llvm::Value* result_int = CreateAdd(base_int, offset);
-    ::llvm::Value* result = CreateIntToPtr(result_int, ret_ty);
-
-    return result;
-  }
-
-  ::llvm::Value* CreatePtrDisp(::llvm::Value* base,
-                             ::llvm::Value* bs,
-                             ::llvm::Value* count,
-                             ::llvm::Value* offset,
-                             ::llvm::PointerType* ret_ty) {
-    ::llvm::Value* block_offset = CreateMul(bs, count);
-    ::llvm::Value* total_offset = CreateAdd(block_offset, offset);
-
-    return CreatePtrDisp(base, total_offset, ret_ty);
-  }
-
-  ::llvm::LoadInst* LoadFromObjectOffset(::llvm::Value* object_addr,
-                                       int64_t offset,
-                                       ::llvm::Type* type,
-                                       ::llvm::MDNode* tbaa_info) {
-    // Convert offset to ::llvm::value
-    ::llvm::Value* llvm_offset = getPtrEquivInt(offset);
-    // Calculate the value's address
-    ::llvm::Value* value_addr = CreatePtrDisp(object_addr, llvm_offset, type->getPointerTo());
-    // Load
-    return CreateLoad(value_addr, tbaa_info);
-  }
-
-  void StoreToObjectOffset(::llvm::Value* object_addr,
-                           int64_t offset,
-                           ::llvm::Value* new_value,
-                           ::llvm::MDNode* tbaa_info) {
-    // Convert offset to ::llvm::value
-    ::llvm::Value* llvm_offset = getPtrEquivInt(offset);
-    // Calculate the value's address
-    ::llvm::Value* value_addr = CreatePtrDisp(object_addr,
-                                            llvm_offset,
-                                            new_value->getType()->getPointerTo());
-    // Store
-    CreateStore(new_value, value_addr, tbaa_info);
-  }
-
-  ::llvm::AtomicCmpXchgInst* CompareExchangeObjectOffset(::llvm::Value* object_addr,
-                                                       int64_t offset,
-                                                       ::llvm::Value* cmp_value,
-                                                       ::llvm::Value* new_value,
-                                                       ::llvm::MDNode* tbaa_info) {
-    // Convert offset to ::llvm::value
-    ::llvm::Value* llvm_offset = getPtrEquivInt(offset);
-    // Calculate the value's address
-    ::llvm::Value* value_addr = CreatePtrDisp(object_addr,
-                                            llvm_offset,
-                                            new_value->getType()->getPointerTo());
-    // Atomic compare and exchange
-    return CreateAtomicCmpXchgInst(value_addr, cmp_value, new_value, tbaa_info);
-  }
-
-
-  //--------------------------------------------------------------------------
-  // Runtime Helper Function
-  //--------------------------------------------------------------------------
-
-  RuntimeSupportBuilder& Runtime() {
-    return *runtime_support_;
-  }
-
-  // TODO: Deprecate
-  ::llvm::Function* GetRuntime(runtime_support::RuntimeId rt) {
-    return runtime_support_->GetRuntimeSupportFunction(rt);
-  }
-
-  // TODO: Deprecate
-  void SetRuntimeSupport(RuntimeSupportBuilder* runtime_support) {
-    // Can only set once. We can't do this on constructor, because RuntimeSupportBuilder needs
-    // IRBuilder.
-    if (runtime_support_ == NULL && runtime_support != NULL) {
-      runtime_support_ = runtime_support;
-    }
-  }
-
-
-  //--------------------------------------------------------------------------
-  // Type Helper Function
-  //--------------------------------------------------------------------------
-
-  ::llvm::Type* getJType(char shorty_jty) {
-    return getJType(GetJTypeFromShorty(shorty_jty));
-  }
-
-  ::llvm::Type* getJType(JType jty);
-
-  ::llvm::Type* getJVoidTy() {
-    return getVoidTy();
-  }
-
-  ::llvm::IntegerType* getJBooleanTy() {
-    return getInt8Ty();
-  }
-
-  ::llvm::IntegerType* getJByteTy() {
-    return getInt8Ty();
-  }
-
-  ::llvm::IntegerType* getJCharTy() {
-    return getInt16Ty();
-  }
-
-  ::llvm::IntegerType* getJShortTy() {
-    return getInt16Ty();
-  }
-
-  ::llvm::IntegerType* getJIntTy() {
-    return getInt32Ty();
-  }
-
-  ::llvm::IntegerType* getJLongTy() {
-    return getInt64Ty();
-  }
-
-  ::llvm::Type* getJFloatTy() {
-    return getFloatTy();
-  }
-
-  ::llvm::Type* getJDoubleTy() {
-    return getDoubleTy();
-  }
-
-  ::llvm::PointerType* getJObjectTy() {
-    return java_object_type_;
-  }
-
-  ::llvm::PointerType* getJMethodTy() {
-    return java_method_type_;
-  }
-
-  ::llvm::PointerType* getJThreadTy() {
-    return java_thread_type_;
-  }
-
-  ::llvm::Type* getArtFrameTy() {
-    return art_frame_type_;
-  }
-
-  ::llvm::PointerType* getJEnvTy() {
-    return jenv_type_;
-  }
-
-  ::llvm::Type* getJValueTy() {
-    // NOTE: JValue is an union type, which may contains boolean, byte, char,
-    // short, int, long, float, double, Object.  However, LLVM itself does
-    // not support union type, so we have to return a type with biggest size,
-    // then bitcast it before we use it.
-    return getJLongTy();
-  }
-
-  ::llvm::StructType* getShadowFrameTy(uint32_t vreg_size);
-
-
-  //--------------------------------------------------------------------------
-  // Constant Value Helper Function
-  //--------------------------------------------------------------------------
-
-  ::llvm::ConstantInt* getJBoolean(bool is_true) {
-    return (is_true) ? getTrue() : getFalse();
-  }
-
-  ::llvm::ConstantInt* getJByte(int8_t i) {
-    return ::llvm::ConstantInt::getSigned(getJByteTy(), i);
-  }
-
-  ::llvm::ConstantInt* getJChar(int16_t i) {
-    return ::llvm::ConstantInt::getSigned(getJCharTy(), i);
-  }
-
-  ::llvm::ConstantInt* getJShort(int16_t i) {
-    return ::llvm::ConstantInt::getSigned(getJShortTy(), i);
-  }
-
-  ::llvm::ConstantInt* getJInt(int32_t i) {
-    return ::llvm::ConstantInt::getSigned(getJIntTy(), i);
-  }
-
-  ::llvm::ConstantInt* getJLong(int64_t i) {
-    return ::llvm::ConstantInt::getSigned(getJLongTy(), i);
-  }
-
-  ::llvm::Constant* getJFloat(float f) {
-    return ::llvm::ConstantFP::get(getJFloatTy(), f);
-  }
-
-  ::llvm::Constant* getJDouble(double d) {
-    return ::llvm::ConstantFP::get(getJDoubleTy(), d);
-  }
-
-  ::llvm::ConstantPointerNull* getJNull() {
-    return ::llvm::ConstantPointerNull::get(getJObjectTy());
-  }
-
-  ::llvm::Constant* getJZero(char shorty_jty) {
-    return getJZero(GetJTypeFromShorty(shorty_jty));
-  }
-
-  ::llvm::Constant* getJZero(JType jty) {
-    switch (jty) {
-    case kVoid:
-      LOG(FATAL) << "Zero is not a value of void type";
-      return NULL;
-
-    case kBoolean:
-      return getJBoolean(false);
-
-    case kByte:
-      return getJByte(0);
-
-    case kChar:
-      return getJChar(0);
-
-    case kShort:
-      return getJShort(0);
-
-    case kInt:
-      return getJInt(0);
-
-    case kLong:
-      return getJLong(0);
-
-    case kFloat:
-      return getJFloat(0.0f);
-
-    case kDouble:
-      return getJDouble(0.0);
-
-    case kObject:
-      return getJNull();
-
-    default:
-      LOG(FATAL) << "Unknown java type: " << jty;
-      return NULL;
-    }
-  }
-
-
- private:
-  ::llvm::Module* module_;
-
-  MDBuilder mdb_;
-
-  ::llvm::PointerType* java_object_type_;
-  ::llvm::PointerType* java_method_type_;
-  ::llvm::PointerType* java_thread_type_;
-
-  ::llvm::PointerType* jenv_type_;
-
-  ::llvm::StructType* art_frame_type_;
-
-  RuntimeSupportBuilder* runtime_support_;
-
-  IntrinsicHelper& intrinsic_helper_;
-};
-
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_IR_BUILDER_H_
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
deleted file mode 100644
index 741c2d7..0000000
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO: TargetLibraryInfo is included before sys/... because on Android bionic does #define tricks like:
-//
-// #define  stat64    stat
-// #define  fstat64   fstat
-// #define  lstat64   lstat
-//
-// which causes grief. bionic probably should not do that.
-#include <llvm/Target/TargetLibraryInfo.h>
-
-#include "llvm_compilation_unit.h"
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <llvm/ADT/OwningPtr.h>
-#include <llvm/ADT/StringSet.h>
-#include <llvm/ADT/Triple.h>
-#include <llvm/Analysis/CallGraph.h>
-#include <llvm/Analysis/CallGraphSCCPass.h>
-#include <llvm/Analysis/Dominators.h>
-#include <llvm/Analysis/LoopInfo.h>
-#include <llvm/Analysis/LoopPass.h>
-#include <llvm/Analysis/RegionPass.h>
-#include <llvm/Analysis/ScalarEvolution.h>
-#include <llvm/Analysis/Verifier.h>
-#include <llvm/Assembly/PrintModulePass.h>
-#include <llvm/Bitcode/ReaderWriter.h>
-#include <llvm/CodeGen/MachineFrameInfo.h>
-#include <llvm/CodeGen/MachineFunction.h>
-#include <llvm/CodeGen/MachineFunctionPass.h>
-#include <llvm/DebugInfo.h>
-#include <llvm/IR/DataLayout.h>
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/IR/Module.h>
-#include <llvm/Object/ObjectFile.h>
-#include <llvm/PassManager.h>
-#include <llvm/Support/Debug.h>
-#include <llvm/Support/ELF.h>
-#include <llvm/Support/FormattedStream.h>
-#include <llvm/Support/ManagedStatic.h>
-#include <llvm/Support/MemoryBuffer.h>
-#include <llvm/Support/PassNameParser.h>
-#include <llvm/Support/PluginLoader.h>
-#include <llvm/Support/PrettyStackTrace.h>
-#include <llvm/Support/Signals.h>
-#include <llvm/Support/SystemUtils.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/TargetSelect.h>
-#include <llvm/Support/ToolOutputFile.h>
-#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/system_error.h>
-#include <llvm/Target/TargetMachine.h>
-#include <llvm/Transforms/IPO.h>
-#include <llvm/Transforms/IPO/PassManagerBuilder.h>
-#include <llvm/Transforms/Scalar.h>
-
-#include "base/logging.h"
-#include "base/unix_file/fd_file.h"
-#include "compiled_method.h"
-#include "compiler_llvm.h"
-#include "instruction_set.h"
-#include "ir_builder.h"
-#include "os.h"
-#include "runtime_support_builder_arm.h"
-#include "runtime_support_builder_x86.h"
-#include "utils_llvm.h"
-
-namespace art {
-namespace llvm {
-
-::llvm::FunctionPass*
-CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb,
-                      CompilerDriver* compiler, const DexCompilationUnit* dex_compilation_unit);
-
-::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
-
-
-LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size_t cunit_id)
-    : compiler_llvm_(compiler_llvm), cunit_id_(cunit_id) {
-  driver_ = NULL;
-  dex_compilation_unit_ = NULL;
-  llvm_info_.reset(new LLVMInfo());
-  context_.reset(llvm_info_->GetLLVMContext());
-  module_ = llvm_info_->GetLLVMModule();
-
-  // Include the runtime function declaration
-  makeLLVMModuleContents(module_);
-
-
-  intrinsic_helper_.reset(new IntrinsicHelper(*context_, *module_));
-
-  // Create IRBuilder
-  irb_.reset(new IRBuilder(*context_, *module_, *intrinsic_helper_));
-
-  // We always need a switch case, so just use a normal function.
-  switch (GetInstructionSet()) {
-  default:
-    runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
-    break;
-  case kThumb2:
-  case kArm:
-    runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
-    break;
-  case kX86:
-    runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
-    break;
-  }
-
-  irb_->SetRuntimeSupport(runtime_support_.get());
-}
-
-
-LlvmCompilationUnit::~LlvmCompilationUnit() {
-  ::llvm::LLVMContext* llvm_context = context_.release();  // Managed by llvm_info_
-  CHECK(llvm_context != NULL);
-}
-
-
-InstructionSet LlvmCompilationUnit::GetInstructionSet() const {
-  return compiler_llvm_->GetInstructionSet();
-}
-
-
-static std::string DumpDirectory() {
-  if (kIsTargetBuild) {
-    return GetDalvikCacheOrDie("llvm-dump");
-  }
-  return "/tmp";
-}
-
-void LlvmCompilationUnit::DumpBitcodeToFile() {
-  std::string bitcode;
-  DumpBitcodeToString(bitcode);
-  std::string filename(StringPrintf("%s/Art%zu.bc", DumpDirectory().c_str(), cunit_id_));
-  std::unique_ptr<File> output(OS::CreateEmptyFile(filename.c_str()));
-  output->WriteFully(bitcode.data(), bitcode.size());
-  LOG(INFO) << ".bc file written successfully: " << filename;
-}
-
-void LlvmCompilationUnit::DumpBitcodeToString(std::string& str_buffer) {
-  ::llvm::raw_string_ostream str_os(str_buffer);
-  ::llvm::WriteBitcodeToFile(module_, str_os);
-}
-
-bool LlvmCompilationUnit::Materialize() {
-  const bool kDumpBitcode = false;
-  if (kDumpBitcode) {
-    // Dump the bitcode for debugging
-    DumpBitcodeToFile();
-  }
-
-  // Compile and prelink ::llvm::Module
-  if (!MaterializeToString(elf_object_)) {
-    LOG(ERROR) << "Failed to materialize compilation unit " << cunit_id_;
-    return false;
-  }
-
-  const bool kDumpELF = false;
-  if (kDumpELF) {
-    // Dump the ELF image for debugging
-    std::string filename(StringPrintf("%s/Art%zu.o", DumpDirectory().c_str(), cunit_id_));
-    std::unique_ptr<File> output(OS::CreateEmptyFile(filename.c_str()));
-    output->WriteFully(elf_object_.data(), elf_object_.size());
-    LOG(INFO) << ".o file written successfully: " << filename;
-  }
-
-  return true;
-}
-
-
-bool LlvmCompilationUnit::MaterializeToString(std::string& str_buffer) {
-  ::llvm::raw_string_ostream str_os(str_buffer);
-  return MaterializeToRawOStream(str_os);
-}
-
-
-bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_stream) {
-  // Lookup the LLVM target
-  std::string target_triple;
-  std::string target_cpu;
-  std::string target_attr;
-  CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), &target_triple, &target_cpu,
-                                             &target_attr);
-
-  std::string errmsg;
-  const ::llvm::Target* target =
-    ::llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
-
-  CHECK(target != NULL) << errmsg;
-
-  // Target options
-  ::llvm::TargetOptions target_options;
-  target_options.FloatABIType = ::llvm::FloatABI::Soft;
-  target_options.NoFramePointerElim = true;
-  target_options.UseSoftFloat = false;
-  target_options.EnableFastISel = false;
-
-  // Create the ::llvm::TargetMachine
-  ::llvm::OwningPtr< ::llvm::TargetMachine> target_machine(
-    target->createTargetMachine(target_triple, target_cpu, target_attr, target_options,
-                                ::llvm::Reloc::Static, ::llvm::CodeModel::Small,
-                                ::llvm::CodeGenOpt::Aggressive));
-
-  CHECK(target_machine.get() != NULL) << "Failed to create target machine";
-
-  // Add target data
-  const ::llvm::DataLayout* data_layout = target_machine->getDataLayout();
-
-  // PassManager for code generation passes
-  ::llvm::PassManager pm;
-  pm.add(new ::llvm::DataLayout(*data_layout));
-
-  // FunctionPassManager for optimization pass
-  ::llvm::FunctionPassManager fpm(module_);
-  fpm.add(new ::llvm::DataLayout(*data_layout));
-
-  if (bitcode_filename_.empty()) {
-    // If we don't need write the bitcode to file, add the AddSuspendCheckToLoopLatchPass to the
-    // regular FunctionPass.
-    fpm.add(CreateGBCExpanderPass(*llvm_info_->GetIntrinsicHelper(), *irb_.get(),
-                                  driver_, dex_compilation_unit_));
-  } else {
-    ::llvm::FunctionPassManager fpm2(module_);
-    fpm2.add(CreateGBCExpanderPass(*llvm_info_->GetIntrinsicHelper(), *irb_.get(),
-                                   driver_, dex_compilation_unit_));
-    fpm2.doInitialization();
-    for (::llvm::Module::iterator F = module_->begin(), E = module_->end();
-         F != E; ++F) {
-      fpm2.run(*F);
-    }
-    fpm2.doFinalization();
-
-    // Write bitcode to file
-    std::string errmsg;
-
-    ::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
-      new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
-                                 ::llvm::sys::fs::F_Binary));
-
-
-    if (!errmsg.empty()) {
-      LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
-      return false;
-    }
-
-    ::llvm::WriteBitcodeToFile(module_, out_file->os());
-    out_file->keep();
-  }
-
-  // Add optimization pass
-  ::llvm::PassManagerBuilder pm_builder;
-  // TODO: Use inliner after we can do IPO.
-  pm_builder.Inliner = NULL;
-  // pm_builder.Inliner = ::llvm::createFunctionInliningPass();
-  // pm_builder.Inliner = ::llvm::createAlwaysInlinerPass();
-  // pm_builder.Inliner = ::llvm::createPartialInliningPass();
-  pm_builder.OptLevel = 3;
-  pm_builder.DisableUnitAtATime = 1;
-  pm_builder.populateFunctionPassManager(fpm);
-  pm_builder.populateModulePassManager(pm);
-  pm.add(::llvm::createStripDeadPrototypesPass());
-
-  // Add passes to emit ELF image
-  {
-    ::llvm::formatted_raw_ostream formatted_os(out_stream, false);
-
-    // Ask the target to add backend passes as necessary.
-    if (target_machine->addPassesToEmitFile(pm,
-                                            formatted_os,
-                                            ::llvm::TargetMachine::CGFT_ObjectFile,
-                                            true)) {
-      LOG(FATAL) << "Unable to generate ELF for this target";
-      return false;
-    }
-
-    // Run the per-function optimization
-    fpm.doInitialization();
-    for (::llvm::Module::iterator F = module_->begin(), E = module_->end();
-         F != E; ++F) {
-      fpm.run(*F);
-    }
-    fpm.doFinalization();
-
-    // Run the code generation passes
-    pm.run(*module_);
-  }
-
-  return true;
-}
-
-// Check whether the align is less than or equal to the code alignment of
-// that architecture.  Since the Oat writer only guarantee that the compiled
-// method being aligned to kArchAlignment, we have no way to align the ELf
-// section if the section alignment is greater than kArchAlignment.
-void LlvmCompilationUnit::CheckCodeAlign(uint32_t align) const {
-  InstructionSet insn_set = GetInstructionSet();
-  size_t insn_set_align = GetInstructionSetAlignment(insn_set);
-  CHECK_LE(align, static_cast<uint32_t>(insn_set_align));
-}
-
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/llvm_compilation_unit.h b/compiler/llvm/llvm_compilation_unit.h
deleted file mode 100644
index f11fb6e..0000000
--- a/compiler/llvm/llvm_compilation_unit.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_LLVM_COMPILATION_UNIT_H_
-#define ART_COMPILER_LLVM_LLVM_COMPILATION_UNIT_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/mutex.h"
-#include "dex/compiler_internals.h"
-#include "driver/compiler_driver.h"
-#include "driver/dex_compilation_unit.h"
-#include "globals.h"
-#include "instruction_set.h"
-#include "runtime_support_builder.h"
-#include "runtime_support_llvm_func.h"
-#include "safe_map.h"
-
-namespace art {
-  class CompiledMethod;
-}
-
-namespace llvm {
-  class Function;
-  class LLVMContext;
-  class Module;
-  class raw_ostream;
-}
-
-namespace art {
-namespace llvm {
-
-class CompilerLLVM;
-class IRBuilder;
-
-class LlvmCompilationUnit {
- public:
-  ~LlvmCompilationUnit();
-
-  uint32_t GetCompilationUnitId() const {
-    return cunit_id_;
-  }
-
-  InstructionSet GetInstructionSet() const;
-
-  ::llvm::LLVMContext* GetLLVMContext() const {
-    return context_.get();
-  }
-
-  ::llvm::Module* GetModule() const {
-    return module_;
-  }
-
-  IRBuilder* GetIRBuilder() const {
-    return irb_.get();
-  }
-
-  void SetBitcodeFileName(const std::string& bitcode_filename) {
-    bitcode_filename_ = bitcode_filename;
-  }
-
-  LLVMInfo* GetQuickContext() const {
-    return llvm_info_.get();
-  }
-  void SetCompilerDriver(CompilerDriver* driver) {
-    driver_ = driver;
-  }
-  DexCompilationUnit* GetDexCompilationUnit() {
-    return dex_compilation_unit_;
-  }
-  void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) {
-    dex_compilation_unit_ = dex_compilation_unit;
-  }
-
-  bool Materialize();
-
-  bool IsMaterialized() const {
-    return !elf_object_.empty();
-  }
-
-  const std::string& GetElfObject() const {
-    DCHECK(IsMaterialized());
-    return elf_object_;
-  }
-
- private:
-  LlvmCompilationUnit(const CompilerLLVM* compiler_llvm,
-                      size_t cunit_id);
-
-  const CompilerLLVM* compiler_llvm_;
-  const size_t cunit_id_;
-
-  std::unique_ptr< ::llvm::LLVMContext> context_;
-  std::unique_ptr<IRBuilder> irb_;
-  std::unique_ptr<RuntimeSupportBuilder> runtime_support_;
-  ::llvm::Module* module_;  // Managed by context_
-  std::unique_ptr<IntrinsicHelper> intrinsic_helper_;
-  std::unique_ptr<LLVMInfo> llvm_info_;
-  CompilerDriver* driver_;
-  DexCompilationUnit* dex_compilation_unit_;
-
-  std::string bitcode_filename_;
-
-  std::string elf_object_;
-
-  SafeMap<const ::llvm::Function*, CompiledMethod*> compiled_methods_map_;
-
-  void CheckCodeAlign(uint32_t offset) const;
-
-  void DumpBitcodeToFile();
-  void DumpBitcodeToString(std::string& str_buffer);
-
-  bool MaterializeToString(std::string& str_buffer);
-  bool MaterializeToRawOStream(::llvm::raw_ostream& out_stream);
-
-  friend class CompilerLLVM;  // For LlvmCompilationUnit constructor
-};
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_LLVM_COMPILATION_UNIT_H_
diff --git a/compiler/llvm/llvm_compiler.cc b/compiler/llvm/llvm_compiler.cc
deleted file mode 100644
index 55af614..0000000
--- a/compiler/llvm/llvm_compiler.cc
+++ /dev/null
@@ -1,161 +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.
- */
-
-#include "llvm_compiler.h"
-
-#ifdef ART_USE_PORTABLE_COMPILER
-#include "compiler.h"
-#include "compiler_llvm.h"
-#include "dex/portable/mir_to_gbc.h"
-#include "dex_file.h"
-#include "elf_writer_mclinker.h"
-#include "mirror/art_method-inl.h"
-#endif
-
-namespace art {
-
-#ifdef ART_USE_PORTABLE_COMPILER
-
-namespace llvm {
-
-// Thread-local storage compiler worker threads
-class LLVMCompilerTls : public CompilerTls {
-  public:
-    LLVMCompilerTls() : llvm_info_(nullptr) {}
-    ~LLVMCompilerTls() {}
-
-    void* GetLLVMInfo() { return llvm_info_; }
-
-    void SetLLVMInfo(void* llvm_info) { llvm_info_ = llvm_info; }
-
-  private:
-    void* llvm_info_;
-};
-
-
-
-class LLVMCompiler FINAL : public Compiler {
- public:
-  explicit LLVMCompiler(CompilerDriver* driver) : Compiler(driver, 1000) {}
-
-  CompilerTls* CreateNewCompilerTls() {
-    return new LLVMCompilerTls();
-  }
-
-  void Init() const OVERRIDE {
-    ArtInitCompilerContext(GetCompilerDriver());
-  }
-
-  void UnInit() const OVERRIDE {
-    ArtUnInitCompilerContext(GetCompilerDriver());
-  }
-
-  bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const
-      OVERRIDE {
-    return true;
-  }
-
-  CompiledMethod* Compile(const DexFile::CodeItem* code_item,
-                          uint32_t access_flags,
-                          InvokeType invoke_type,
-                          uint16_t class_def_idx,
-                          uint32_t method_idx,
-                          jobject class_loader,
-                          const DexFile& dex_file) const OVERRIDE {
-    CompiledMethod* method = TryCompileWithSeaIR(code_item,
-                                                 access_flags,
-                                                 invoke_type,
-                                                 class_def_idx,
-                                                 method_idx,
-                                                 class_loader,
-                                                 dex_file);
-    if (method != nullptr) {
-      return method;
-    }
-
-    return ArtCompileMethod(GetCompilerDriver(),
-                            code_item,
-                            access_flags,
-                            invoke_type,
-                            class_def_idx,
-                            method_idx,
-                            class_loader,
-                            dex_file);
-  }
-
-  CompiledMethod* JniCompile(uint32_t access_flags,
-                             uint32_t method_idx,
-                             const DexFile& dex_file) const OVERRIDE {
-    return ArtLLVMJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file);
-  }
-
-  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
-    return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
-  }
-
-  bool WriteElf(art::File* file,
-                OatWriter* oat_writer,
-                const std::vector<const art::DexFile*>& dex_files,
-                const std::string& android_root,
-                bool is_host, const CompilerDriver& driver) const
-      OVERRIDE
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return art::ElfWriterMclinker::Create(
-        file, oat_writer, dex_files, android_root, is_host, driver);
-  }
-
-  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
-    return PortableCodeGenerator(
-        cu, cu->mir_graph.get(), &cu->arena,
-        reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit));
-  }
-
-  void InitCompilationUnit(CompilationUnit& cu) const {
-      // Fused long branches not currently useful in bitcode.
-    cu.disable_opt |=
-        (1 << kBranchFusing) |
-        (1 << kSuppressExceptionEdges);
-  }
-
-  bool IsPortable() const OVERRIDE {
-    return true;
-  }
-
-  void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
-    typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&);
-
-    SetBitcodeFileNameFn set_bitcode_file_name =
-      reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
-
-    set_bitcode_file_name(driver, filename);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LLVMCompiler);
-};
-
-}  // namespace llvm
-#endif
-
-Compiler* CreateLLVMCompiler(CompilerDriver* driver) {
-#ifdef ART_USE_PORTABLE_COMPILER
-      return new llvm::LLVMCompiler(driver);
-#else
-      return nullptr;
-#endif
-}
-
-}  // namespace art
diff --git a/compiler/llvm/llvm_compiler.h b/compiler/llvm/llvm_compiler.h
deleted file mode 100644
index da6d0e9..0000000
--- a/compiler/llvm/llvm_compiler.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_LLVM_COMPILER_H_
-#define ART_COMPILER_LLVM_LLVM_COMPILER_H_
-
-namespace art {
-
-class Compiler;
-class CompilerDriver;
-
-Compiler* CreateLLVMCompiler(CompilerDriver* driver);
-
-}
-
-#endif  // ART_COMPILER_LLVM_LLVM_COMPILER_H_
diff --git a/compiler/llvm/md_builder.cc b/compiler/llvm/md_builder.cc
deleted file mode 100644
index 4331557..0000000
--- a/compiler/llvm/md_builder.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "md_builder.h"
-
-#include "llvm/IR/MDBuilder.h"
-
-#include <string>
-
-namespace art {
-namespace llvm {
-
-
-::llvm::MDNode* MDBuilder::GetTBAASpecialType(TBAASpecialType sty_id) {
-  DCHECK_GE(sty_id, 0) << "Unknown TBAA special type: " << sty_id;
-  DCHECK_LT(sty_id, MAX_TBAA_SPECIAL_TYPE) << "Unknown TBAA special type: " << sty_id;
-  DCHECK(tbaa_root_ != NULL);
-
-  ::llvm::MDNode*& spec_ty = tbaa_special_type_[sty_id];
-  if (spec_ty == NULL) {
-    switch (sty_id) {
-    case kTBAARegister:
-      spec_ty = createTBAANode("Register", tbaa_root_);
-      break;
-    case kTBAAStackTemp:
-      spec_ty = createTBAANode("StackTemp", tbaa_root_);
-      break;
-    case kTBAAHeapArray:
-      spec_ty = createTBAANode("HeapArray", tbaa_root_);
-      break;
-    case kTBAAHeapInstance:
-      spec_ty = createTBAANode("HeapInstance", tbaa_root_);
-      break;
-    case kTBAAHeapStatic:
-      spec_ty = createTBAANode("HeapStatic", tbaa_root_);
-      break;
-    case kTBAAJRuntime:
-      spec_ty = createTBAANode("JRuntime", tbaa_root_);
-      break;
-    case kTBAARuntimeInfo:
-      spec_ty = createTBAANode("RuntimeInfo", GetTBAASpecialType(kTBAAJRuntime));
-      break;
-    case kTBAAShadowFrame:
-      spec_ty = createTBAANode("ShadowFrame", GetTBAASpecialType(kTBAAJRuntime));
-      break;
-    case kTBAAConstJObject:
-      spec_ty = createTBAANode("ConstJObject", tbaa_root_, true);
-      break;
-    default:
-      LOG(FATAL) << "Unknown TBAA special type: " << sty_id;
-      break;
-    }
-  }
-  return spec_ty;
-}
-
-::llvm::MDNode* MDBuilder::GetTBAAMemoryJType(TBAASpecialType sty_id, JType jty_id) {
-  DCHECK(sty_id == kTBAAHeapArray ||
-         sty_id == kTBAAHeapInstance ||
-         sty_id == kTBAAHeapStatic) << "SpecialType must be array, instance, or static";
-
-  DCHECK_GE(jty_id, 0) << "Unknown JType: " << jty_id;
-  DCHECK_LT(jty_id, MAX_JTYPE) << "Unknown JType: " << jty_id;
-  DCHECK_NE(jty_id, kVoid) << "Can't load/store Void type!";
-
-  std::string name;
-  size_t sty_mapped_index = 0;
-  switch (sty_id) {
-  case kTBAAHeapArray:    sty_mapped_index = 0; name = "HeapArray "; break;
-  case kTBAAHeapInstance: sty_mapped_index = 1; name = "HeapInstance "; break;
-  case kTBAAHeapStatic:   sty_mapped_index = 2; name = "HeapStatic "; break;
-  default:
-    LOG(FATAL) << "Unknown TBAA special type: " << sty_id;
-    break;
-  }
-
-  ::llvm::MDNode*& spec_ty = tbaa_memory_jtype_[sty_mapped_index][jty_id];
-  if (spec_ty != NULL) {
-    return spec_ty;
-  }
-
-  switch (jty_id) {
-  case kBoolean: name += "Boolean"; break;
-  case kByte:    name += "Byte"; break;
-  case kChar:    name += "Char"; break;
-  case kShort:   name += "Short"; break;
-  case kInt:     name += "Int"; break;
-  case kLong:    name += "Long"; break;
-  case kFloat:   name += "Float"; break;
-  case kDouble:  name += "Double"; break;
-  case kObject:  name += "Object"; break;
-  default:
-    LOG(FATAL) << "Unknown JType: " << jty_id;
-    break;
-  }
-
-  spec_ty = createTBAANode(name, GetTBAASpecialType(sty_id));
-  return spec_ty;
-}
-
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/md_builder.h b/compiler/llvm/md_builder.h
deleted file mode 100644
index 1246f9b..0000000
--- a/compiler/llvm/md_builder.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_MD_BUILDER_H_
-#define ART_COMPILER_LLVM_MD_BUILDER_H_
-
-#include "backend_types.h"
-
-#include "llvm/IR/MDBuilder.h"
-
-#include <cstring>
-
-namespace llvm {
-  class LLVMContext;
-  class MDNode;
-}
-
-namespace art {
-namespace llvm {
-
-typedef ::llvm::MDBuilder LLVMMDBuilder;
-
-class MDBuilder : public LLVMMDBuilder {
- public:
-  explicit MDBuilder(::llvm::LLVMContext& context)
-     : LLVMMDBuilder(context), tbaa_root_(createTBAARoot("Art TBAA Root")) {
-    std::memset(tbaa_special_type_, 0, sizeof(tbaa_special_type_));
-    std::memset(tbaa_memory_jtype_, 0, sizeof(tbaa_memory_jtype_));
-
-    // Pre-generate the MDNode for static branch prediction
-    // 64 and 4 are the llvm.expect's default values
-    expect_cond_[kLikely] = createBranchWeights(64, 4);
-    expect_cond_[kUnlikely] = createBranchWeights(4, 64);
-  }
-
-  ::llvm::MDNode* GetTBAASpecialType(TBAASpecialType special_ty);
-  ::llvm::MDNode* GetTBAAMemoryJType(TBAASpecialType special_ty, JType j_ty);
-
-  ::llvm::MDNode* GetBranchWeights(ExpectCond expect) {
-    DCHECK_LT(expect, MAX_EXPECT) << "MAX_EXPECT is not for branch weight";
-    return expect_cond_[expect];
-  }
-
- private:
-  ::llvm::MDNode* const tbaa_root_;
-  ::llvm::MDNode* tbaa_special_type_[MAX_TBAA_SPECIAL_TYPE];
-  // There are 3 categories of memory types will not alias: array element, instance field, and
-  // static field.
-  ::llvm::MDNode* tbaa_memory_jtype_[3][MAX_JTYPE];
-
-  ::llvm::MDNode* expect_cond_[MAX_EXPECT];
-};
-
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_MD_BUILDER_H_
diff --git a/compiler/llvm/runtime_support_builder.cc b/compiler/llvm/runtime_support_builder.cc
deleted file mode 100644
index c825fbf..0000000
--- a/compiler/llvm/runtime_support_builder.cc
+++ /dev/null
@@ -1,202 +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 "runtime_support_builder.h"
-
-#include "gc/accounting/card_table.h"
-#include "ir_builder.h"
-#include "monitor.h"
-#include "mirror/object.h"
-#include "runtime_support_llvm_func_list.h"
-#include "thread.h"
-
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/Type.h>
-
-using ::llvm::BasicBlock;
-using ::llvm::CallInst;
-using ::llvm::Function;
-using ::llvm::Value;
-
-namespace art {
-namespace llvm {
-
-RuntimeSupportBuilder::RuntimeSupportBuilder(::llvm::LLVMContext& context,
-                                             ::llvm::Module& module,
-                                             IRBuilder& irb)
-    : context_(context), module_(module), irb_(irb) {
-  memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_));
-#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
-  do { \
-    ::llvm::Function* fn = module_.getFunction(#NAME); \
-    DCHECK(fn != NULL) << "Function not found: " << #NAME; \
-    runtime_support_func_decls_[runtime_support::ID] = fn; \
-  } while (0);
-
-  RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
-}
-
-
-/* Thread */
-
-::llvm::Value* RuntimeSupportBuilder::EmitGetCurrentThread() {
-  Function* func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
-  CallInst* call_inst = irb_.CreateCall(func);
-  call_inst->setOnlyReadsMemory();
-  irb_.SetTBAA(call_inst, kTBAAConstJObject);
-  return call_inst;
-}
-
-::llvm::Value* RuntimeSupportBuilder::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
-                                                             TBAASpecialType s_ty) {
-  Value* thread = EmitGetCurrentThread();
-  return irb_.LoadFromObjectOffset(thread, offset, type, s_ty);
-}
-
-void RuntimeSupportBuilder::EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value,
-                                                    TBAASpecialType s_ty) {
-  Value* thread = EmitGetCurrentThread();
-  irb_.StoreToObjectOffset(thread, offset, value, s_ty);
-}
-
-::llvm::Value* RuntimeSupportBuilder::EmitSetCurrentThread(::llvm::Value* thread) {
-  Function* func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread);
-  return irb_.CreateCall(func, thread);
-}
-
-
-/* ShadowFrame */
-
-::llvm::Value* RuntimeSupportBuilder::EmitPushShadowFrame(::llvm::Value* new_shadow_frame,
-                                                        ::llvm::Value* method,
-                                                        uint32_t num_vregs) {
-  Value* old_shadow_frame = EmitLoadFromThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
-                                                     irb_.getArtFrameTy()->getPointerTo(),
-                                                     kTBAARuntimeInfo);
-  EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
-                          new_shadow_frame,
-                          kTBAARuntimeInfo);
-
-  // Store the method pointer
-  irb_.StoreToObjectOffset(new_shadow_frame,
-                           ShadowFrame::MethodOffset(),
-                           method,
-                           kTBAAShadowFrame);
-
-  // Store the number of vregs
-  irb_.StoreToObjectOffset(new_shadow_frame,
-                           ShadowFrame::NumberOfVRegsOffset(),
-                           irb_.getInt32(num_vregs),
-                           kTBAAShadowFrame);
-
-  // Store the link to previous shadow frame
-  irb_.StoreToObjectOffset(new_shadow_frame,
-                           ShadowFrame::LinkOffset(),
-                           old_shadow_frame,
-                           kTBAAShadowFrame);
-
-  return old_shadow_frame;
-}
-
-::llvm::Value*
-RuntimeSupportBuilder::EmitPushShadowFrameNoInline(::llvm::Value* new_shadow_frame,
-                                                   ::llvm::Value* method,
-                                                   uint32_t num_vregs) {
-  Function* func = GetRuntimeSupportFunction(runtime_support::PushShadowFrame);
-  ::llvm::CallInst* call_inst =
-      irb_.CreateCall4(func,
-                       EmitGetCurrentThread(),
-                       new_shadow_frame,
-                       method,
-                       irb_.getInt32(num_vregs));
-  irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
-  return call_inst;
-}
-
-void RuntimeSupportBuilder::EmitPopShadowFrame(::llvm::Value* old_shadow_frame) {
-  // Store old shadow frame to TopShadowFrame
-  EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
-                          old_shadow_frame,
-                          kTBAARuntimeInfo);
-}
-
-
-/* Exception */
-
-::llvm::Value* RuntimeSupportBuilder::EmitGetAndClearException() {
-  Function* slow_func = GetRuntimeSupportFunction(runtime_support::GetAndClearException);
-  return irb_.CreateCall(slow_func, EmitGetCurrentThread());
-}
-
-::llvm::Value* RuntimeSupportBuilder::EmitIsExceptionPending() {
-  Value* exception = EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
-                                              irb_.getJObjectTy(),
-                                              kTBAARuntimeInfo);
-  // If exception not null
-  return irb_.CreateIsNotNull(exception);
-}
-
-
-/* Suspend */
-
-void RuntimeSupportBuilder::EmitTestSuspend() {
-  Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
-  CallInst* call_inst = irb_.CreateCall(slow_func, EmitGetCurrentThread());
-  irb_.SetTBAA(call_inst, kTBAAJRuntime);
-}
-
-
-/* Monitor */
-
-void RuntimeSupportBuilder::EmitLockObject(::llvm::Value* object) {
-  Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject);
-  irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
-}
-
-void RuntimeSupportBuilder::EmitUnlockObject(::llvm::Value* object) {
-  Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject);
-  irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
-}
-
-
-void RuntimeSupportBuilder::EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr) {
-  Function* parent_func = irb_.GetInsertBlock()->getParent();
-  BasicBlock* bb_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", parent_func);
-  BasicBlock* bb_cont = BasicBlock::Create(context_, "mark_gc_card_cont", parent_func);
-
-  ::llvm::Value* not_null = irb_.CreateIsNotNull(value);
-  irb_.CreateCondBr(not_null, bb_mark_gc_card, bb_cont);
-
-  irb_.SetInsertPoint(bb_mark_gc_card);
-  Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(),
-                                               irb_.getInt8Ty()->getPointerTo(),
-                                               kTBAAConstJObject);
-  Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
-  Value* card_no = irb_.CreateLShr(target_addr_int,
-                                   irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift));
-  Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
-  irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry,
-                   kTBAARuntimeInfo);
-  irb_.CreateBr(bb_cont);
-
-  irb_.SetInsertPoint(bb_cont);
-}
-
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/runtime_support_builder.h b/compiler/llvm/runtime_support_builder.h
deleted file mode 100644
index 898611a..0000000
--- a/compiler/llvm/runtime_support_builder.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
-#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
-
-#include "backend_types.h"
-#include "base/logging.h"
-#include "runtime_support_llvm_func.h"
-
-#include <stdint.h>
-
-namespace llvm {
-  class LLVMContext;
-  class Module;
-  class Function;
-  class Type;
-  class Value;
-}
-
-namespace art {
-namespace llvm {
-
-class IRBuilder;
-
-
-class RuntimeSupportBuilder {
- public:
-  RuntimeSupportBuilder(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb);
-
-  /* Thread */
-  virtual ::llvm::Value* EmitGetCurrentThread();
-  virtual ::llvm::Value* EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
-                                                TBAASpecialType s_ty);
-  virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value,
-                                       TBAASpecialType s_ty);
-  virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread);
-
-  /* ShadowFrame */
-  virtual ::llvm::Value* EmitPushShadowFrame(::llvm::Value* new_shadow_frame,
-                                           ::llvm::Value* method, uint32_t num_vregs);
-  virtual ::llvm::Value* EmitPushShadowFrameNoInline(::llvm::Value* new_shadow_frame,
-                                                   ::llvm::Value* method, uint32_t num_vregs);
-  virtual void EmitPopShadowFrame(::llvm::Value* old_shadow_frame);
-
-  /* Exception */
-  virtual ::llvm::Value* EmitGetAndClearException();
-  virtual ::llvm::Value* EmitIsExceptionPending();
-
-  /* Suspend */
-  virtual void EmitTestSuspend();
-
-  /* Monitor */
-  void EmitLockObject(::llvm::Value* object);
-  void EmitUnlockObject(::llvm::Value* object);
-
-  /* MarkGCCard */
-  virtual void EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr);
-
-  ::llvm::Function* GetRuntimeSupportFunction(runtime_support::RuntimeId id) {
-    if (id >= 0 && id < runtime_support::MAX_ID) {
-      return runtime_support_func_decls_[id];
-    } else {
-      LOG(ERROR) << "Unknown runtime function id: " << id;
-      return NULL;
-    }
-  }
-
-  virtual ~RuntimeSupportBuilder() {}
-
- protected:
-  ::llvm::LLVMContext& context_;
-  ::llvm::Module& module_;
-  IRBuilder& irb_;
-
- private:
-  ::llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID];
-  bool target_runtime_support_func_[runtime_support::MAX_ID];
-};
-
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
diff --git a/compiler/llvm/runtime_support_builder_arm.cc b/compiler/llvm/runtime_support_builder_arm.cc
deleted file mode 100644
index cad4624..0000000
--- a/compiler/llvm/runtime_support_builder_arm.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "runtime_support_builder_arm.h"
-
-#include "ir_builder.h"
-#include "thread.h"
-#include "utils_llvm.h"
-
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/InlineAsm.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/Type.h>
-
-#include <vector>
-
-using ::llvm::CallInst;
-using ::llvm::Function;
-using ::llvm::FunctionType;
-using ::llvm::InlineAsm;
-using ::llvm::IntegerType;
-using ::llvm::Type;
-using ::llvm::Value;
-
-namespace {
-
-char LDRSTRSuffixByType(art::llvm::IRBuilder& irb, Type* type) {
-  int width = type->isPointerTy() ?
-              irb.getSizeOfPtrEquivInt()*8 :
-              ::llvm::cast<IntegerType>(type)->getBitWidth();
-  switch (width) {
-    case 8:  return 'b';
-    case 16: return 'h';
-    case 32: return ' ';
-    default:
-      LOG(FATAL) << "Unsupported width: " << width;
-      return ' ';
-  }
-}
-
-}  // namespace
-
-namespace art {
-namespace llvm {
-
-/* Thread */
-
-Value* RuntimeSupportBuilderARM::EmitGetCurrentThread() {
-  Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
-  InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), "mov $0, r9", "=r", false);
-  CallInst* thread = irb_.CreateCall(func);
-  thread->setDoesNotAccessMemory();
-  irb_.SetTBAA(thread, kTBAAConstJObject);
-  return thread;
-}
-
-Value* RuntimeSupportBuilderARM::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
-                                                          TBAASpecialType s_ty) {
-  FunctionType* func_ty = FunctionType::get(/*Result=*/type,
-                                            /*isVarArg=*/false);
-  std::string inline_asm(StringPrintf("ldr%c $0, [r9, #%d]",
-                                      LDRSTRSuffixByType(irb_, type),
-                                      static_cast<int>(offset)));
-  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "=r", true);
-  CallInst* result = irb_.CreateCall(func);
-  result->setOnlyReadsMemory();
-  irb_.SetTBAA(result, s_ty);
-  return result;
-}
-
-void RuntimeSupportBuilderARM::EmitStoreToThreadOffset(int64_t offset, Value* value,
-                                                       TBAASpecialType s_ty) {
-  FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_),
-                                            /*Params=*/value->getType(),
-                                            /*isVarArg=*/false);
-  std::string inline_asm(StringPrintf("str%c $0, [r9, #%d]",
-                                      LDRSTRSuffixByType(irb_, value->getType()),
-                                      static_cast<int>(offset)));
-  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "r", true);
-  CallInst* call_inst = irb_.CreateCall(func, value);
-  irb_.SetTBAA(call_inst, s_ty);
-}
-
-Value* RuntimeSupportBuilderARM::EmitSetCurrentThread(Value* thread) {
-  // Separate to two InlineAsm: The first one produces the return value, while the second,
-  // sets the current thread.
-  // LLVM can delete the first one if the caller in LLVM IR doesn't use the return value.
-  //
-  // Here we don't call EmitGetCurrentThread, because we mark it as DoesNotAccessMemory and
-  // ConstJObject. We denote side effect to "true" below instead, so LLVM won't
-  // reorder these instructions incorrectly.
-  Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
-  InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), "mov $0, r9", "=r", true);
-  CallInst* old_thread_register = irb_.CreateCall(func);
-  old_thread_register->setOnlyReadsMemory();
-
-  FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_),
-                                            /*Params=*/irb_.getJObjectTy(),
-                                            /*isVarArg=*/false);
-  func = InlineAsm::get(func_ty, "mov r9, $0", "r", true);
-  irb_.CreateCall(func, thread);
-  return old_thread_register;
-}
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/runtime_support_builder_arm.h b/compiler/llvm/runtime_support_builder_arm.h
deleted file mode 100644
index 0d01509..0000000
--- a/compiler/llvm/runtime_support_builder_arm.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
-#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
-
-#include "runtime_support_builder.h"
-
-namespace art {
-namespace llvm {
-
-class RuntimeSupportBuilderARM : public RuntimeSupportBuilder {
- public:
-  RuntimeSupportBuilderARM(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb)
-    : RuntimeSupportBuilder(context, module, irb) {}
-
-  /* Thread */
-  virtual ::llvm::Value* EmitGetCurrentThread();
-  virtual ::llvm::Value* EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
-                                                TBAASpecialType s_ty);
-  virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value,
-                                       TBAASpecialType s_ty);
-  virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread);
-};
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
diff --git a/compiler/llvm/runtime_support_builder_x86.cc b/compiler/llvm/runtime_support_builder_x86.cc
deleted file mode 100644
index 3d11f9d..0000000
--- a/compiler/llvm/runtime_support_builder_x86.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "runtime_support_builder_x86.h"
-
-#include "base/stringprintf.h"
-#include "ir_builder.h"
-#include "thread.h"
-#include "utils_llvm.h"
-
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/InlineAsm.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/Type.h>
-
-#include <vector>
-
-using ::llvm::CallInst;
-using ::llvm::Function;
-using ::llvm::FunctionType;
-using ::llvm::InlineAsm;
-using ::llvm::Type;
-using ::llvm::UndefValue;
-using ::llvm::Value;
-
-namespace art {
-namespace llvm {
-
-
-Value* RuntimeSupportBuilderX86::EmitGetCurrentThread() {
-  Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
-  std::string inline_asm(StringPrintf("mov %%fs:%d, $0", Thread::SelfOffset().Int32Value()));
-  InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), inline_asm, "=r", false);
-  CallInst* thread = irb_.CreateCall(func);
-  thread->setDoesNotAccessMemory();
-  irb_.SetTBAA(thread, kTBAAConstJObject);
-  return thread;
-}
-
-Value* RuntimeSupportBuilderX86::EmitLoadFromThreadOffset(int64_t offset, Type* type,
-                                                          TBAASpecialType s_ty) {
-  FunctionType* func_ty = FunctionType::get(/*Result=*/type,
-                                            /*isVarArg=*/false);
-  std::string inline_asm(StringPrintf("mov %%fs:%d, $0", static_cast<int>(offset)));
-  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "=r", true);
-  CallInst* result = irb_.CreateCall(func);
-  result->setOnlyReadsMemory();
-  irb_.SetTBAA(result, s_ty);
-  return result;
-}
-
-void RuntimeSupportBuilderX86::EmitStoreToThreadOffset(int64_t offset, Value* value,
-                                                       TBAASpecialType s_ty) {
-  FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_),
-                                            /*Params=*/value->getType(),
-                                            /*isVarArg=*/false);
-  std::string inline_asm(StringPrintf("mov $0, %%fs:%d", static_cast<int>(offset)));
-  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "r", true);
-  CallInst* call_inst = irb_.CreateCall(func, value);
-  irb_.SetTBAA(call_inst, s_ty);
-}
-
-Value* RuntimeSupportBuilderX86::EmitSetCurrentThread(Value*) {
-  /* Nothing to be done. */
-  return UndefValue::get(irb_.getJObjectTy());
-}
-
-
-}  // namespace llvm
-}  // namespace art
diff --git a/compiler/llvm/runtime_support_builder_x86.h b/compiler/llvm/runtime_support_builder_x86.h
deleted file mode 100644
index 5f36e7c..0000000
--- a/compiler/llvm/runtime_support_builder_x86.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
-#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
-
-#include "runtime_support_builder.h"
-
-namespace art {
-namespace llvm {
-
-class RuntimeSupportBuilderX86 : public RuntimeSupportBuilder {
- public:
-  RuntimeSupportBuilderX86(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb)
-    : RuntimeSupportBuilder(context, module, irb) {}
-
-  /* Thread */
-  virtual ::llvm::Value* EmitGetCurrentThread();
-  virtual ::llvm::Value* EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
-                                                TBAASpecialType s_ty);
-  virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value,
-                                       TBAASpecialType s_ty);
-  virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread);
-};
-
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
diff --git a/compiler/llvm/runtime_support_llvm_func.h b/compiler/llvm/runtime_support_llvm_func.h
deleted file mode 100644
index a5ad852..0000000
--- a/compiler/llvm/runtime_support_llvm_func.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_H_
-#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_H_
-
-#include "runtime_support_llvm_func_list.h"
-
-namespace art {
-namespace llvm {
-namespace runtime_support {
-
-  enum RuntimeId {
-#define DEFINE_RUNTIME_SUPPORT_FUNC_ID(ID, NAME) ID,
-    RUNTIME_SUPPORT_FUNC_LIST(DEFINE_RUNTIME_SUPPORT_FUNC_ID)
-
-    MAX_ID
-  };
-
-}  // namespace runtime_support
-}  // namespace llvm
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_H_
diff --git a/compiler/llvm/runtime_support_llvm_func_list.h b/compiler/llvm/runtime_support_llvm_func_list.h
deleted file mode 100644
index b5ac1ff..0000000
--- a/compiler/llvm/runtime_support_llvm_func_list.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_
-#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_
-
-#define RUNTIME_SUPPORT_FUNC_LIST(V) \
-  V(LockObject, art_portable_lock_object_from_code) \
-  V(UnlockObject, art_portable_unlock_object_from_code) \
-  V(GetCurrentThread, art_portable_get_current_thread_from_code) \
-  V(SetCurrentThread, art_portable_set_current_thread_from_code) \
-  V(PushShadowFrame, art_portable_push_shadow_frame_from_code) \
-  V(PopShadowFrame, art_portable_pop_shadow_frame_from_code) \
-  V(TestSuspend, art_portable_test_suspend_from_code) \
-  V(ThrowException, art_portable_throw_exception_from_code) \
-  V(ThrowStackOverflowException, art_portable_throw_stack_overflow_from_code) \
-  V(ThrowNullPointerException, art_portable_throw_null_pointer_exception_from_code) \
-  V(ThrowDivZeroException, art_portable_throw_div_zero_from_code) \
-  V(ThrowIndexOutOfBounds, art_portable_throw_array_bounds_from_code) \
-  V(InitializeTypeAndVerifyAccess, art_portable_initialize_type_and_verify_access_from_code) \
-  V(InitializeType, art_portable_initialize_type_from_code) \
-  V(IsAssignable, art_portable_is_assignable_from_code) \
-  V(CheckCast, art_portable_check_cast_from_code) \
-  V(CheckPutArrayElement, art_portable_check_put_array_element_from_code) \
-  V(AllocObject, art_portable_alloc_object_from_code) \
-  V(AllocObjectWithAccessCheck, art_portable_alloc_object_from_code_with_access_check) \
-  V(AllocArray, art_portable_alloc_array_from_code) \
-  V(AllocArrayWithAccessCheck, art_portable_alloc_array_from_code_with_access_check) \
-  V(CheckAndAllocArray, art_portable_check_and_alloc_array_from_code) \
-  V(CheckAndAllocArrayWithAccessCheck, art_portable_check_and_alloc_array_from_code_with_access_check) \
-  V(FindStaticMethodWithAccessCheck, art_portable_find_static_method_from_code_with_access_check) \
-  V(FindDirectMethodWithAccessCheck, art_portable_find_direct_method_from_code_with_access_check) \
-  V(FindVirtualMethodWithAccessCheck, art_portable_find_virtual_method_from_code_with_access_check) \
-  V(FindSuperMethodWithAccessCheck, art_portable_find_super_method_from_code_with_access_check) \
-  V(FindInterfaceMethodWithAccessCheck, art_portable_find_interface_method_from_code_with_access_check) \
-  V(FindInterfaceMethod, art_portable_find_interface_method_from_code) \
-  V(ResolveString, art_portable_resolve_string_from_code) \
-  V(Set32Static, art_portable_set32_static_from_code) \
-  V(Set64Static, art_portable_set64_static_from_code) \
-  V(SetObjectStatic, art_portable_set_obj_static_from_code) \
-  V(Get32Static, art_portable_get32_static_from_code) \
-  V(Get64Static, art_portable_get64_static_from_code) \
-  V(GetObjectStatic, art_portable_get_obj_static_from_code) \
-  V(Set32Instance, art_portable_set32_instance_from_code) \
-  V(Set64Instance, art_portable_set64_instance_from_code) \
-  V(SetObjectInstance, art_portable_set_obj_instance_from_code) \
-  V(Get32Instance, art_portable_get32_instance_from_code) \
-  V(Get64Instance, art_portable_get64_instance_from_code) \
-  V(GetObjectInstance, art_portable_get_obj_instance_from_code) \
-  V(InitializeStaticStorage, art_portable_initialize_static_storage_from_code) \
-  V(FillArrayData, art_portable_fill_array_data_from_code) \
-  V(GetAndClearException, art_portable_get_and_clear_exception) \
-  V(IsExceptionPending, art_portable_is_exception_pending_from_code) \
-  V(FindCatchBlock, art_portable_find_catch_block_from_code) \
-  V(MarkGCCard, art_portable_mark_gc_card_from_code) \
-  V(ProxyInvokeHandler, art_portable_proxy_invoke_handler_from_code) \
-  V(art_d2l, art_d2l) \
-  V(art_d2i, art_d2i) \
-  V(art_f2l, art_f2l) \
-  V(art_f2i, art_f2i) \
-  V(JniMethodStart,                        art_portable_jni_method_start) \
-  V(JniMethodStartSynchronized,            art_portable_jni_method_start_synchronized) \
-  V(JniMethodEnd,                          art_portable_jni_method_end) \
-  V(JniMethodEndSynchronized,              art_portable_jni_method_end_synchronized) \
-  V(JniMethodEndWithReference,             art_portable_jni_method_end_with_reference) \
-  V(JniMethodEndWithReferenceSynchronized, art_portable_jni_method_end_with_reference_synchronized)
-
-#endif  // ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_
diff --git a/compiler/llvm/tools/gen_art_module_cc.sh b/compiler/llvm/tools/gen_art_module_cc.sh
deleted file mode 100755
index c5df333..0000000
--- a/compiler/llvm/tools/gen_art_module_cc.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash -e
-
-# 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.
-
-SCRIPTDIR=`dirname "$0"`
-cd "${SCRIPTDIR}/.."
-
-mkdir -p generated
-
-OUTPUT_FILE=generated/art_module.cc
-
-echo "// Generated with ${0}" > ${OUTPUT_FILE}
-
-echo '
-
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
-// TODO: Remove this pragma after llc can generate makeLLVMModuleContents()
-// with smaller frame size.
-
-#include <llvm/IR/DerivedTypes.h>
-#include <llvm/IR/Function.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/Type.h>
-
-#include <vector>
-
-using namespace llvm;
-
-namespace art {
-namespace llvm {
-
-' >> ${OUTPUT_FILE}
-
-llc -march=cpp -cppgen=contents art_module.ll -o - >> ${OUTPUT_FILE}
-
-echo '
-} // namespace llvm
-} // namespace art' >> ${OUTPUT_FILE}
diff --git a/compiler/llvm/utils_llvm.h b/compiler/llvm/utils_llvm.h
deleted file mode 100644
index a606b91..0000000
--- a/compiler/llvm/utils_llvm.h
+++ /dev/null
@@ -1,32 +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.
- */
-
-#ifndef ART_COMPILER_LLVM_UTILS_LLVM_H_
-#define ART_COMPILER_LLVM_UTILS_LLVM_H_
-
-#include <llvm/Analysis/Verifier.h>
-
-namespace art {
-
-#ifndef NDEBUG
-#define VERIFY_LLVM_FUNCTION(func) ::llvm::verifyFunction(func, ::llvm::AbortProcessAction)
-#else
-#define VERIFY_LLVM_FUNCTION(func)
-#endif
-
-}  // namespace art
-
-#endif  // ART_COMPILER_LLVM_UTILS_LLVM_H_
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 0b1f9e2..d3d2055 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "arch/instruction_set_features.h"
 #include "class_linker.h"
 #include "common_compiler_test.h"
 #include "compiler.h"
@@ -38,49 +39,32 @@
 
   void CheckMethod(mirror::ArtMethod* method,
                    const OatFile::OatMethod& oat_method,
-                   const DexFile* dex_file)
+                   const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const CompiledMethod* compiled_method =
-        compiler_driver_->GetCompiledMethod(MethodReference(dex_file,
+        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_EQ(oat_method.GetFrameSizeInBytes(), 0U);
       EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
       EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
     } else {
       const void* quick_oat_code = oat_method.GetQuickCode();
-      if (quick_oat_code != nullptr) {
-        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
-        EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
-        EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
-        uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(quick_oat_code), 2);
-        quick_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
-        const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-        EXPECT_TRUE(quick_code != nullptr);
-        size_t code_size = quick_code->size() * sizeof(quick_code[0]);
-        EXPECT_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size))
-            << PrettyMethod(method) << " " << code_size;
-        CHECK_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size));
-      } else {
-        const void* portable_oat_code = oat_method.GetPortableCode();
-        EXPECT_TRUE(portable_oat_code != nullptr) << PrettyMethod(method);
-        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U);
-        EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
-        EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
-        uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(portable_oat_code), 2);
-        portable_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
-        const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode();
-        EXPECT_TRUE(portable_code != nullptr);
-        size_t code_size = portable_code->size() * sizeof(portable_code[0]);
-        EXPECT_EQ(0, memcmp(quick_oat_code, &portable_code[0], code_size))
-            << PrettyMethod(method) << " " << code_size;
-        CHECK_EQ(0, memcmp(quick_oat_code, &portable_code[0], code_size));
-      }
+      EXPECT_TRUE(quick_oat_code != nullptr) << PrettyMethod(method);
+      EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
+      EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
+      EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
+      uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(quick_oat_code), 2);
+      quick_oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+      const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
+      EXPECT_TRUE(quick_code != nullptr);
+      size_t code_size = quick_code->size() * sizeof(quick_code[0]);
+      EXPECT_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size))
+          << PrettyMethod(method) << " " << code_size;
+      CHECK_EQ(0, memcmp(quick_oat_code, &quick_code[0], code_size));
     }
   }
 };
@@ -90,12 +74,13 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   // TODO: make selectable.
-  Compiler::Kind compiler_kind = kUsePortableCompiler
-      ? Compiler::kPortable
-      : Compiler::kQuick;
+  Compiler::Kind compiler_kind = Compiler::kQuick;
   InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
 
-  InstructionSetFeatures insn_features;
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> insn_features(
+      InstructionSetFeatures::FromVariant(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,12 +91,12 @@
                                             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, nullptr, 2, true,
+                                            true, "", timer_.get(), -1, ""));
+  jobject class_loader = nullptr;
   if (kCompile) {
-    TimingLogger timings("OatTest::WriteRead", false, false);
-    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
+    TimingLogger timings2("OatTest::WriteRead", false, false);
+    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2);
   }
 
   ScratchFile tmp;
@@ -135,9 +120,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,
+                                                  nullptr, false, &error_msg));
   ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_TRUE(oat_header.IsValid());
@@ -146,22 +130,23 @@
   ASSERT_EQ(4096U, oat_header.GetImageFileLocationOatDataBegin());
   ASSERT_EQ("lue.art", std::string(oat_header.GetStoreValueByKey(OatHeader::kImageLocationKey)));
 
-  const DexFile* dex_file = java_lang_dex_file_;
-  uint32_t dex_file_checksum = dex_file->GetLocationChecksum();
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file->GetLocation().c_str(),
+  ASSERT_TRUE(java_lang_dex_file_ != nullptr);
+  const DexFile& dex_file = *java_lang_dex_file_;
+  uint32_t dex_file_checksum = dex_file.GetLocationChecksum();
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
                                                                     &dex_file_checksum);
   ASSERT_TRUE(oat_dex_file != nullptr);
-  CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
+  CHECK_EQ(dex_file.GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
   ScopedObjectAccess soa(Thread::Current());
-  for (size_t i = 0; i < dex_file->NumClassDefs(); i++) {
-    const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-    const byte* class_data = dex_file->GetClassData(class_def);
+  for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
+    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) {
-      ClassDataItemIterator it(*dex_file, class_data);
+    if (class_data != nullptr) {
+      ClassDataItemIterator it(dex_file, class_data);
       num_virtual_methods = it.NumVirtualMethods();
     }
-    const char* descriptor = dex_file->GetClassDescriptor(class_def);
+    const char* descriptor = dex_file.GetClassDescriptor(class_def);
     StackHandleScope<1> hs(soa.Self());
     mirror::Class* klass = class_linker->FindClass(soa.Self(), descriptor,
                                                    NullHandle<mirror::ClassLoader>());
@@ -172,12 +157,12 @@
              oat_class.GetType()) << descriptor;
 
     size_t method_index = 0;
-    for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
-      CheckMethod(klass->GetDirectMethod(i),
+    for (size_t j = 0; j < klass->NumDirectMethods(); j++, method_index++) {
+      CheckMethod(klass->GetDirectMethod(j),
                   oat_class.GetOatMethod(method_index), dex_file);
     }
-    for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
-      CheckMethod(klass->GetVirtualMethod(i),
+    for (size_t j = 0; j < num_virtual_methods; j++, method_index++) {
+      CheckMethod(klass->GetVirtualMethod(j),
                   oat_class.GetOatMethod(method_index), dex_file);
     }
   }
@@ -186,20 +171,23 @@
 TEST_F(OatTest, OatHeaderSizeCheck) {
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
-  EXPECT_EQ(84U, sizeof(OatHeader));
-  EXPECT_EQ(8U, sizeof(OatMethodOffsets));
-  EXPECT_EQ(24U, sizeof(OatQuickMethodHeader));
+  EXPECT_EQ(72U, sizeof(OatHeader));
+  EXPECT_EQ(4U, sizeof(OatMethodOffsets));
+  EXPECT_EQ(28U, sizeof(OatQuickMethodHeader));
   EXPECT_EQ(91 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
 }
 
 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::FromVariant(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/oat_writer.cc b/compiler/oat_writer.cc
index dd64368..3c36ffa 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -38,6 +38,7 @@
 #include "scoped_thread_state_change.h"
 #include "handle_scope-inl.h"
 #include "utils/arm/assembler_thumb2.h"
+#include "utils/arm64/assembler_arm64.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
@@ -69,16 +70,18 @@
  public:
   NoRelativeCallPatcher() { }
 
-  uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE {
+  uint32_t ReserveSpace(uint32_t offset,
+                        const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE {
     return offset;  // No space reserved; no patches expected.
   }
 
-  uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
+  uint32_t WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) OVERRIDE {
     return offset;  // No thunks added; no patches expected.
   }
 
-  void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
-             uint32_t target_offset) OVERRIDE {
+  void Patch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, uint32_t literal_offset ATTRIBUTE_UNUSED,
+             uint32_t patch_offset ATTRIBUTE_UNUSED,
+             uint32_t target_offset ATTRIBUTE_UNUSED) OVERRIDE {
     LOG(FATAL) << "Unexpected relative patch.";
   }
 
@@ -90,11 +93,12 @@
  public:
   X86RelativeCallPatcher() { }
 
-  uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE {
+  uint32_t ReserveSpace(uint32_t offset,
+                        const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE {
     return offset;  // No space reserved; no limit on relative call distance.
   }
 
-  uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
+  uint32_t WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) OVERRIDE {
     return offset;  // No thunks added; no limit on relative call distance.
   }
 
@@ -117,10 +121,14 @@
   DISALLOW_COPY_AND_ASSIGN(X86RelativeCallPatcher);
 };
 
-class OatWriter::Thumb2RelativeCallPatcher FINAL : public RelativeCallPatcher {
+class OatWriter::ArmBaseRelativeCallPatcher : public RelativeCallPatcher {
  public:
-  explicit Thumb2RelativeCallPatcher(OatWriter* writer)
-      : writer_(writer), thunk_code_(CompileThunkCode()),
+  ArmBaseRelativeCallPatcher(OatWriter* writer,
+                             InstructionSet instruction_set, std::vector<uint8_t> thunk_code,
+                             uint32_t max_positive_displacement, uint32_t max_negative_displacement)
+      : writer_(writer), instruction_set_(instruction_set), thunk_code_(thunk_code),
+        max_positive_displacement_(max_positive_displacement),
+        max_negative_displacement_(max_negative_displacement),
         thunk_locations_(), current_thunk_to_write_(0u), unprocessed_patches_() {
   }
 
@@ -130,11 +138,11 @@
     // of code. To avoid any alignment discrepancies for the final chunk, we always align the
     // offset after reserving of writing any chunk.
     if (UNLIKELY(compiled_method == nullptr)) {
-      uint32_t aligned_offset = CompiledMethod::AlignCode(offset, kThumb2);
+      uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
       bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset);
       if (needs_thunk) {
         thunk_locations_.push_back(aligned_offset);
-        offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), kThumb2);
+        offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), instruction_set_);
       }
       return offset;
     }
@@ -143,14 +151,14 @@
     uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader);
     uint32_t next_aligned_offset = compiled_method->AlignCode(quick_code_offset + quick_code_size);
     if (!unprocessed_patches_.empty() &&
-        next_aligned_offset - unprocessed_patches_.front().second > kMaxPositiveDisplacement) {
+        next_aligned_offset - unprocessed_patches_.front().second > max_positive_displacement_) {
       bool needs_thunk = ReserveSpaceProcessPatches(next_aligned_offset);
       if (needs_thunk) {
         // A single thunk will cover all pending patches.
         unprocessed_patches_.clear();
         uint32_t thunk_location = compiled_method->AlignCode(offset);
         thunk_locations_.push_back(thunk_location);
-        offset = CompiledMethod::AlignCode(thunk_location + thunk_code_.size(), kThumb2);
+        offset = CompiledMethod::AlignCode(thunk_location + thunk_code_.size(), instruction_set_);
       }
     }
     for (const LinkerPatch& patch : compiled_method->GetPatches()) {
@@ -166,7 +174,7 @@
     if (current_thunk_to_write_ == thunk_locations_.size()) {
       return offset;
     }
-    uint32_t aligned_offset = CompiledMethod::AlignCode(offset, kThumb2);
+    uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
     if (UNLIKELY(aligned_offset == thunk_locations_[current_thunk_to_write_])) {
       ++current_thunk_to_write_;
       uint32_t aligned_code_delta = aligned_offset - offset;
@@ -179,7 +187,7 @@
       writer_->size_relative_call_thunks_ += thunk_code_.size();
       uint32_t thunk_end_offset = aligned_offset + thunk_code_.size();
       // Align after writing chunk, see the ReserveSpace() above.
-      offset = CompiledMethod::AlignCode(thunk_end_offset, kThumb2);
+      offset = CompiledMethod::AlignCode(thunk_end_offset, instruction_set_);
       aligned_code_delta = offset - thunk_end_offset;
       if (aligned_code_delta != 0u && !writer_->WriteCodeAlignment(out, aligned_code_delta)) {
         return 0u;
@@ -188,30 +196,88 @@
     return offset;
   }
 
-  void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
-             uint32_t target_offset) OVERRIDE {
-    DCHECK_LE(literal_offset + 4u, code->size());
-    DCHECK_EQ(literal_offset & 1u, 0u);
-    DCHECK_EQ(patch_offset & 1u, 0u);
-    DCHECK_EQ(target_offset & 1u, 1u);  // Thumb2 mode bit.
+ protected:
+  uint32_t CalculateDisplacement(uint32_t patch_offset, uint32_t target_offset) {
     // Unsigned arithmetic with its well-defined overflow behavior is just fine here.
-    uint32_t displacement = target_offset - 1u - patch_offset;
+    uint32_t displacement = target_offset - patch_offset;
     // NOTE: With unsigned arithmetic we do mean to use && rather than || below.
-    if (displacement > kMaxPositiveDisplacement && displacement < -kMaxNegativeDisplacement) {
+    if (displacement > max_positive_displacement_ && displacement < -max_negative_displacement_) {
       // Unwritten thunks have higher offsets, check if it's within range.
       DCHECK(current_thunk_to_write_ == thunk_locations_.size() ||
              thunk_locations_[current_thunk_to_write_] > patch_offset);
       if (current_thunk_to_write_ != thunk_locations_.size() &&
-          thunk_locations_[current_thunk_to_write_] - patch_offset < kMaxPositiveDisplacement) {
+          thunk_locations_[current_thunk_to_write_] - patch_offset < max_positive_displacement_) {
         displacement = thunk_locations_[current_thunk_to_write_] - patch_offset;
       } else {
         // We must have a previous thunk then.
         DCHECK_NE(current_thunk_to_write_, 0u);
         DCHECK_LT(thunk_locations_[current_thunk_to_write_ - 1], patch_offset);
         displacement = thunk_locations_[current_thunk_to_write_ - 1] - patch_offset;
-        DCHECK(displacement >= -kMaxNegativeDisplacement);
+        DCHECK(displacement >= -max_negative_displacement_);
       }
     }
+    return displacement;
+  }
+
+ private:
+  bool ReserveSpaceProcessPatches(uint32_t next_aligned_offset) {
+    // Process as many patches as possible, stop only on unresolved targets or calls too far back.
+    while (!unprocessed_patches_.empty()) {
+      uint32_t patch_offset = unprocessed_patches_.front().second;
+      auto it = writer_->method_offset_map_.find(unprocessed_patches_.front().first);
+      if (it == writer_->method_offset_map_.end()) {
+        // If still unresolved, check if we have a thunk within range.
+        DCHECK(thunk_locations_.empty() || thunk_locations_.back() <= patch_offset);
+        if (thunk_locations_.empty() ||
+            patch_offset - thunk_locations_.back() > max_negative_displacement_) {
+          return next_aligned_offset - patch_offset > max_positive_displacement_;
+        }
+      } else if (it->second >= patch_offset) {
+        DCHECK_LE(it->second - patch_offset, max_positive_displacement_);
+      } else {
+        // When calling back, check if we have a thunk that's closer than the actual target.
+        uint32_t target_offset = (thunk_locations_.empty() || it->second > thunk_locations_.back())
+            ? it->second
+            : thunk_locations_.back();
+        DCHECK_GT(patch_offset, target_offset);
+        if (patch_offset - target_offset > max_negative_displacement_) {
+          return true;
+        }
+      }
+      unprocessed_patches_.pop_front();
+    }
+    return false;
+  }
+
+  OatWriter* const writer_;
+  const InstructionSet instruction_set_;
+  const std::vector<uint8_t> thunk_code_;
+  const uint32_t max_positive_displacement_;
+  const uint32_t max_negative_displacement_;
+  std::vector<uint32_t> thunk_locations_;
+  size_t current_thunk_to_write_;
+
+  // ReserveSpace() tracks unprocessed patches.
+  typedef std::pair<MethodReference, uint32_t> UnprocessedPatch;
+  std::deque<UnprocessedPatch> unprocessed_patches_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativeCallPatcher);
+};
+
+class OatWriter::Thumb2RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatcher {
+ public:
+  explicit Thumb2RelativeCallPatcher(OatWriter* writer)
+      : ArmBaseRelativeCallPatcher(writer, kThumb2, CompileThunkCode(),
+                                   kMaxPositiveDisplacement, kMaxNegativeDisplacement) {
+  }
+
+  void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
+             uint32_t target_offset) OVERRIDE {
+    DCHECK_LE(literal_offset + 4u, code->size());
+    DCHECK_EQ(literal_offset & 1u, 0u);
+    DCHECK_EQ(patch_offset & 1u, 0u);
+    DCHECK_EQ(target_offset & 1u, 1u);  // Thumb2 mode bit.
+    uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u);
     displacement -= kPcDisplacement;  // The base PC is at the end of the 4-byte patch.
     DCHECK_EQ(displacement & 1u, 0u);
     DCHECK((displacement >> 24) == 0u || (displacement >> 24) == 255u);  // 25-bit signed.
@@ -237,42 +303,13 @@
   }
 
  private:
-  bool ReserveSpaceProcessPatches(uint32_t next_aligned_offset) {
-    // Process as many patches as possible, stop only on unresolved targets or calls too far back.
-    while (!unprocessed_patches_.empty()) {
-      uint32_t patch_offset = unprocessed_patches_.front().second;
-      auto it = writer_->method_offset_map_.find(unprocessed_patches_.front().first);
-      if (it == writer_->method_offset_map_.end()) {
-        // If still unresolved, check if we have a thunk within range.
-        DCHECK(thunk_locations_.empty() || thunk_locations_.back() <= patch_offset);
-        if (thunk_locations_.empty() ||
-            patch_offset - thunk_locations_.back() > kMaxNegativeDisplacement) {
-          return next_aligned_offset - patch_offset > kMaxPositiveDisplacement;
-        }
-      } else if (it->second >= patch_offset) {
-        DCHECK_LE(it->second - patch_offset, kMaxPositiveDisplacement);
-      } else {
-        // When calling back, check if we have a thunk that's closer than the actual target.
-        uint32_t target_offset = (thunk_locations_.empty() || it->second > thunk_locations_.back())
-            ? it->second
-            : thunk_locations_.back();
-        DCHECK_GT(patch_offset, target_offset);
-        if (patch_offset - target_offset > kMaxNegativeDisplacement) {
-          return true;
-        }
-      }
-      unprocessed_patches_.pop_front();
-    }
-    return false;
-  }
-
   static std::vector<uint8_t> CompileThunkCode() {
     // The thunk just uses the entry point in the ArtMethod. This works even for calls
     // to the generic JNI and interpreter trampolines.
     arm::Thumb2Assembler assembler;
     assembler.LoadFromOffset(
         arm::kLoadWord, arm::PC, arm::R0,
-        mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
+        mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
     assembler.bkpt(0);
     std::vector<uint8_t> thunk_code(assembler.CodeSize());
     MemoryRegion code(thunk_code.data(), thunk_code.size());
@@ -289,18 +326,63 @@
   static constexpr uint32_t kMaxPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement;
   static constexpr uint32_t kMaxNegativeDisplacement = (1u << 24) - kPcDisplacement;
 
-  OatWriter* const writer_;
-  const std::vector<uint8_t> thunk_code_;
-  std::vector<uint32_t> thunk_locations_;
-  size_t current_thunk_to_write_;
-
-  // ReserveSpace() tracks unprocessed patches.
-  typedef std::pair<MethodReference, uint32_t> UnprocessedPatch;
-  std::deque<UnprocessedPatch> unprocessed_patches_;
-
   DISALLOW_COPY_AND_ASSIGN(Thumb2RelativeCallPatcher);
 };
 
+class OatWriter::Arm64RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatcher {
+ public:
+  explicit Arm64RelativeCallPatcher(OatWriter* writer)
+      : ArmBaseRelativeCallPatcher(writer, kArm64, CompileThunkCode(),
+                                   kMaxPositiveDisplacement, kMaxNegativeDisplacement) {
+  }
+
+  void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset,
+             uint32_t target_offset) OVERRIDE {
+    DCHECK_LE(literal_offset + 4u, code->size());
+    DCHECK_EQ(literal_offset & 3u, 0u);
+    DCHECK_EQ(patch_offset & 3u, 0u);
+    DCHECK_EQ(target_offset & 3u, 0u);
+    uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u);
+    DCHECK_EQ(displacement & 3u, 0u);
+    DCHECK((displacement >> 27) == 0u || (displacement >> 27) == 31u);  // 28-bit signed.
+    uint32_t value = (displacement & 0x0fffffffu) >> 2;
+    value |= 0x94000000;  // BL
+
+    uint8_t* addr = &(*code)[literal_offset];
+    // Check that we're just overwriting an existing BL.
+    DCHECK_EQ(addr[3] & 0xfc, 0x94);
+    // Write the new BL.
+    addr[0] = (value >> 0) & 0xff;
+    addr[1] = (value >> 8) & 0xff;
+    addr[2] = (value >> 16) & 0xff;
+    addr[3] = (value >> 24) & 0xff;
+  }
+
+ private:
+  static std::vector<uint8_t> CompileThunkCode() {
+    // The thunk just uses the entry point in the ArtMethod. This works even for calls
+    // to the generic JNI and interpreter trampolines.
+    arm64::Arm64Assembler assembler;
+    Offset offset(mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+        kArm64PointerSize).Int32Value());
+    assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0));
+    // Ensure we emit the literal pool.
+    assembler.EmitSlowPaths();
+    std::vector<uint8_t> thunk_code(assembler.CodeSize());
+    MemoryRegion code(thunk_code.data(), thunk_code.size());
+    assembler.FinalizeInstructions(code);
+    return thunk_code;
+  }
+
+  // Maximum positive and negative displacement measured from the patch location.
+  // (Signed 28 bit displacement with the last bit 0 has range [-2^27, 2^27-4] measured from
+  // the ARM64 PC pointing to the BL.)
+  static constexpr uint32_t kMaxPositiveDisplacement = (1u << 27) - 4u;
+  static constexpr uint32_t kMaxNegativeDisplacement = (1u << 27);
+
+  DISALLOW_COPY_AND_ASSIGN(Arm64RelativeCallPatcher);
+};
+
 #define DCHECK_OFFSET() \
   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
@@ -335,9 +417,6 @@
     size_interpreter_to_interpreter_bridge_(0),
     size_interpreter_to_compiled_code_bridge_(0),
     size_jni_dlsym_lookup_(0),
-    size_portable_imt_conflict_trampoline_(0),
-    size_portable_resolution_trampoline_(0),
-    size_portable_to_interpreter_bridge_(0),
     size_quick_generic_jni_trampoline_(0),
     size_quick_imt_conflict_trampoline_(0),
     size_quick_resolution_trampoline_(0),
@@ -373,7 +452,8 @@
       relative_call_patcher_.reset(new Thumb2RelativeCallPatcher(this));
       break;
     case kArm64:
-      // TODO: Implement relative calls for arm64.
+      relative_call_patcher_.reset(new Arm64RelativeCallPatcher(this));
+      break;
     default:
       relative_call_patcher_.reset(new NoRelativeCallPatcher);
       break;
@@ -424,27 +504,30 @@
 }
 
 struct OatWriter::GcMapDataAccess {
-  static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
+  static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
     return compiled_method->GetGcMap();
   }
 
   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    return oat_class->method_offsets_[method_offsets_index].gc_map_offset_;
+    uint32_t offset = oat_class->method_headers_[method_offsets_index].gc_map_offset_;
+    return offset == 0u ? 0u :
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
       ALWAYS_INLINE {
-    oat_class->method_offsets_[method_offsets_index].gc_map_offset_ = offset;
+    oat_class->method_headers_[method_offsets_index].gc_map_offset_ =
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
-  static const char* Name() ALWAYS_INLINE {
+  static const char* Name() {
     return "GC map";
   }
 };
 
 struct OatWriter::MappingTableDataAccess {
-  static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
-    return &compiled_method->GetMappingTable();
+  static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
+    return compiled_method->GetMappingTable();
   }
 
   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
@@ -459,13 +542,13 @@
         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
-  static const char* Name() ALWAYS_INLINE {
+  static const char* Name() {
     return "mapping table";
   }
 };
 
 struct OatWriter::VmapTableDataAccess {
-  static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
+  static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
     return &compiled_method->GetVmapTable();
   }
 
@@ -481,7 +564,7 @@
         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
-  static const char* Name() ALWAYS_INLINE {
+  static const char* Name() {
     return "vmap table";
   }
 };
@@ -571,7 +654,7 @@
     return true;
   }
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
+  bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it) {
     // Fill in the compiled_methods_ array for methods that have a
     // CompiledMethod. We track the number of non-null entries in
     // num_non_null_compiled_methods_ since we only want to allocate
@@ -636,105 +719,101 @@
       // Derived from CompiledMethod.
       uint32_t quick_code_offset = 0;
 
-      const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode();
-      const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-      if (portable_code != nullptr) {
-        CHECK(quick_code == nullptr);
-        size_t oat_method_offsets_offset =
-            oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
-        compiled_method->AddOatdataOffsetToCompliledCodeOffset(
-            oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
+      const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
+      CHECK(quick_code != nullptr);
+      offset_ = writer_->relative_call_patcher_->ReserveSpace(offset_, compiled_method);
+      offset_ = compiled_method->AlignCode(offset_);
+      DCHECK_ALIGNED_PARAM(offset_,
+                           GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
+      uint32_t code_size = quick_code->size() * sizeof(uint8_t);
+      CHECK_NE(code_size, 0U);
+      uint32_t thumb_offset = compiled_method->CodeDelta();
+      quick_code_offset = offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
+
+      bool deduped = false;
+
+      // Deduplicate code arrays.
+      auto lb = dedupe_map_.lower_bound(compiled_method);
+      if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(compiled_method, lb->first)) {
+        quick_code_offset = lb->second;
+        deduped = true;
       } else {
-        CHECK(quick_code != nullptr);
-        offset_ = writer_->relative_call_patcher_->ReserveSpace(offset_, compiled_method);
-        offset_ = compiled_method->AlignCode(offset_);
-        DCHECK_ALIGNED_PARAM(offset_,
-                             GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
-        uint32_t code_size = quick_code->size() * sizeof(uint8_t);
-        CHECK_NE(code_size, 0U);
-        uint32_t thumb_offset = compiled_method->CodeDelta();
-        quick_code_offset = offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
+        dedupe_map_.PutBefore(lb, compiled_method, quick_code_offset);
+      }
 
-        bool deduped = false;
+      MethodReference method_ref(dex_file_, it.GetMemberIndex());
+      auto method_lb = writer_->method_offset_map_.lower_bound(method_ref);
+      if (method_lb != writer_->method_offset_map_.end() &&
+          !writer_->method_offset_map_.key_comp()(method_ref, method_lb->first)) {
+        // TODO: Should this be a hard failure?
+        LOG(WARNING) << "Multiple definitions of "
+            << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file)
+            << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : "");
+      } else {
+        writer_->method_offset_map_.PutBefore(method_lb, method_ref, quick_code_offset);
+      }
 
-        // Deduplicate code arrays.
-        auto lb = dedupe_map_.lower_bound(compiled_method);
-        if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(compiled_method, lb->first)) {
-          quick_code_offset = lb->second;
-          deduped = true;
-        } else {
-          dedupe_map_.PutBefore(lb, compiled_method, quick_code_offset);
-        }
+      // Update quick method header.
+      DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
+      OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
+      uint32_t mapping_table_offset = method_header->mapping_table_offset_;
+      uint32_t vmap_table_offset = method_header->vmap_table_offset_;
+      uint32_t gc_map_offset = method_header->gc_map_offset_;
+      // The code offset was 0 when the mapping/vmap table offset was set, so it's set
+      // to 0-offset and we need to adjust it by code_offset.
+      uint32_t code_offset = quick_code_offset - thumb_offset;
+      if (mapping_table_offset != 0u) {
+        mapping_table_offset += code_offset;
+        DCHECK_LT(mapping_table_offset, code_offset);
+      }
+      if (vmap_table_offset != 0u) {
+        vmap_table_offset += code_offset;
+        DCHECK_LT(vmap_table_offset, code_offset);
+      }
+      if (gc_map_offset != 0u) {
+        gc_map_offset += code_offset;
+        DCHECK_LT(gc_map_offset, code_offset);
+      }
+      uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+      uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
+      uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
+      *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
+                                            gc_map_offset, frame_size_in_bytes, core_spill_mask,
+                                            fp_spill_mask, code_size);
 
-        MethodReference method_ref(dex_file_, it.GetMemberIndex());
-        auto method_lb = writer_->method_offset_map_.lower_bound(method_ref);
-        if (method_lb != writer_->method_offset_map_.end() &&
-            !writer_->method_offset_map_.key_comp()(method_ref, method_lb->first)) {
-          // TODO: Should this be a hard failure?
-          LOG(WARNING) << "Multiple definitions of "
-              << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file)
-              << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : "");
-        } else {
-          writer_->method_offset_map_.PutBefore(method_lb, method_ref, quick_code_offset);
-        }
-
-        // Update quick method header.
-        DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
-        OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
-        uint32_t mapping_table_offset = method_header->mapping_table_offset_;
-        uint32_t vmap_table_offset = method_header->vmap_table_offset_;
-        // The code offset was 0 when the mapping/vmap table offset was set, so it's set
-        // to 0-offset and we need to adjust it by code_offset.
-        uint32_t code_offset = quick_code_offset - thumb_offset;
-        if (mapping_table_offset != 0u) {
-          mapping_table_offset += code_offset;
-          DCHECK_LT(mapping_table_offset, code_offset);
-        }
-        if (vmap_table_offset != 0u) {
-          vmap_table_offset += code_offset;
-          DCHECK_LT(vmap_table_offset, code_offset);
-        }
-        uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
-        uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
-        uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
-        *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
-                                              frame_size_in_bytes, core_spill_mask, fp_spill_mask,
-                                              code_size);
-
-        if (!deduped) {
-          // Update offsets. (Checksum is updated when writing.)
-          offset_ += sizeof(*method_header);  // Method header is prepended before code.
-          offset_ += code_size;
-          // Record absolute patch locations.
-          if (!compiled_method->GetPatches().empty()) {
-            uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
-            for (const LinkerPatch& patch : compiled_method->GetPatches()) {
-              if (patch.Type() != kLinkerPatchCallRelative) {
-                writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
-              }
+      if (!deduped) {
+        // Update offsets. (Checksum is updated when writing.)
+        offset_ += sizeof(*method_header);  // Method header is prepended before code.
+        offset_ += code_size;
+        // Record absolute patch locations.
+        if (!compiled_method->GetPatches().empty()) {
+          uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
+          for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+            if (patch.Type() != kLinkerPatchCallRelative) {
+              writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
             }
           }
         }
+      }
 
-        if (writer_->compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
-          // Record debug information for this function if we are doing that.
+      if (writer_->compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
+        // Record debug information for this function if we are doing that.
 
-          std::string name = PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
-          if (deduped) {
-            // TODO We should place the DEDUPED tag on the first instance of a deduplicated symbol
-            // so that it will show up in a debuggerd crash report.
-            name += " [ DEDUPED ]";
-          }
-
-          const uint32_t quick_code_start = quick_code_offset -
-              writer_->oat_header_->GetExecutableOffset();
-          const DexFile::CodeItem *code_item = it.GetMethodCodeItem();
-          writer_->method_info_.push_back(DebugInfo(name,
-                dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)),
-                quick_code_start, quick_code_start + code_size,
-                code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item),
-                compiled_method));
+        std::string name = PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
+        if (deduped) {
+          // TODO We should place the DEDUPED tag on the first instance of a deduplicated symbol
+          // so that it will show up in a debuggerd crash report.
+          name += " [ DEDUPED ]";
         }
+
+        const uint32_t quick_code_start = quick_code_offset -
+            writer_->oat_header_->GetExecutableOffset();
+        const DexFile::CodeItem *code_item = it.GetMethodCodeItem();
+        writer_->method_info_.push_back(DebugInfo(name,
+              dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)),
+              quick_code_start, quick_code_start + code_size,
+              code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item),
+              compiled_method));
       }
 
       if (kIsDebugBuild) {
@@ -750,7 +829,7 @@
         } else {
           status = mirror::Class::kStatusNotReady;
         }
-        std::vector<uint8_t> const * gc_map = compiled_method->GetGcMap();
+        const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap();
         if (gc_map != nullptr) {
           size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
           bool is_native = it.MemberIsNative();
@@ -783,7 +862,7 @@
     : OatDexMethodVisitor(writer, offset) {
   }
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
+  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
@@ -792,7 +871,7 @@
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u);
 
-      const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method);
+      const SwapVector<uint8_t>* map = DataAccess::GetData(compiled_method);
       uint32_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
       if (map_size != 0u) {
         auto lb = dedupe_map_.lower_bound(map);
@@ -814,7 +893,7 @@
  private:
   // Deduplication is already done on a pointer basis by the compiler driver,
   // so we can simply compare the pointers to find out if things are duplicated.
-  SafeMap<const std::vector<uint8_t>*, uint32_t> dedupe_map_;
+  SafeMap<const SwapVector<uint8_t>*, uint32_t> dedupe_map_;
 };
 
 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
@@ -828,7 +907,7 @@
     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
-    OatMethodOffsets offsets(0u, 0u);
+    OatMethodOffsets offsets(0u);
     if (compiled_method != nullptr) {
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       offsets = oat_class->method_offsets_[method_offsets_index_];
@@ -839,7 +918,7 @@
     InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_));
     // Unchecked as we hold mutator_lock_ on entry.
     ScopedObjectAccessUnchecked soa(Thread::Current());
-    StackHandleScope<2> hs(soa.Self());
+    StackHandleScope<1> hs(soa.Self());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
     mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, it.GetMemberIndex(), dex_cache,
                                                       NullHandle<mirror::ClassLoader>(),
@@ -853,9 +932,7 @@
       std::string dump = exc->Dump();
       LOG(FATAL) << dump;
     }
-    // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
     method->SetQuickOatCodeOffset(offsets.code_offset_);
-    method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
 
     return true;
   }
@@ -868,8 +945,8 @@
     : OatDexMethodVisitor(writer, relative_offset),
       out_(out),
       file_offset_(file_offset),
-      self_(Thread::Current()),
-      old_no_thread_suspension_cause_(self_->StartAssertNoThreadSuspension("OatWriter patching")),
+      soa_(Thread::Current()),
+      no_thread_suspension_(soa_.Self(), "OatWriter patching"),
       class_linker_(Runtime::Current()->GetClassLinker()),
       dex_cache_(nullptr) {
     if (writer_->image_writer_ != nullptr) {
@@ -877,12 +954,9 @@
       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
       patched_code_.reserve(16 * KB);
     }
-    self_->TransitionFromSuspendedToRunnable();
   }
 
   ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
-    self_->EndAssertNoThreadSuspension(old_no_thread_suspension_cause_);
-    self_->TransitionFromRunnableToSuspended(kNative);
   }
 
   bool StartClass(const DexFile* dex_file, size_t class_def_index)
@@ -916,9 +990,11 @@
       size_t file_offset = file_offset_;
       OutputStream* out = out_;
 
-      const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode();
+      const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
       if (quick_code != nullptr) {
-        CHECK(compiled_method->GetPortableCode() == nullptr);
+        // Need a wrapper if we create a copy for patching.
+        ArrayRef<const uint8_t> wrapped(*quick_code);
+
         offset_ = writer_->relative_call_patcher_->WriteThunks(out, offset_);
         if (offset_ == 0u) {
           ReportWriteFailure("relative call thunk", it);
@@ -957,8 +1033,8 @@
           DCHECK_OFFSET_();
 
           if (!compiled_method->GetPatches().empty()) {
-            patched_code_ =  *quick_code;
-            quick_code = &patched_code_;
+            patched_code_ = std::vector<uint8_t>(quick_code->begin(), quick_code->end());
+            wrapped = ArrayRef<const uint8_t>(patched_code_);
             for (const LinkerPatch& patch : compiled_method->GetPatches()) {
               if (patch.Type() == kLinkerPatchCallRelative) {
                 // NOTE: Relative calls across oat files are not supported.
@@ -979,8 +1055,8 @@
             }
           }
 
-          writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size);
-          if (!out->WriteFully(&(*quick_code)[0], code_size)) {
+          writer_->oat_header_->UpdateChecksum(wrapped.data(), code_size);
+          if (!out->WriteFully(wrapped.data(), code_size)) {
             ReportWriteFailure("method code", it);
             return false;
           }
@@ -997,9 +1073,9 @@
 
  private:
   OutputStream* const out_;
-  size_t const file_offset_;
-  Thread* const self_;
-  const char* const old_no_thread_suspension_cause_;  // TODO: Use ScopedAssertNoThreadSuspension.
+  const size_t file_offset_;
+  const ScopedObjectAccess soa_;
+  const ScopedAssertNoThreadSuspension no_thread_suspension_;
   ClassLinker* const class_linker_;
   mirror::DexCache* dex_cache_;
   std::vector<uint8_t> patched_code_;
@@ -1079,7 +1155,7 @@
 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
  public:
   WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
-                          size_t relative_offset)
+                        size_t relative_offset)
     : OatDexMethodVisitor(writer, relative_offset),
       out_(out),
       file_offset_(file_offset) {
@@ -1097,11 +1173,12 @@
       ++method_offsets_index_;
 
       // Write deduplicated map.
-      const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method);
+      const SwapVector<uint8_t>* map = DataAccess::GetData(compiled_method);
       size_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
       DCHECK((map_size == 0u && map_offset == 0u) ||
             (map_size != 0u && map_offset != 0u && map_offset <= offset_))
-          << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+          << map_size << " " << map_offset << " " << offset_ << " "
+          << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name();
       if (map_size != 0u && map_offset == offset_) {
         if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) {
           ReportWriteFailure(it);
@@ -1134,7 +1211,7 @@
         return false;
       }
       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-      const byte* class_data = dex_file->GetClassData(class_def);
+      const uint8_t* class_data = dex_file->GetClassData(class_def);
       if (class_data != NULL) {  // ie not an empty class, such as a marker interface
         ClassDataItemIterator it(*dex_file, class_data);
         while (it.HasNextStaticField()) {
@@ -1217,9 +1294,9 @@
   // Update oat_dex_files_.
   auto oat_class_it = oat_classes_.begin();
   for (OatDexFile* oat_dex_file : oat_dex_files_) {
-    for (uint32_t& offset : oat_dex_file->methods_offsets_) {
+    for (uint32_t& method_offset : oat_dex_file->methods_offsets_) {
       DCHECK(oat_class_it != oat_classes_.end());
-      offset = (*oat_class_it)->offset_;
+      method_offset = (*oat_class_it)->offset_;
       ++oat_class_it;
     }
     oat_dex_file->UpdateChecksum(oat_header_);
@@ -1269,9 +1346,6 @@
     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge);
     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge);
     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
-    DO_TRAMPOLINE(portable_imt_conflict_trampoline_, PortableImtConflictTrampoline);
-    DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline);
-    DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge);
     DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
     DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
@@ -1282,9 +1356,6 @@
     oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
     oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
     oat_header_->SetJniDlsymLookupOffset(0);
-    oat_header_->SetPortableImtConflictTrampolineOffset(0);
-    oat_header_->SetPortableResolutionTrampolineOffset(0);
-    oat_header_->SetPortableToInterpreterBridgeOffset(0);
     oat_header_->SetQuickGenericJniTrampolineOffset(0);
     oat_header_->SetQuickImtConflictTrampolineOffset(0);
     oat_header_->SetQuickResolutionTrampolineOffset(0);
@@ -1379,9 +1450,6 @@
     DO_STAT(size_interpreter_to_interpreter_bridge_);
     DO_STAT(size_interpreter_to_compiled_code_bridge_);
     DO_STAT(size_jni_dlsym_lookup_);
-    DO_STAT(size_portable_imt_conflict_trampoline_);
-    DO_STAT(size_portable_resolution_trampoline_);
-    DO_STAT(size_portable_to_interpreter_bridge_);
     DO_STAT(size_quick_generic_jni_trampoline_);
     DO_STAT(size_quick_imt_conflict_trampoline_);
     DO_STAT(size_quick_resolution_trampoline_);
@@ -1524,9 +1592,6 @@
     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_);
     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_);
     DO_TRAMPOLINE(jni_dlsym_lookup_);
-    DO_TRAMPOLINE(portable_imt_conflict_trampoline_);
-    DO_TRAMPOLINE(portable_resolution_trampoline_);
-    DO_TRAMPOLINE(portable_to_interpreter_bridge_);
     DO_TRAMPOLINE(quick_generic_jni_trampoline_);
     DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
     DO_TRAMPOLINE(quick_resolution_trampoline_);
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 5545ba8..e020d31 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -214,10 +214,7 @@
     }
 
     // Offset of start of OatClass from beginning of OatHeader. It is
-    // used to validate file position when writing. For Portable, it
-    // is also used to calculate the position of the OatMethodOffsets
-    // so that code pointers within the OatMethodOffsets can be
-    // patched to point to code in the Portable .o ELF objects.
+    // used to validate file position when writing.
     size_t offset_;
 
     // CompiledMethods for each class_def_method_index, or NULL if no method is available.
@@ -231,10 +228,10 @@
 
     // data to write
 
-    COMPILE_ASSERT(mirror::Class::Status::kStatusMax < (2 ^ 16), class_status_wont_fit_in_16bits);
+    static_assert(mirror::Class::Status::kStatusMax < (2 ^ 16), "class status won't fit in 16bits");
     int16_t status_;
 
-    COMPILE_ASSERT(OatClassType::kOatClassMax < (2 ^ 16), oat_class_type_wont_fit_in_16bits);
+    static_assert(OatClassType::kOatClassMax < (2 ^ 16), "oat_class type won't fit in 16bits");
     uint16_t type_;
 
     uint32_t method_bitmap_size_;
@@ -285,9 +282,6 @@
   std::unique_ptr<const std::vector<uint8_t>> interpreter_to_interpreter_bridge_;
   std::unique_ptr<const std::vector<uint8_t>> interpreter_to_compiled_code_bridge_;
   std::unique_ptr<const std::vector<uint8_t>> jni_dlsym_lookup_;
-  std::unique_ptr<const std::vector<uint8_t>> portable_imt_conflict_trampoline_;
-  std::unique_ptr<const std::vector<uint8_t>> portable_resolution_trampoline_;
-  std::unique_ptr<const std::vector<uint8_t>> portable_to_interpreter_bridge_;
   std::unique_ptr<const std::vector<uint8_t>> quick_generic_jni_trampoline_;
   std::unique_ptr<const std::vector<uint8_t>> quick_imt_conflict_trampoline_;
   std::unique_ptr<const std::vector<uint8_t>> quick_resolution_trampoline_;
@@ -302,9 +296,6 @@
   uint32_t size_interpreter_to_interpreter_bridge_;
   uint32_t size_interpreter_to_compiled_code_bridge_;
   uint32_t size_jni_dlsym_lookup_;
-  uint32_t size_portable_imt_conflict_trampoline_;
-  uint32_t size_portable_resolution_trampoline_;
-  uint32_t size_portable_to_interpreter_bridge_;
   uint32_t size_quick_generic_jni_trampoline_;
   uint32_t size_quick_imt_conflict_trampoline_;
   uint32_t size_quick_resolution_trampoline_;
@@ -330,7 +321,9 @@
   class RelativeCallPatcher;
   class NoRelativeCallPatcher;
   class X86RelativeCallPatcher;
+  class ArmBaseRelativeCallPatcher;
   class Thumb2RelativeCallPatcher;
+  class Arm64RelativeCallPatcher;
 
   std::unique_ptr<RelativeCallPatcher> relative_call_patcher_;
 
@@ -345,12 +338,15 @@
         return lhs->GetQuickCode() < rhs->GetQuickCode();
       }
       // If the code is the same, all other fields are likely to be the same as well.
-      if (UNLIKELY(&lhs->GetMappingTable() != &rhs->GetMappingTable())) {
-        return &lhs->GetMappingTable() < &rhs->GetMappingTable();
+      if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) {
+        return lhs->GetMappingTable() < rhs->GetMappingTable();
       }
       if (UNLIKELY(&lhs->GetVmapTable() != &rhs->GetVmapTable())) {
         return &lhs->GetVmapTable() < &rhs->GetVmapTable();
       }
+      if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) {
+        return lhs->GetGcMap() < rhs->GetGcMap();
+      }
       const auto& lhs_patches = lhs->GetPatches();
       const auto& rhs_patches = rhs->GetPatches();
       if (UNLIKELY(lhs_patches.size() != rhs_patches.size())) {
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
new file mode 100644
index 0000000..d6c3515
--- /dev/null
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -0,0 +1,719 @@
+/*
+ * 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 "bounds_check_elimination.h"
+#include "nodes.h"
+#include "utils/arena_containers.h"
+
+namespace art {
+
+class MonotonicValueRange;
+
+/**
+ * A value bound is represented as a pair of value and constant,
+ * e.g. array.length - 1.
+ */
+class ValueBound : public ValueObject {
+ public:
+  ValueBound(HInstruction* instruction, int constant) {
+    if (instruction != nullptr && instruction->IsIntConstant()) {
+      // Normalizing ValueBound with constant instruction.
+      int instr_const = instruction->AsIntConstant()->GetValue();
+      if (constant >= 0 && (instr_const <= INT_MAX - constant)) {
+        // No overflow.
+        instruction_ = nullptr;
+        constant_ = instr_const + constant;
+        return;
+      }
+      if (constant < 0 && (instr_const >= INT_MIN - constant)) {
+        // No underflow.
+        instruction_ = nullptr;
+        constant_ = instr_const + constant;
+        return;
+      }
+    }
+    instruction_ = instruction;
+    constant_ = constant;
+  }
+
+  // Try to detect useful value bound format from an instruction, e.g.
+  // a constant or array length related value.
+  static ValueBound DetectValueBoundFromValue(HInstruction* instruction, bool* found) {
+    DCHECK(instruction != nullptr);
+    if (instruction->IsIntConstant()) {
+      *found = true;
+      return ValueBound(nullptr, instruction->AsIntConstant()->GetValue());
+    }
+
+    if (instruction->IsArrayLength()) {
+      *found = true;
+      return ValueBound(instruction, 0);
+    }
+    // Try to detect (array.length + c) format.
+    if (instruction->IsAdd()) {
+      HAdd* add = instruction->AsAdd();
+      HInstruction* left = add->GetLeft();
+      HInstruction* right = add->GetRight();
+      if (left->IsArrayLength() && right->IsIntConstant()) {
+        *found = true;
+        return ValueBound(left, right->AsIntConstant()->GetValue());
+      }
+    }
+
+    // No useful bound detected.
+    *found = false;
+    return ValueBound::Max();
+  }
+
+  HInstruction* GetInstruction() const { return instruction_; }
+  int GetConstant() const { return constant_; }
+
+  bool IsRelativeToArrayLength() const {
+    return instruction_ != nullptr && instruction_->IsArrayLength();
+  }
+
+  bool IsConstant() const {
+    return instruction_ == nullptr;
+  }
+
+  static ValueBound Min() { return ValueBound(nullptr, INT_MIN); }
+  static ValueBound Max() { return ValueBound(nullptr, INT_MAX); }
+
+  bool Equals(ValueBound bound) const {
+    return instruction_ == bound.instruction_ && constant_ == bound.constant_;
+  }
+
+  // Returns if it's certain bound1 >= bound2.
+  bool GreaterThanOrEqual(ValueBound bound) const {
+    if (instruction_ == bound.instruction_) {
+      if (instruction_ == nullptr) {
+        // Pure constant.
+        return constant_ >= bound.constant_;
+      }
+      // There might be overflow/underflow. Be conservative for now.
+      return false;
+    }
+    // Not comparable. Just return false.
+    return false;
+  }
+
+  // Returns if it's certain bound1 <= bound2.
+  bool LessThanOrEqual(ValueBound bound) const {
+    if (instruction_ == bound.instruction_) {
+      if (instruction_ == nullptr) {
+        // Pure constant.
+        return constant_ <= bound.constant_;
+      }
+      if (IsRelativeToArrayLength()) {
+        // Array length is guaranteed to be no less than 0.
+        // No overflow/underflow can happen if both constants are negative.
+        if (constant_ <= 0 && bound.constant_ <= 0) {
+          return constant_ <= bound.constant_;
+        }
+        // There might be overflow/underflow. Be conservative for now.
+        return false;
+      }
+    }
+
+    // In case the array length is some constant, we can
+    // still compare.
+    if (IsConstant() && bound.IsRelativeToArrayLength()) {
+      HInstruction* array = bound.GetInstruction()->AsArrayLength()->InputAt(0);
+      if (array->IsNullCheck()) {
+        array = array->AsNullCheck()->InputAt(0);
+      }
+      if (array->IsNewArray()) {
+        HInstruction* len = array->InputAt(0);
+        if (len->IsIntConstant()) {
+          int len_const = len->AsIntConstant()->GetValue();
+          return constant_ <= len_const + bound.GetConstant();
+        }
+      }
+    }
+
+    // Not comparable. Just return false.
+    return false;
+  }
+
+  // Try to narrow lower bound. Returns the greatest of the two if possible.
+  // Pick one if they are not comparable.
+  static ValueBound NarrowLowerBound(ValueBound bound1, ValueBound bound2) {
+    if (bound1.instruction_ == bound2.instruction_) {
+      // Same instruction, compare the constant part.
+      return ValueBound(bound1.instruction_,
+                        std::max(bound1.constant_, bound2.constant_));
+    }
+
+    // Not comparable. Just pick one. We may lose some info, but that's ok.
+    // Favor constant as lower bound.
+    return bound1.IsConstant() ? bound1 : bound2;
+  }
+
+  // Try to narrow upper bound. Returns the lowest of the two if possible.
+  // Pick one if they are not comparable.
+  static ValueBound NarrowUpperBound(ValueBound bound1, ValueBound bound2) {
+    if (bound1.instruction_ == bound2.instruction_) {
+      // Same instruction, compare the constant part.
+      return ValueBound(bound1.instruction_,
+                        std::min(bound1.constant_, bound2.constant_));
+    }
+
+    // Not comparable. Just pick one. We may lose some info, but that's ok.
+    // Favor array length as upper bound.
+    return bound1.IsRelativeToArrayLength() ? bound1 : bound2;
+  }
+
+  // Add a constant to a ValueBound. If the constant part of the ValueBound
+  // overflows/underflows, then we can't accurately represent it. For correctness,
+  // just return Max/Min() depending on whether the returned ValueBound is used for
+  // lower/upper bound.
+  ValueBound Add(int c, bool* overflow_or_underflow) const {
+    *overflow_or_underflow = false;
+    if (c == 0) {
+      return *this;
+    }
+
+    int new_constant;
+    if (c > 0) {
+      if (constant_ > INT_MAX - c) {
+        // Constant part overflows.
+        *overflow_or_underflow = true;
+        return Max();
+      } else {
+        new_constant = constant_ + c;
+      }
+    } else {
+      if (constant_ < INT_MIN - c) {
+        // Constant part underflows.
+        *overflow_or_underflow = true;
+        return Max();
+      } else {
+        new_constant = constant_ + c;
+      }
+    }
+    return ValueBound(instruction_, new_constant);
+  }
+
+ private:
+  HInstruction* instruction_;
+  int constant_;
+};
+
+/**
+ * Represent a range of lower bound and upper bound, both being inclusive.
+ * Currently a ValueRange may be generated as a result of the following:
+ * comparisons related to array bounds, array bounds check, add/sub on top
+ * of an existing value range, or a loop phi corresponding to an
+ * incrementing/decrementing array index (MonotonicValueRange).
+ */
+class ValueRange : public ArenaObject<kArenaAllocMisc> {
+ public:
+  ValueRange(ArenaAllocator* allocator, ValueBound lower, ValueBound upper)
+      : allocator_(allocator), lower_(lower), upper_(upper) {}
+
+  virtual ~ValueRange() {}
+
+  virtual const MonotonicValueRange* AsMonotonicValueRange() const { return nullptr; }
+  bool IsMonotonicValueRange() const {
+    return AsMonotonicValueRange() != nullptr;
+  }
+
+  ArenaAllocator* GetAllocator() const { return allocator_; }
+  ValueBound GetLower() const { return lower_; }
+  ValueBound GetUpper() const { return upper_; }
+
+  // If it's certain that this value range fits in other_range.
+  virtual bool FitsIn(ValueRange* other_range) const {
+    if (other_range == nullptr) {
+      return true;
+    }
+    DCHECK(!other_range->IsMonotonicValueRange());
+    return lower_.GreaterThanOrEqual(other_range->lower_) &&
+           upper_.LessThanOrEqual(other_range->upper_);
+  }
+
+  // Returns the intersection of this and range.
+  // If it's not possible to do intersection because some
+  // bounds are not comparable, it's ok to pick either bound.
+  virtual ValueRange* Narrow(ValueRange* range) {
+    if (range == nullptr) {
+      return this;
+    }
+
+    if (range->IsMonotonicValueRange()) {
+      return this;
+    }
+
+    return new (allocator_) ValueRange(
+        allocator_,
+        ValueBound::NarrowLowerBound(lower_, range->lower_),
+        ValueBound::NarrowUpperBound(upper_, range->upper_));
+  }
+
+  // Shift a range by a constant. If either bound can't be represented
+  // as (instruction+c) format due to possible overflow/underflow,
+  // return the full integer range.
+  ValueRange* Add(int constant) const {
+    bool overflow_or_underflow;
+    ValueBound lower = lower_.Add(constant, &overflow_or_underflow);
+    if (overflow_or_underflow) {
+      // We can't accurately represent the bounds anymore.
+      return FullIntRange();
+    }
+    ValueBound upper = upper_.Add(constant, &overflow_or_underflow);
+    if (overflow_or_underflow) {
+      // We can't accurately represent the bounds anymore.
+      return FullIntRange();
+    }
+    return new (allocator_) ValueRange(allocator_, lower, upper);
+  }
+
+  // Return [INT_MIN, INT_MAX].
+  ValueRange* FullIntRange() const {
+    return new (allocator_) ValueRange(allocator_, ValueBound::Min(), ValueBound::Max());
+  }
+
+ private:
+  ArenaAllocator* const allocator_;
+  const ValueBound lower_;  // inclusive
+  const ValueBound upper_;  // inclusive
+
+  DISALLOW_COPY_AND_ASSIGN(ValueRange);
+};
+
+/**
+ * A monotonically incrementing/decrementing value range, e.g.
+ * the variable i in "for (int i=0; i<array.length; i++)".
+ * Special care needs to be taken to account for overflow/underflow
+ * of such value ranges.
+ */
+class MonotonicValueRange : public ValueRange {
+ public:
+  MonotonicValueRange(ArenaAllocator* allocator,
+                      HInstruction* initial,
+                      int increment,
+                      ValueBound bound)
+      // To be conservative, give it full range [INT_MIN, INT_MAX] in case it's
+      // used as a regular value range, due to possible overflow/underflow.
+      : ValueRange(allocator, ValueBound::Min(), ValueBound::Max()),
+        initial_(initial),
+        increment_(increment),
+        bound_(bound) {}
+
+  virtual ~MonotonicValueRange() {}
+
+  const MonotonicValueRange* AsMonotonicValueRange() const OVERRIDE { return this; }
+
+  // If it's certain that this value range fits in other_range.
+  bool FitsIn(ValueRange* other_range) const OVERRIDE {
+    if (other_range == nullptr) {
+      return true;
+    }
+    DCHECK(!other_range->IsMonotonicValueRange());
+    return false;
+  }
+
+  // Try to narrow this MonotonicValueRange given another range.
+  // Ideally it will return a normal ValueRange. But due to
+  // possible overflow/underflow, that may not be possible.
+  ValueRange* Narrow(ValueRange* range) OVERRIDE {
+    if (range == nullptr) {
+      return this;
+    }
+    DCHECK(!range->IsMonotonicValueRange());
+
+    if (increment_ > 0) {
+      // Monotonically increasing.
+      ValueBound lower = ValueBound::NarrowLowerBound(bound_, range->GetLower());
+
+      // We currently conservatively assume max array length is INT_MAX. If we can
+      // make assumptions about the max array length, e.g. due to the max heap size,
+      // divided by the element size (such as 4 bytes for each integer array), we can
+      // lower this number and rule out some possible overflows.
+      int max_array_len = INT_MAX;
+
+      int upper = INT_MAX;
+      if (range->GetUpper().IsConstant()) {
+        upper = range->GetUpper().GetConstant();
+      } else if (range->GetUpper().IsRelativeToArrayLength()) {
+        int constant = range->GetUpper().GetConstant();
+        if (constant <= 0) {
+          // Normal case. e.g. <= array.length - 1, <= array.length - 2, etc.
+          upper = max_array_len + constant;
+        } else {
+          // There might be overflow. Give up narrowing.
+          return this;
+        }
+      } else {
+        // There might be overflow. Give up narrowing.
+        return this;
+      }
+
+      // If we can prove for the last number in sequence of initial_,
+      // initial_ + increment_, initial_ + 2 x increment_, ...
+      // that's <= upper, (last_num_in_sequence + increment_) doesn't trigger overflow,
+      // then this MonoticValueRange is narrowed to a normal value range.
+
+      // Be conservative first, assume last number in the sequence hits upper.
+      int last_num_in_sequence = upper;
+      if (initial_->IsIntConstant()) {
+        int initial_constant = initial_->AsIntConstant()->GetValue();
+        if (upper <= initial_constant) {
+          last_num_in_sequence = upper;
+        } else {
+          // Cast to int64_t for the substraction part to avoid int overflow.
+          last_num_in_sequence = initial_constant +
+              ((int64_t)upper - (int64_t)initial_constant) / increment_ * increment_;
+        }
+      }
+      if (last_num_in_sequence <= INT_MAX - increment_) {
+        // No overflow. The sequence will be stopped by the upper bound test as expected.
+        return new (GetAllocator()) ValueRange(GetAllocator(), lower, range->GetUpper());
+      }
+
+      // There might be overflow. Give up narrowing.
+      return this;
+    } else {
+      DCHECK_NE(increment_, 0);
+      // Monotonically decreasing.
+      ValueBound upper = ValueBound::NarrowUpperBound(bound_, range->GetUpper());
+
+      // Need to take care of underflow. Try to prove underflow won't happen
+      // for common cases. Basically need to be able to prove for any value
+      // that's >= range->GetLower(), it won't be positive with value+increment.
+      if (range->GetLower().IsConstant()) {
+        int constant = range->GetLower().GetConstant();
+        if (constant >= INT_MIN - increment_) {
+          return new (GetAllocator()) ValueRange(GetAllocator(), range->GetLower(), upper);
+        }
+      }
+
+      // There might be underflow. Give up narrowing.
+      return this;
+    }
+  }
+
+ private:
+  HInstruction* const initial_;
+  const int increment_;
+  ValueBound bound_;  // Additional value bound info for initial_;
+
+  DISALLOW_COPY_AND_ASSIGN(MonotonicValueRange);
+};
+
+class BCEVisitor : public HGraphVisitor {
+ public:
+  explicit BCEVisitor(HGraph* graph)
+      : HGraphVisitor(graph),
+        maps_(graph->GetBlocks().Size()) {}
+
+ private:
+  // Return the map of proven value ranges at the beginning of a basic block.
+  ArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) {
+    int block_id = basic_block->GetBlockId();
+    if (maps_.at(block_id) == nullptr) {
+      std::unique_ptr<ArenaSafeMap<int, ValueRange*>> map(
+          new ArenaSafeMap<int, ValueRange*>(
+              std::less<int>(), GetGraph()->GetArena()->Adapter()));
+      maps_.at(block_id) = std::move(map);
+    }
+    return maps_.at(block_id).get();
+  }
+
+  // Traverse up the dominator tree to look for value range info.
+  ValueRange* LookupValueRange(HInstruction* instruction, HBasicBlock* basic_block) {
+    while (basic_block != nullptr) {
+      ArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block);
+      if (map->find(instruction->GetId()) != map->end()) {
+        return map->Get(instruction->GetId());
+      }
+      basic_block = basic_block->GetDominator();
+    }
+    // Didn't find any.
+    return nullptr;
+  }
+
+  // Narrow the value range of 'instruction' at the end of 'basic_block' with 'range',
+  // and push the narrowed value range to 'successor'.
+  void ApplyRangeFromComparison(HInstruction* instruction, HBasicBlock* basic_block,
+                  HBasicBlock* successor, ValueRange* range) {
+    ValueRange* existing_range = LookupValueRange(instruction, basic_block);
+    ValueRange* narrowed_range = (existing_range == nullptr) ?
+        range : existing_range->Narrow(range);
+    if (narrowed_range != nullptr) {
+      GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
+    }
+  }
+
+  // Handle "if (left cmp_cond right)".
+  void HandleIf(HIf* instruction, HInstruction* left, HInstruction* right, IfCondition cond) {
+    HBasicBlock* block = instruction->GetBlock();
+
+    HBasicBlock* true_successor = instruction->IfTrueSuccessor();
+    // There should be no critical edge at this point.
+    DCHECK_EQ(true_successor->GetPredecessors().Size(), 1u);
+
+    HBasicBlock* false_successor = instruction->IfFalseSuccessor();
+    // There should be no critical edge at this point.
+    DCHECK_EQ(false_successor->GetPredecessors().Size(), 1u);
+
+    bool found;
+    ValueBound bound = ValueBound::DetectValueBoundFromValue(right, &found);
+    ValueBound lower = bound;
+    ValueBound upper = bound;
+    if (!found) {
+      // No constant or array.length+c bound found.
+      // For i<j, we can still use j's upper bound as i's upper bound. Same for lower.
+      ValueRange* range = LookupValueRange(right, block);
+      if (range != nullptr) {
+        lower = range->GetLower();
+        upper = range->GetUpper();
+      } else {
+        lower = ValueBound::Min();
+        upper = ValueBound::Max();
+      }
+    }
+
+    bool overflow_or_underflow;
+    if (cond == kCondLT || cond == kCondLE) {
+      if (!upper.Equals(ValueBound::Max())) {
+        int compensation = (cond == kCondLT) ? -1 : 0;  // upper bound is inclusive
+        ValueBound new_upper = upper.Add(compensation, &overflow_or_underflow);
+        if (overflow_or_underflow) {
+          new_upper = ValueBound::Max();
+        }
+        ValueRange* new_range = new (GetGraph()->GetArena())
+            ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper);
+        ApplyRangeFromComparison(left, block, true_successor, new_range);
+      }
+
+      // array.length as a lower bound isn't considered useful.
+      if (!lower.Equals(ValueBound::Min()) && !lower.IsRelativeToArrayLength()) {
+        int compensation = (cond == kCondLE) ? 1 : 0;  // lower bound is inclusive
+        ValueBound new_lower = lower.Add(compensation, &overflow_or_underflow);
+        if (overflow_or_underflow) {
+          new_lower = ValueBound::Min();
+        }
+        ValueRange* new_range = new (GetGraph()->GetArena())
+            ValueRange(GetGraph()->GetArena(), new_lower, ValueBound::Max());
+        ApplyRangeFromComparison(left, block, false_successor, new_range);
+      }
+    } else if (cond == kCondGT || cond == kCondGE) {
+      // array.length as a lower bound isn't considered useful.
+      if (!lower.Equals(ValueBound::Min()) && !lower.IsRelativeToArrayLength()) {
+        int compensation = (cond == kCondGT) ? 1 : 0;  // lower bound is inclusive
+        ValueBound new_lower = lower.Add(compensation, &overflow_or_underflow);
+        if (overflow_or_underflow) {
+          new_lower = ValueBound::Min();
+        }
+        ValueRange* new_range = new (GetGraph()->GetArena())
+            ValueRange(GetGraph()->GetArena(), new_lower, ValueBound::Max());
+        ApplyRangeFromComparison(left, block, true_successor, new_range);
+      }
+
+      if (!upper.Equals(ValueBound::Max())) {
+        int compensation = (cond == kCondGE) ? -1 : 0;  // upper bound is inclusive
+        ValueBound new_upper = upper.Add(compensation, &overflow_or_underflow);
+        if (overflow_or_underflow) {
+          new_upper = ValueBound::Max();
+        }
+        ValueRange* new_range = new (GetGraph()->GetArena())
+            ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper);
+        ApplyRangeFromComparison(left, block, false_successor, new_range);
+      }
+    }
+  }
+
+  void VisitBoundsCheck(HBoundsCheck* bounds_check) {
+    HBasicBlock* block = bounds_check->GetBlock();
+    HInstruction* index = bounds_check->InputAt(0);
+    HInstruction* array_length = bounds_check->InputAt(1);
+    ValueRange* index_range = LookupValueRange(index, block);
+
+    if (index_range != nullptr) {
+      ValueBound lower = ValueBound(nullptr, 0);        // constant 0
+      ValueBound upper = ValueBound(array_length, -1);  // array_length - 1
+      ValueRange* array_range = new (GetGraph()->GetArena())
+          ValueRange(GetGraph()->GetArena(), lower, upper);
+      if (index_range->FitsIn(array_range)) {
+        ReplaceBoundsCheck(bounds_check, index);
+        return;
+      }
+    }
+
+    if (index->IsIntConstant()) {
+      ValueRange* array_length_range = LookupValueRange(array_length, block);
+      int constant = index->AsIntConstant()->GetValue();
+      if (array_length_range != nullptr &&
+          array_length_range->GetLower().IsConstant()) {
+        if (constant < array_length_range->GetLower().GetConstant()) {
+          ReplaceBoundsCheck(bounds_check, index);
+          return;
+        }
+      }
+
+      // Once we have an array access like 'array[5] = 1', we record array.length >= 6.
+      ValueBound lower = ValueBound(nullptr, constant + 1);
+      ValueBound upper = ValueBound::Max();
+      ValueRange* range = new (GetGraph()->GetArena())
+          ValueRange(GetGraph()->GetArena(), lower, upper);
+      ValueRange* existing_range = LookupValueRange(array_length, block);
+      ValueRange* new_range = range;
+      if (existing_range != nullptr) {
+        new_range = range->Narrow(existing_range);
+      }
+      GetValueRangeMap(block)->Overwrite(array_length->GetId(), new_range);
+    }
+  }
+
+  void ReplaceBoundsCheck(HInstruction* bounds_check, HInstruction* index) {
+    bounds_check->ReplaceWith(index);
+    bounds_check->GetBlock()->RemoveInstruction(bounds_check);
+  }
+
+  void VisitPhi(HPhi* phi) {
+    if (phi->IsLoopHeaderPhi() && phi->GetType() == Primitive::kPrimInt) {
+      DCHECK_EQ(phi->InputCount(), 2U);
+      HInstruction* instruction = phi->InputAt(1);
+      if (instruction->IsAdd()) {
+        HAdd* add = instruction->AsAdd();
+        HInstruction* left = add->GetLeft();
+        HInstruction* right = add->GetRight();
+        if (left == phi && right->IsIntConstant()) {
+          HInstruction* initial_value = phi->InputAt(0);
+          ValueRange* range = nullptr;
+          int increment = right->AsIntConstant()->GetValue();
+          if (increment == 0) {
+            // Add constant 0. It's really a fixed value.
+            range = new (GetGraph()->GetArena()) ValueRange(
+                GetGraph()->GetArena(),
+                ValueBound(initial_value, 0),
+                ValueBound(initial_value, 0));
+          } else {
+            // Monotonically increasing/decreasing.
+            bool found;
+            ValueBound bound = ValueBound::DetectValueBoundFromValue(
+                initial_value, &found);
+            if (!found) {
+              // No constant or array.length+c bound found.
+              // For i=j, we can still use j's upper bound as i's upper bound.
+              // Same for lower.
+              ValueRange* initial_range = LookupValueRange(initial_value, phi->GetBlock());
+              if (initial_range != nullptr) {
+                bound = increment > 0 ? initial_range->GetLower() :
+                                        initial_range->GetUpper();
+              } else {
+                bound = increment > 0 ? ValueBound::Min() : ValueBound::Max();
+              }
+            }
+            range = new (GetGraph()->GetArena()) MonotonicValueRange(
+                GetGraph()->GetArena(),
+                initial_value,
+                increment,
+                bound);
+          }
+          GetValueRangeMap(phi->GetBlock())->Overwrite(phi->GetId(), range);
+        }
+      }
+    }
+  }
+
+  void VisitIf(HIf* instruction) {
+    if (instruction->InputAt(0)->IsCondition()) {
+      HCondition* cond = instruction->InputAt(0)->AsCondition();
+      IfCondition cmp = cond->GetCondition();
+      if (cmp == kCondGT || cmp == kCondGE ||
+          cmp == kCondLT || cmp == kCondLE) {
+        HInstruction* left = cond->GetLeft();
+        HInstruction* right = cond->GetRight();
+        HandleIf(instruction, left, right, cmp);
+      }
+    }
+  }
+
+  void VisitAdd(HAdd* add) {
+    HInstruction* right = add->GetRight();
+    if (right->IsIntConstant()) {
+      ValueRange* left_range = LookupValueRange(add->GetLeft(), add->GetBlock());
+      if (left_range == nullptr) {
+        return;
+      }
+      ValueRange* range = left_range->Add(right->AsIntConstant()->GetValue());
+      if (range != nullptr) {
+        GetValueRangeMap(add->GetBlock())->Overwrite(add->GetId(), range);
+      }
+    }
+  }
+
+  void VisitSub(HSub* sub) {
+    HInstruction* left = sub->GetLeft();
+    HInstruction* right = sub->GetRight();
+    if (right->IsIntConstant()) {
+      ValueRange* left_range = LookupValueRange(left, sub->GetBlock());
+      if (left_range == nullptr) {
+        return;
+      }
+      ValueRange* range = left_range->Add(-right->AsIntConstant()->GetValue());
+      if (range != nullptr) {
+        GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+        return;
+      }
+    }
+
+    // Here we are interested in the typical triangular case of nested loops,
+    // such as the inner loop 'for (int j=0; j<array.length-i; j++)' where i
+    // is the index for outer loop. In this case, we know j is bounded by array.length-1.
+    if (left->IsArrayLength()) {
+      HInstruction* array_length = left->AsArrayLength();
+      ValueRange* right_range = LookupValueRange(right, sub->GetBlock());
+      if (right_range != nullptr) {
+        ValueBound lower = right_range->GetLower();
+        ValueBound upper = right_range->GetUpper();
+        if (lower.IsConstant() && upper.IsRelativeToArrayLength()) {
+          HInstruction* upper_inst = upper.GetInstruction();
+          if (upper_inst->IsArrayLength() &&
+              upper_inst->AsArrayLength() == array_length) {
+            // (array.length - v) where v is in [c1, array.length + c2]
+            // gets [-c2, array.length - c1] as its value range.
+            ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
+                GetGraph()->GetArena(),
+                ValueBound(nullptr, - upper.GetConstant()),
+                ValueBound(array_length, - lower.GetConstant()));
+            GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+          }
+        }
+      }
+    }
+  }
+
+  std::vector<std::unique_ptr<ArenaSafeMap<int, ValueRange*>>> maps_;
+
+  DISALLOW_COPY_AND_ASSIGN(BCEVisitor);
+};
+
+void BoundsCheckElimination::Run() {
+  BCEVisitor visitor(graph_);
+  // Reverse post order guarantees a node's dominators are visited first.
+  // We want to visit in the dominator-based order since if a value is known to
+  // be bounded by a range at one instruction, it must be true that all uses of
+  // that value dominated by that instruction fits in that range. Range of that
+  // value can be narrowed further down in the dominator tree.
+  //
+  // TODO: only visit blocks that dominate some array accesses.
+  visitor.VisitReversePostOrder();
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/bounds_check_elimination.h b/compiler/optimizing/bounds_check_elimination.h
new file mode 100644
index 0000000..05cb185
--- /dev/null
+++ b/compiler/optimizing/bounds_check_elimination.h
@@ -0,0 +1,36 @@
+/*
+ * 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_BOUNDS_CHECK_ELIMINATION_H_
+#define ART_COMPILER_OPTIMIZING_BOUNDS_CHECK_ELIMINATION_H_
+
+#include "optimization.h"
+
+namespace art {
+
+class BoundsCheckElimination : public HOptimization {
+ public:
+  explicit BoundsCheckElimination(HGraph* graph) : HOptimization(graph, true, "BCE") {}
+
+  void Run() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BoundsCheckElimination);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_BOUNDS_CHECK_ELIMINATION_H_
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
new file mode 100644
index 0000000..f650ff2
--- /dev/null
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -0,0 +1,1045 @@
+/*
+ * 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 "bounds_check_elimination.h"
+#include "builder.h"
+#include "gvn.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+#include "utils/arena_allocator.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+// if (i < 0) { array[i] = 1; // Can't eliminate. }
+// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
+// else { array[i] = 1; // Can eliminate. }
+TEST(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter1 = new (&allocator)
+      HParameterValue(0, Primitive::kPrimNot);  // array
+  HInstruction* parameter2 = new (&allocator)
+      HParameterValue(0, Primitive::kPrimInt);  // i
+  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
+  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
+  entry->AddInstruction(parameter1);
+  entry->AddInstruction(parameter2);
+  entry->AddInstruction(constant_1);
+  entry->AddInstruction(constant_0);
+
+  HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block1);
+  HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, constant_0);
+  HIf* if_inst = new (&allocator) HIf(cmp);
+  block1->AddInstruction(cmp);
+  block1->AddInstruction(if_inst);
+  entry->AddSuccessor(block1);
+
+  HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block2);
+  HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
+  HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check2 = new (&allocator)
+      HBoundsCheck(parameter2, array_length, 0);
+  HArraySet* array_set = new (&allocator) HArraySet(
+    null_check, bounds_check2, constant_1, Primitive::kPrimInt, 0);
+  block2->AddInstruction(null_check);
+  block2->AddInstruction(array_length);
+  block2->AddInstruction(bounds_check2);
+  block2->AddInstruction(array_set);
+
+  HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block3);
+  null_check = new (&allocator) HNullCheck(parameter1, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  cmp = new (&allocator) HLessThan(parameter2, array_length);
+  if_inst = new (&allocator) HIf(cmp);
+  block3->AddInstruction(null_check);
+  block3->AddInstruction(array_length);
+  block3->AddInstruction(cmp);
+  block3->AddInstruction(if_inst);
+
+  HBasicBlock* block4 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block4);
+  null_check = new (&allocator) HNullCheck(parameter1, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check4 = new (&allocator)
+      HBoundsCheck(parameter2, array_length, 0);
+  array_set = new (&allocator) HArraySet(
+    null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
+  block4->AddInstruction(null_check);
+  block4->AddInstruction(array_length);
+  block4->AddInstruction(bounds_check4);
+  block4->AddInstruction(array_set);
+
+  HBasicBlock* block5 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block5);
+  null_check = new (&allocator) HNullCheck(parameter1, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check5 = new (&allocator)
+      HBoundsCheck(parameter2, array_length, 0);
+  array_set = new (&allocator) HArraySet(
+    null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
+  block5->AddInstruction(null_check);
+  block5->AddInstruction(array_length);
+  block5->AddInstruction(bounds_check5);
+  block5->AddInstruction(array_set);
+
+  HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(exit);
+  block2->AddSuccessor(exit);
+  block4->AddSuccessor(exit);
+  block5->AddSuccessor(exit);
+  exit->AddInstruction(new (&allocator) HExit());
+
+  block1->AddSuccessor(block3);  // True successor
+  block1->AddSuccessor(block2);  // False successor
+
+  block3->AddSuccessor(block5);  // True successor
+  block3->AddSuccessor(block4);  // False successor
+
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check2));
+  ASSERT_FALSE(IsRemoved(bounds_check4));
+  ASSERT_TRUE(IsRemoved(bounds_check5));
+}
+
+// if (i > 0) {
+//   // Positive number plus MAX_INT will overflow and be negative.
+//   int j = i + Integer.MAX_VALUE;
+//   if (j < array.length) array[j] = 1;  // Can't eliminate.
+// }
+TEST(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter1 = new (&allocator)
+      HParameterValue(0, Primitive::kPrimNot);  // array
+  HInstruction* parameter2 = new (&allocator)
+      HParameterValue(0, Primitive::kPrimInt);  // i
+  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
+  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
+  HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
+  entry->AddInstruction(parameter1);
+  entry->AddInstruction(parameter2);
+  entry->AddInstruction(constant_1);
+  entry->AddInstruction(constant_0);
+  entry->AddInstruction(constant_max_int);
+
+  HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block1);
+  HInstruction* cmp = new (&allocator) HLessThanOrEqual(parameter2, constant_0);
+  HIf* if_inst = new (&allocator) HIf(cmp);
+  block1->AddInstruction(cmp);
+  block1->AddInstruction(if_inst);
+  entry->AddSuccessor(block1);
+
+  HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block2);
+  HInstruction* add = new (&allocator) HAdd(Primitive::kPrimInt, parameter2, constant_max_int);
+  HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
+  HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
+  HInstruction* cmp2 = new (&allocator) HGreaterThanOrEqual(add, array_length);
+  if_inst = new (&allocator) HIf(cmp2);
+  block2->AddInstruction(add);
+  block2->AddInstruction(null_check);
+  block2->AddInstruction(array_length);
+  block2->AddInstruction(cmp2);
+  block2->AddInstruction(if_inst);
+
+  HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block3);
+  HBoundsCheck* bounds_check = new (&allocator)
+      HBoundsCheck(add, array_length, 0);
+  HArraySet* array_set = new (&allocator) HArraySet(
+    null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
+  block3->AddInstruction(bounds_check);
+  block3->AddInstruction(array_set);
+
+  HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(exit);
+  exit->AddInstruction(new (&allocator) HExit());
+  block1->AddSuccessor(exit);    // true successor
+  block1->AddSuccessor(block2);  // false successor
+  block2->AddSuccessor(exit);    // true successor
+  block2->AddSuccessor(block3);  // false successor
+  block3->AddSuccessor(exit);
+
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+}
+
+// if (i < array.length) {
+//   int j = i - Integer.MAX_VALUE;
+//   j = j - Integer.MAX_VALUE;  // j is (i+2) after substracting MAX_INT twice
+//   if (j > 0) array[j] = 1;    // Can't eliminate.
+// }
+TEST(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter1 = new (&allocator)
+      HParameterValue(0, Primitive::kPrimNot);  // array
+  HInstruction* parameter2 = new (&allocator)
+      HParameterValue(0, Primitive::kPrimInt);  // i
+  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
+  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
+  HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
+  entry->AddInstruction(parameter1);
+  entry->AddInstruction(parameter2);
+  entry->AddInstruction(constant_1);
+  entry->AddInstruction(constant_0);
+  entry->AddInstruction(constant_max_int);
+
+  HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block1);
+  HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
+  HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
+  HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, array_length);
+  HIf* if_inst = new (&allocator) HIf(cmp);
+  block1->AddInstruction(null_check);
+  block1->AddInstruction(array_length);
+  block1->AddInstruction(cmp);
+  block1->AddInstruction(if_inst);
+  entry->AddSuccessor(block1);
+
+  HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block2);
+  HInstruction* sub1 = new (&allocator) HSub(Primitive::kPrimInt, parameter2, constant_max_int);
+  HInstruction* sub2 = new (&allocator) HSub(Primitive::kPrimInt, sub1, constant_max_int);
+  HInstruction* cmp2 = new (&allocator) HLessThanOrEqual(sub2, constant_0);
+  if_inst = new (&allocator) HIf(cmp2);
+  block2->AddInstruction(sub1);
+  block2->AddInstruction(sub2);
+  block2->AddInstruction(cmp2);
+  block2->AddInstruction(if_inst);
+
+  HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block3);
+  HBoundsCheck* bounds_check = new (&allocator)
+      HBoundsCheck(sub2, array_length, 0);
+  HArraySet* array_set = new (&allocator) HArraySet(
+    null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
+  block3->AddInstruction(bounds_check);
+  block3->AddInstruction(array_set);
+
+  HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(exit);
+  exit->AddInstruction(new (&allocator) HExit());
+  block1->AddSuccessor(exit);    // true successor
+  block1->AddSuccessor(block2);  // false successor
+  block2->AddSuccessor(exit);    // true successor
+  block2->AddSuccessor(block3);  // false successor
+  block3->AddSuccessor(exit);
+
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+}
+
+// array[5] = 1; // Can't eliminate.
+// array[4] = 1; // Can eliminate.
+// array[6] = 1; // Can't eliminate.
+TEST(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+  HInstruction* constant_5 = new (&allocator) HIntConstant(5);
+  HInstruction* constant_4 = new (&allocator) HIntConstant(4);
+  HInstruction* constant_6 = new (&allocator) HIntConstant(6);
+  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
+  entry->AddInstruction(parameter);
+  entry->AddInstruction(constant_5);
+  entry->AddInstruction(constant_4);
+  entry->AddInstruction(constant_6);
+  entry->AddInstruction(constant_1);
+
+  HBasicBlock* block = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+
+  HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
+  HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check5 = new (&allocator)
+      HBoundsCheck(constant_5, array_length, 0);
+  HInstruction* array_set = new (&allocator) HArraySet(
+    null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
+  block->AddInstruction(null_check);
+  block->AddInstruction(array_length);
+  block->AddInstruction(bounds_check5);
+  block->AddInstruction(array_set);
+
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check4 = new (&allocator)
+      HBoundsCheck(constant_4, array_length, 0);
+  array_set = new (&allocator) HArraySet(
+    null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
+  block->AddInstruction(null_check);
+  block->AddInstruction(array_length);
+  block->AddInstruction(bounds_check4);
+  block->AddInstruction(array_set);
+
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check6 = new (&allocator)
+      HBoundsCheck(constant_6, array_length, 0);
+  array_set = new (&allocator) HArraySet(
+    null_check, bounds_check6, constant_1, Primitive::kPrimInt, 0);
+  block->AddInstruction(null_check);
+  block->AddInstruction(array_length);
+  block->AddInstruction(bounds_check6);
+  block->AddInstruction(array_set);
+
+  block->AddInstruction(new (&allocator) HGoto());
+
+  HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(exit);
+  block->AddSuccessor(exit);
+  exit->AddInstruction(new (&allocator) HExit());
+
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check5));
+  ASSERT_TRUE(IsRemoved(bounds_check4));
+  ASSERT_FALSE(IsRemoved(bounds_check6));
+}
+
+// for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
+static HGraph* BuildSSAGraph1(ArenaAllocator* allocator,
+                              HInstruction** bounds_check,
+                              int initial,
+                              int increment,
+                              IfCondition cond = kCondGE) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
+  HInstruction* constant_increment = new (allocator) HIntConstant(increment);
+  HInstruction* constant_10 = new (allocator) HIntConstant(10);
+  entry->AddInstruction(parameter);
+  entry->AddInstruction(constant_initial);
+  entry->AddInstruction(constant_increment);
+  entry->AddInstruction(constant_10);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+  block->AddInstruction(new (allocator) HGoto());
+
+  HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
+  HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
+  HBasicBlock* exit = new (allocator) HBasicBlock(graph);
+
+  graph->AddBlock(loop_header);
+  graph->AddBlock(loop_body);
+  graph->AddBlock(exit);
+  block->AddSuccessor(loop_header);
+  loop_header->AddSuccessor(exit);       // true successor
+  loop_header->AddSuccessor(loop_body);  // false successor
+  loop_body->AddSuccessor(loop_header);
+
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  phi->AddInput(constant_initial);
+  HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
+  HInstruction* array_length = new (allocator) HArrayLength(null_check);
+  HInstruction* cmp = nullptr;
+  if (cond == kCondGE) {
+    cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
+  } else {
+    DCHECK(cond == kCondGT);
+    cmp = new (allocator) HGreaterThan(phi, array_length);
+  }
+  HInstruction* if_inst = new (allocator) HIf(cmp);
+  loop_header->AddPhi(phi);
+  loop_header->AddInstruction(null_check);
+  loop_header->AddInstruction(array_length);
+  loop_header->AddInstruction(cmp);
+  loop_header->AddInstruction(if_inst);
+
+  null_check = new (allocator) HNullCheck(parameter, 0);
+  array_length = new (allocator) HArrayLength(null_check);
+  *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
+  HInstruction* array_set = new (allocator) HArraySet(
+      null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
+
+  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
+  loop_body->AddInstruction(null_check);
+  loop_body->AddInstruction(array_length);
+  loop_body->AddInstruction(*bounds_check);
+  loop_body->AddInstruction(array_set);
+  loop_body->AddInstruction(add);
+  loop_body->AddInstruction(new (allocator) HGoto());
+  phi->AddInput(add);
+
+  exit->AddInstruction(new (allocator) HExit());
+
+  return graph;
+}
+
+TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination1) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
+  HInstruction* bounds_check = nullptr;
+  HGraph* graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
+  graph->BuildDominatorTree();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // This time add gvn. Need gvn to eliminate the second
+  // HArrayLength which uses the null check as its input.
+  graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
+  bounds_check_elimination_after_gvn.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
+  graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 1);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
+  bounds_check_elimination_with_initial_1.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
+  graph = BuildSSAGraph1(&allocator, &bounds_check, -1, 1);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
+  bounds_check_elimination_with_initial_minus_1.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
+  graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1, kCondGT);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
+  bounds_check_elimination_with_greater_than.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // for (int i=0; i<array.length; i += 2) {
+  //   array[i] = 10; // Can't eliminate due to overflow concern. }
+  graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 2);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_increment_2(graph);
+  bounds_check_elimination_with_increment_2.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
+  graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 2);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_increment_2_from_1(graph);
+  bounds_check_elimination_with_increment_2_from_1.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+}
+
+// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
+static HGraph* BuildSSAGraph2(ArenaAllocator* allocator,
+                              HInstruction** bounds_check,
+                              int initial,
+                              int increment = -1,
+                              IfCondition cond = kCondLE) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
+  HInstruction* constant_increment = new (allocator) HIntConstant(increment);
+  HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
+  HInstruction* constant_10 = new (allocator) HIntConstant(10);
+  entry->AddInstruction(parameter);
+  entry->AddInstruction(constant_initial);
+  entry->AddInstruction(constant_increment);
+  entry->AddInstruction(constant_minus_1);
+  entry->AddInstruction(constant_10);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+  HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
+  HInstruction* array_length = new (allocator) HArrayLength(null_check);
+  block->AddInstruction(null_check);
+  block->AddInstruction(array_length);
+  block->AddInstruction(new (allocator) HGoto());
+
+  HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
+  HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
+  HBasicBlock* exit = new (allocator) HBasicBlock(graph);
+
+  graph->AddBlock(loop_header);
+  graph->AddBlock(loop_body);
+  graph->AddBlock(exit);
+  block->AddSuccessor(loop_header);
+  loop_header->AddSuccessor(exit);       // true successor
+  loop_header->AddSuccessor(loop_body);  // false successor
+  loop_body->AddSuccessor(loop_header);
+
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  phi->AddInput(array_length);
+  HInstruction* cmp = nullptr;
+  if (cond == kCondLE) {
+    cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
+  } else {
+    DCHECK(cond == kCondLT);
+    cmp = new (allocator) HLessThan(phi, constant_initial);
+  }
+  HInstruction* if_inst = new (allocator) HIf(cmp);
+  loop_header->AddPhi(phi);
+  loop_header->AddInstruction(cmp);
+  loop_header->AddInstruction(if_inst);
+
+  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
+  null_check = new (allocator) HNullCheck(parameter, 0);
+  array_length = new (allocator) HArrayLength(null_check);
+  *bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
+  HInstruction* array_set = new (allocator) HArraySet(
+      null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
+  HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
+  loop_body->AddInstruction(add);
+  loop_body->AddInstruction(null_check);
+  loop_body->AddInstruction(array_length);
+  loop_body->AddInstruction(*bounds_check);
+  loop_body->AddInstruction(array_set);
+  loop_body->AddInstruction(add_phi);
+  loop_body->AddInstruction(new (allocator) HGoto());
+  phi->AddInput(add);
+
+  exit->AddInstruction(new (allocator) HExit());
+
+  return graph;
+}
+
+TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination2) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
+  HInstruction* bounds_check = nullptr;
+  HGraph* graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
+  graph->BuildDominatorTree();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // This time add gvn. Need gvn to eliminate the second
+  // HArrayLength which uses the null check as its input.
+  graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
+  bounds_check_elimination_after_gvn.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
+  graph = BuildSSAGraph2(&allocator, &bounds_check, 1);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
+  bounds_check_elimination_with_initial_1.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
+  graph = BuildSSAGraph2(&allocator, &bounds_check, -1);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
+  bounds_check_elimination_with_initial_minus_1.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
+  graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -1, kCondLT);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_less_than(graph);
+  bounds_check_elimination_with_less_than.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
+  graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -2);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_increment_minus_2(graph);
+  bounds_check_elimination_increment_minus_2.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+}
+
+// int[] array = new array[10];
+// for (int i=0; i<10; i+=increment) { array[i] = 10; }
+static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
+                              HInstruction** bounds_check,
+                              int initial,
+                              int increment,
+                              IfCondition cond) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* constant_10 = new (allocator) HIntConstant(10);
+  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
+  HInstruction* constant_increment = new (allocator) HIntConstant(increment);
+  entry->AddInstruction(constant_10);
+  entry->AddInstruction(constant_initial);
+  entry->AddInstruction(constant_increment);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+  HInstruction* new_array = new (allocator)
+      HNewArray(constant_10, 0, Primitive::kPrimInt);
+  block->AddInstruction(new_array);
+  block->AddInstruction(new (allocator) HGoto());
+
+  HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
+  HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
+  HBasicBlock* exit = new (allocator) HBasicBlock(graph);
+
+  graph->AddBlock(loop_header);
+  graph->AddBlock(loop_body);
+  graph->AddBlock(exit);
+  block->AddSuccessor(loop_header);
+  loop_header->AddSuccessor(exit);       // true successor
+  loop_header->AddSuccessor(loop_body);  // false successor
+  loop_body->AddSuccessor(loop_header);
+
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  phi->AddInput(constant_initial);
+  HInstruction* cmp = nullptr;
+  if (cond == kCondGE) {
+    cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
+  } else {
+    DCHECK(cond == kCondGT);
+    cmp = new (allocator) HGreaterThan(phi, constant_10);
+  }
+  HInstruction* if_inst = new (allocator) HIf(cmp);
+  loop_header->AddPhi(phi);
+  loop_header->AddInstruction(cmp);
+  loop_header->AddInstruction(if_inst);
+
+  HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
+  HArrayLength* array_length = new (allocator) HArrayLength(null_check);
+  *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
+  HInstruction* array_set = new (allocator) HArraySet(
+      null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
+  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
+  loop_body->AddInstruction(null_check);
+  loop_body->AddInstruction(array_length);
+  loop_body->AddInstruction(*bounds_check);
+  loop_body->AddInstruction(array_set);
+  loop_body->AddInstruction(add);
+  loop_body->AddInstruction(new (allocator) HGoto());
+  phi->AddInput(add);
+
+  exit->AddInstruction(new (allocator) HExit());
+
+  return graph;
+}
+
+TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination3) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  // int[] array = new array[10];
+  // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
+  HInstruction* bounds_check = nullptr;
+  HGraph* graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGE);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
+  bounds_check_elimination_after_gvn.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // int[] array = new array[10];
+  // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
+  graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
+  bounds_check_elimination_with_initial_1.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // int[] array = new array[10];
+  // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
+  graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
+  bounds_check_elimination_with_greater_than.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // int[] array = new array[10];
+  // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
+  graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_increment_8(graph);
+  bounds_check_elimination_increment_8.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+}
+
+// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
+static HGraph* BuildSSAGraph4(ArenaAllocator* allocator,
+                              HInstruction** bounds_check,
+                              int initial,
+                              IfCondition cond = kCondGE) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
+  HInstruction* constant_1 = new (allocator) HIntConstant(1);
+  HInstruction* constant_10 = new (allocator) HIntConstant(10);
+  HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
+  entry->AddInstruction(parameter);
+  entry->AddInstruction(constant_initial);
+  entry->AddInstruction(constant_1);
+  entry->AddInstruction(constant_10);
+  entry->AddInstruction(constant_minus_1);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+  block->AddInstruction(new (allocator) HGoto());
+
+  HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
+  HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
+  HBasicBlock* exit = new (allocator) HBasicBlock(graph);
+
+  graph->AddBlock(loop_header);
+  graph->AddBlock(loop_body);
+  graph->AddBlock(exit);
+  block->AddSuccessor(loop_header);
+  loop_header->AddSuccessor(exit);       // true successor
+  loop_header->AddSuccessor(loop_body);  // false successor
+  loop_body->AddSuccessor(loop_header);
+
+  HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  phi->AddInput(constant_initial);
+  HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
+  HInstruction* array_length = new (allocator) HArrayLength(null_check);
+  HInstruction* cmp = nullptr;
+  if (cond == kCondGE) {
+    cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
+  } else if (cond == kCondGT) {
+    cmp = new (allocator) HGreaterThan(phi, array_length);
+  }
+  HInstruction* if_inst = new (allocator) HIf(cmp);
+  loop_header->AddPhi(phi);
+  loop_header->AddInstruction(null_check);
+  loop_header->AddInstruction(array_length);
+  loop_header->AddInstruction(cmp);
+  loop_header->AddInstruction(if_inst);
+
+  null_check = new (allocator) HNullCheck(parameter, 0);
+  array_length = new (allocator) HArrayLength(null_check);
+  HInstruction* sub = new (allocator) HSub(Primitive::kPrimInt, array_length, phi);
+  HInstruction* add_minus_1 = new (allocator)
+      HAdd(Primitive::kPrimInt, sub, constant_minus_1);
+  *bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
+  HInstruction* array_set = new (allocator) HArraySet(
+      null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
+  HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_1);
+  loop_body->AddInstruction(null_check);
+  loop_body->AddInstruction(array_length);
+  loop_body->AddInstruction(sub);
+  loop_body->AddInstruction(add_minus_1);
+  loop_body->AddInstruction(*bounds_check);
+  loop_body->AddInstruction(array_set);
+  loop_body->AddInstruction(add);
+  loop_body->AddInstruction(new (allocator) HGoto());
+  phi->AddInput(add);
+
+  exit->AddInstruction(new (allocator) HExit());
+
+  return graph;
+}
+
+TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination4) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
+  HInstruction* bounds_check = nullptr;
+  HGraph* graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
+  graph->BuildDominatorTree();
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+
+  // This time add gvn. Need gvn to eliminate the second
+  // HArrayLength which uses the null check as its input.
+  graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
+  bounds_check_elimination_after_gvn.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
+  graph = BuildSSAGraph4(&allocator, &bounds_check, 1);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
+  bounds_check_elimination_with_initial_1.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check));
+
+  // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
+  graph = BuildSSAGraph4(&allocator, &bounds_check, 0, kCondGT);
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
+  bounds_check_elimination_with_greater_than.Run();
+  ASSERT_FALSE(IsRemoved(bounds_check));
+}
+
+// Bubble sort:
+// (Every array access bounds-check can be eliminated.)
+// for (int i=0; i<array.length-1; i++) {
+//  for (int j=0; j<array.length-i-1; j++) {
+//     if (array[j] > array[j+1]) {
+//       int temp = array[j+1];
+//       array[j+1] = array[j];
+//       array[j] = temp;
+//     }
+//  }
+// }
+TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
+  HInstruction* constant_minus_1 = new (&allocator) HIntConstant(-1);
+  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
+  entry->AddInstruction(parameter);
+  entry->AddInstruction(constant_0);
+  entry->AddInstruction(constant_minus_1);
+  entry->AddInstruction(constant_1);
+
+  HBasicBlock* block = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+  block->AddInstruction(new (&allocator) HGoto());
+
+  HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(exit);
+  exit->AddInstruction(new (&allocator) HExit());
+
+  HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(outer_header);
+  HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
+  phi_i->AddInput(constant_0);
+  HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
+  HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
+  HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
+  HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(phi_i, add);
+  HIf* if_inst = new (&allocator) HIf(cmp);
+  outer_header->AddPhi(phi_i);
+  outer_header->AddInstruction(null_check);
+  outer_header->AddInstruction(array_length);
+  outer_header->AddInstruction(add);
+  outer_header->AddInstruction(cmp);
+  outer_header->AddInstruction(if_inst);
+
+  HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(inner_header);
+  HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
+  phi_j->AddInput(constant_0);
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i);
+  add = new (&allocator) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
+  cmp = new (&allocator) HGreaterThanOrEqual(phi_j, add);
+  if_inst = new (&allocator) HIf(cmp);
+  inner_header->AddPhi(phi_j);
+  inner_header->AddInstruction(null_check);
+  inner_header->AddInstruction(array_length);
+  inner_header->AddInstruction(sub);
+  inner_header->AddInstruction(add);
+  inner_header->AddInstruction(cmp);
+  inner_header->AddInstruction(if_inst);
+
+  HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(inner_body_compare);
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check1 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
+  HArrayGet* array_get_j = new (&allocator)
+      HArrayGet(null_check, bounds_check1, Primitive::kPrimInt);
+  inner_body_compare->AddInstruction(null_check);
+  inner_body_compare->AddInstruction(array_length);
+  inner_body_compare->AddInstruction(bounds_check1);
+  inner_body_compare->AddInstruction(array_get_j);
+  HInstruction* j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HBoundsCheck* bounds_check2 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
+  HArrayGet* array_get_j_plus_1 = new (&allocator)
+      HArrayGet(null_check, bounds_check2, Primitive::kPrimInt);
+  cmp = new (&allocator) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
+  if_inst = new (&allocator) HIf(cmp);
+  inner_body_compare->AddInstruction(j_plus_1);
+  inner_body_compare->AddInstruction(null_check);
+  inner_body_compare->AddInstruction(array_length);
+  inner_body_compare->AddInstruction(bounds_check2);
+  inner_body_compare->AddInstruction(array_get_j_plus_1);
+  inner_body_compare->AddInstruction(cmp);
+  inner_body_compare->AddInstruction(if_inst);
+
+  HBasicBlock* inner_body_swap = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(inner_body_swap);
+  j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
+  // temp = array[j+1]
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HInstruction* bounds_check3 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
+  array_get_j_plus_1 = new (&allocator)
+      HArrayGet(null_check, bounds_check3, Primitive::kPrimInt);
+  inner_body_swap->AddInstruction(j_plus_1);
+  inner_body_swap->AddInstruction(null_check);
+  inner_body_swap->AddInstruction(array_length);
+  inner_body_swap->AddInstruction(bounds_check3);
+  inner_body_swap->AddInstruction(array_get_j_plus_1);
+  // array[j+1] = array[j]
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HInstruction* bounds_check4 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
+  array_get_j = new (&allocator)
+      HArrayGet(null_check, bounds_check4, Primitive::kPrimInt);
+  inner_body_swap->AddInstruction(null_check);
+  inner_body_swap->AddInstruction(array_length);
+  inner_body_swap->AddInstruction(bounds_check4);
+  inner_body_swap->AddInstruction(array_get_j);
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HInstruction* bounds_check5 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
+  HArraySet* array_set_j_plus_1 = new (&allocator)
+      HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
+  inner_body_swap->AddInstruction(null_check);
+  inner_body_swap->AddInstruction(array_length);
+  inner_body_swap->AddInstruction(bounds_check5);
+  inner_body_swap->AddInstruction(array_set_j_plus_1);
+  // array[j] = temp
+  null_check = new (&allocator) HNullCheck(parameter, 0);
+  array_length = new (&allocator) HArrayLength(null_check);
+  HInstruction* bounds_check6 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
+  HArraySet* array_set_j = new (&allocator)
+      HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
+  inner_body_swap->AddInstruction(null_check);
+  inner_body_swap->AddInstruction(array_length);
+  inner_body_swap->AddInstruction(bounds_check6);
+  inner_body_swap->AddInstruction(array_set_j);
+  inner_body_swap->AddInstruction(new (&allocator) HGoto());
+
+  HBasicBlock* inner_body_add = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(inner_body_add);
+  add = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
+  inner_body_add->AddInstruction(add);
+  inner_body_add->AddInstruction(new (&allocator) HGoto());
+  phi_j->AddInput(add);
+
+  HBasicBlock* outer_body_add = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(outer_body_add);
+  add = new (&allocator) HAdd(Primitive::kPrimInt, phi_i, constant_1);
+  outer_body_add->AddInstruction(add);
+  outer_body_add->AddInstruction(new (&allocator) HGoto());
+  phi_i->AddInput(add);
+
+  block->AddSuccessor(outer_header);
+  outer_header->AddSuccessor(exit);
+  outer_header->AddSuccessor(inner_header);
+  inner_header->AddSuccessor(outer_body_add);
+  inner_header->AddSuccessor(inner_body_compare);
+  inner_body_compare->AddSuccessor(inner_body_add);
+  inner_body_compare->AddSuccessor(inner_body_swap);
+  inner_body_swap->AddSuccessor(inner_body_add);
+  inner_body_add->AddSuccessor(inner_header);
+  outer_body_add->AddSuccessor(outer_header);
+
+  graph->BuildDominatorTree();
+  GlobalValueNumberer(&allocator, graph).Run();
+  // gvn should remove the same bounds check.
+  ASSERT_FALSE(IsRemoved(bounds_check1));
+  ASSERT_FALSE(IsRemoved(bounds_check2));
+  ASSERT_TRUE(IsRemoved(bounds_check3));
+  ASSERT_TRUE(IsRemoved(bounds_check4));
+  ASSERT_TRUE(IsRemoved(bounds_check5));
+  ASSERT_TRUE(IsRemoved(bounds_check6));
+
+  BoundsCheckElimination bounds_check_elimination(graph);
+  bounds_check_elimination.Run();
+  ASSERT_TRUE(IsRemoved(bounds_check1));
+  ASSERT_TRUE(IsRemoved(bounds_check2));
+  ASSERT_TRUE(IsRemoved(bounds_check3));
+  ASSERT_TRUE(IsRemoved(bounds_check4));
+  ASSERT_TRUE(IsRemoved(bounds_check5));
+  ASSERT_TRUE(IsRemoved(bounds_check6));
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 5015bd0..9c2facb 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +16,7 @@
 
 #include "builder.h"
 
+#include "base/logging.h"
 #include "class_linker.h"
 #include "dex_file.h"
 #include "dex_file-inl.h"
@@ -42,32 +42,100 @@
  */
 class Temporaries : public ValueObject {
  public:
-  Temporaries(HGraph* graph, size_t count) : graph_(graph), count_(count), index_(0) {
-    graph_->UpdateNumberOfTemporaries(count_);
-  }
+  explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {}
 
   void Add(HInstruction* instruction) {
-    // We currently only support vreg size temps.
-    DCHECK(instruction->GetType() != Primitive::kPrimLong
-           && instruction->GetType() != Primitive::kPrimDouble);
-    HInstruction* temp = new (graph_->GetArena()) HTemporary(index_++);
+    HInstruction* temp = new (graph_->GetArena()) HTemporary(index_);
     instruction->GetBlock()->AddInstruction(temp);
+
     DCHECK(temp->GetPrevious() == instruction);
+
+    size_t offset;
+    if (instruction->GetType() == Primitive::kPrimLong
+        || instruction->GetType() == Primitive::kPrimDouble) {
+      offset = 2;
+    } else {
+      offset = 1;
+    }
+    index_ += offset;
+
+    graph_->UpdateTemporariesVRegSlots(index_);
   }
 
  private:
   HGraph* const graph_;
 
-  // The total number of temporaries that will be used.
-  const size_t count_;
-
   // Current index in the temporary stack, updated by `Add`.
   size_t index_;
 };
 
-static bool IsTypeSupported(Primitive::Type type) {
-  return type != Primitive::kPrimFloat && type != Primitive::kPrimDouble;
-}
+class SwitchTable : public ValueObject {
+ public:
+  SwitchTable(const Instruction& instruction, uint32_t dex_pc, bool sparse)
+      : instruction_(instruction), dex_pc_(dex_pc), sparse_(sparse) {
+    int32_t table_offset = instruction.VRegB_31t();
+    const uint16_t* table = reinterpret_cast<const uint16_t*>(&instruction) + table_offset;
+    if (sparse) {
+      CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+    } else {
+      CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
+    }
+    num_entries_ = table[1];
+    values_ = reinterpret_cast<const int32_t*>(&table[2]);
+  }
+
+  uint16_t GetNumEntries() const {
+    return num_entries_;
+  }
+
+  void CheckIndex(size_t index) const {
+    if (sparse_) {
+      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
+      DCHECK_LT(index, 2 * static_cast<size_t>(num_entries_));
+    } else {
+      // In a packed table, we have the starting key and num_entries_ values.
+      DCHECK_LT(index, 1 + static_cast<size_t>(num_entries_));
+    }
+  }
+
+  int32_t GetEntryAt(size_t index) const {
+    CheckIndex(index);
+    return values_[index];
+  }
+
+  uint32_t GetDexPcForIndex(size_t index) const {
+    CheckIndex(index);
+    return dex_pc_ +
+        (reinterpret_cast<const int16_t*>(values_ + index) -
+         reinterpret_cast<const int16_t*>(&instruction_));
+  }
+
+  // Index of the first value in the table.
+  size_t GetFirstValueIndex() const {
+    if (sparse_) {
+      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
+      return num_entries_;
+    } else {
+      // In a packed table, we have the starting key and num_entries_ values.
+      return 1;
+    }
+  }
+
+ private:
+  const Instruction& instruction_;
+  const uint32_t dex_pc_;
+
+  // Whether this is a sparse-switch table (or a packed-switch one).
+  const bool sparse_;
+
+  // This can't be const as it needs to be computed off of the given instruction, and complicated
+  // expressions in the initializer list seemed very ugly.
+  uint16_t num_entries_;
+
+  const int32_t* values_;
+
+  DISALLOW_COPY_AND_ASSIGN(SwitchTable);
+};
 
 void HGraphBuilder::InitializeLocals(uint16_t count) {
   graph_->SetNumberOfVRegs(count);
@@ -79,10 +147,10 @@
   }
 }
 
-bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
+void HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
   // dex_compilation_unit_ is null only when unit testing.
   if (dex_compilation_unit_ == nullptr) {
-    return true;
+    return;
   }
 
   graph_->SetNumberOfInVRegs(number_of_parameters);
@@ -102,87 +170,102 @@
 
   uint32_t pos = 1;
   for (int i = 0; i < number_of_parameters; i++) {
-    switch (shorty[pos++]) {
-      case 'F':
-      case 'D': {
-        return false;
-      }
-
-      default: {
-        // integer and reference parameters.
-        HParameterValue* parameter =
-            new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos - 1]));
-        entry_block_->AddInstruction(parameter);
-        HLocal* local = GetLocalAt(locals_index++);
-        // Store the parameter value in the local that the dex code will use
-        // to reference that parameter.
-        entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
-        if (parameter->GetType() == Primitive::kPrimLong) {
-          i++;
-          locals_index++;
-          parameter_index++;
-        }
-        break;
-      }
+    HParameterValue* parameter =
+        new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos++]));
+    entry_block_->AddInstruction(parameter);
+    HLocal* local = GetLocalAt(locals_index++);
+    // Store the parameter value in the local that the dex code will use
+    // to reference that parameter.
+    entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+    bool is_wide = (parameter->GetType() == Primitive::kPrimLong)
+        || (parameter->GetType() == Primitive::kPrimDouble);
+    if (is_wide) {
+      i++;
+      locals_index++;
+      parameter_index++;
     }
   }
-  return true;
-}
-
-static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
-  if (code_item.tries_size_ > 0) {
-    return false;
-  }
-  return true;
 }
 
 template<typename T>
-void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) {
+void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_pc) {
   int32_t target_offset = instruction.GetTargetOffset();
-  PotentiallyAddSuspendCheck(target_offset, dex_offset);
+  PotentiallyAddSuspendCheck(target_offset, dex_pc);
   HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
   HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
   T* comparison = new (arena_) T(first, second);
   current_block_->AddInstruction(comparison);
   HInstruction* ifinst = new (arena_) HIf(comparison);
   current_block_->AddInstruction(ifinst);
-  HBasicBlock* target = FindBlockStartingAt(dex_offset + target_offset);
+  HBasicBlock* target = FindBlockStartingAt(dex_pc + target_offset);
   DCHECK(target != nullptr);
   current_block_->AddSuccessor(target);
-  target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
+  target = FindBlockStartingAt(dex_pc + instruction.SizeInCodeUnits());
   DCHECK(target != nullptr);
   current_block_->AddSuccessor(target);
   current_block_ = nullptr;
 }
 
 template<typename T>
-void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset) {
+void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_pc) {
   int32_t target_offset = instruction.GetTargetOffset();
-  PotentiallyAddSuspendCheck(target_offset, dex_offset);
+  PotentiallyAddSuspendCheck(target_offset, dex_pc);
   HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
   T* comparison = new (arena_) T(value, GetIntConstant(0));
   current_block_->AddInstruction(comparison);
   HInstruction* ifinst = new (arena_) HIf(comparison);
   current_block_->AddInstruction(ifinst);
-  HBasicBlock* target = FindBlockStartingAt(dex_offset + target_offset);
+  HBasicBlock* target = FindBlockStartingAt(dex_pc + target_offset);
   DCHECK(target != nullptr);
   current_block_->AddSuccessor(target);
-  target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
+  target = FindBlockStartingAt(dex_pc + instruction.SizeInCodeUnits());
   DCHECK(target != nullptr);
   current_block_->AddSuccessor(target);
   current_block_ = nullptr;
 }
 
-HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
-  if (!CanHandleCodeItem(code_item)) {
-    return nullptr;
+void HGraphBuilder::MaybeRecordStat(MethodCompilationStat compilation_stat) {
+  if (compilation_stats_ != nullptr) {
+    compilation_stats_->RecordStat(compilation_stat);
+  }
+}
+
+bool HGraphBuilder::SkipCompilation(size_t number_of_dex_instructions,
+                                    size_t number_of_blocks ATTRIBUTE_UNUSED,
+                                    size_t number_of_branches) {
+  const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions();
+  CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter();
+  if (compiler_filter == CompilerOptions::kEverything) {
+    return false;
   }
 
+  if (compiler_options.IsHugeMethod(number_of_dex_instructions)) {
+    VLOG(compiler) << "Skip compilation of huge method "
+                   << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
+                   << ": " << number_of_dex_instructions << " dex instructions";
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledHugeMethod);
+    return true;
+  }
+
+  // If it's large and contains no branches, it's likely to be machine generated initialization.
+  if (compiler_options.IsLargeMethod(number_of_dex_instructions) && (number_of_branches == 0)) {
+    VLOG(compiler) << "Skip compilation of large method with no branch "
+                   << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
+                   << ": " << number_of_dex_instructions << " dex instructions";
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledLargeMethodNoBranches);
+    return true;
+  }
+
+  return false;
+}
+
+HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item, int start_instruction_id) {
   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_);
+  graph_ = new (arena_) HGraph(arena_, start_instruction_id);
   entry_block_ = new (arena_) HBasicBlock(graph_, 0);
   graph_->AddBlock(entry_block_);
   exit_block_ = new (arena_) HBasicBlock(graph_, kNoDexPc);
@@ -190,23 +273,55 @@
   graph_->SetExitBlock(exit_block_);
 
   InitializeLocals(code_item.registers_size_);
-  graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
+  graph_->SetMaximumNumberOfOutVRegs(code_item.outs_size_);
+
+  // Compute the number of dex instructions, blocks, and branches. We will
+  // check these values against limits given to the compiler.
+  size_t number_of_dex_instructions = 0;
+  size_t number_of_blocks = 0;
+  size_t number_of_branches = 0;
 
   // To avoid splitting blocks, we compute ahead of time the instructions that
   // start a new block, and create these blocks.
-  ComputeBranchTargets(code_ptr, code_end);
+  ComputeBranchTargets(
+      code_ptr, code_end, &number_of_dex_instructions, &number_of_blocks, &number_of_branches);
 
-  if (!InitializeParameters(code_item.ins_size_)) {
+  // Note that the compiler driver is null when unit testing.
+  if ((compiler_driver_ != nullptr)
+      && SkipCompilation(number_of_dex_instructions, number_of_blocks, number_of_branches)) {
     return nullptr;
   }
 
-  size_t dex_offset = 0;
+  // Also create blocks for catch handlers.
+  if (code_item.tries_size_ != 0) {
+    const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item, 0);
+    uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+    for (uint32_t idx = 0; idx < handlers_size; ++idx) {
+      CatchHandlerIterator iterator(handlers_ptr);
+      for (; iterator.HasNext(); iterator.Next()) {
+        uint32_t address = iterator.GetHandlerAddress();
+        HBasicBlock* block = FindBlockStartingAt(address);
+        if (block == nullptr) {
+          block = new (arena_) HBasicBlock(graph_, address);
+          branch_targets_.Put(address, block);
+        }
+        block->SetIsCatchBlock();
+      }
+      handlers_ptr = iterator.EndDataPointer();
+    }
+  }
+
+  InitializeParameters(code_item.ins_size_);
+
+  size_t dex_pc = 0;
   while (code_ptr < code_end) {
-    // Update the current block if dex_offset starts a new block.
-    MaybeUpdateCurrentBlock(dex_offset);
+    // Update the current block if dex_pc starts a new block.
+    MaybeUpdateCurrentBlock(dex_pc);
     const Instruction& instruction = *Instruction::At(code_ptr);
-    if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
-    dex_offset += instruction.SizeInCodeUnits();
+    if (!AnalyzeDexInstruction(instruction, dex_pc)) {
+      return nullptr;
+    }
+    dex_pc += instruction.SizeInCodeUnits();
     code_ptr += instruction.SizeInCodeUnits();
   }
 
@@ -236,8 +351,11 @@
   current_block_ = block;
 }
 
-void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
-  // TODO: Support switch instructions.
+void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr,
+                                         const uint16_t* code_end,
+                                         size_t* number_of_dex_instructions,
+                                         size_t* number_of_blocks,
+                                         size_t* number_of_branches) {
   branch_targets_.SetSize(code_end - code_ptr);
 
   // Create the first block for the dex instructions, single successor of the entry block.
@@ -247,25 +365,64 @@
 
   // Iterate over all instructions and find branching instructions. Create blocks for
   // the locations these instructions branch to.
-  size_t dex_offset = 0;
+  uint32_t dex_pc = 0;
   while (code_ptr < code_end) {
+    (*number_of_dex_instructions)++;
     const Instruction& instruction = *Instruction::At(code_ptr);
     if (instruction.IsBranch()) {
-      int32_t target = instruction.GetTargetOffset() + dex_offset;
+      (*number_of_branches)++;
+      int32_t target = instruction.GetTargetOffset() + dex_pc;
       // Create a block for the target instruction.
       if (FindBlockStartingAt(target) == nullptr) {
         block = new (arena_) HBasicBlock(graph_, target);
         branch_targets_.Put(target, block);
+        (*number_of_blocks)++;
       }
-      dex_offset += instruction.SizeInCodeUnits();
+      dex_pc += instruction.SizeInCodeUnits();
       code_ptr += instruction.SizeInCodeUnits();
-      if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
-        block = new (arena_) HBasicBlock(graph_, dex_offset);
-        branch_targets_.Put(dex_offset, block);
+      if ((code_ptr < code_end) && (FindBlockStartingAt(dex_pc) == nullptr)) {
+        block = new (arena_) HBasicBlock(graph_, dex_pc);
+        branch_targets_.Put(dex_pc, block);
+        (*number_of_blocks)++;
+      }
+    } else if (instruction.IsSwitch()) {
+      SwitchTable table(instruction, dex_pc, instruction.Opcode() == Instruction::SPARSE_SWITCH);
+
+      uint16_t num_entries = table.GetNumEntries();
+
+      // In a packed-switch, the entry at index 0 is the starting key. In a sparse-switch, the
+      // entry at index 0 is the first key, and values are after *all* keys.
+      size_t offset = table.GetFirstValueIndex();
+
+      // Use a larger loop counter type to avoid overflow issues.
+      for (size_t i = 0; i < num_entries; ++i) {
+        // The target of the case.
+        uint32_t target = dex_pc + table.GetEntryAt(i + offset);
+        if (FindBlockStartingAt(target) == nullptr) {
+          block = new (arena_) HBasicBlock(graph_, target);
+          branch_targets_.Put(target, block);
+          (*number_of_blocks)++;
+        }
+
+        // The next case gets its own block.
+        if (i < num_entries) {
+          block = new (arena_) HBasicBlock(graph_, target);
+          branch_targets_.Put(table.GetDexPcForIndex(i), block);
+          (*number_of_blocks)++;
+        }
+      }
+
+      // Fall-through. Add a block if there is more code afterwards.
+      dex_pc += instruction.SizeInCodeUnits();
+      code_ptr += instruction.SizeInCodeUnits();
+      if ((code_ptr < code_end) && (FindBlockStartingAt(dex_pc) == nullptr)) {
+        block = new (arena_) HBasicBlock(graph_, dex_pc);
+        branch_targets_.Put(dex_pc, block);
+        (*number_of_blocks)++;
       }
     } else {
       code_ptr += instruction.SizeInCodeUnits();
-      dex_offset += instruction.SizeInCodeUnits();
+      dex_pc += instruction.SizeInCodeUnits();
     }
   }
 }
@@ -276,6 +433,22 @@
 }
 
 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());
+}
+
+void HGraphBuilder::Conversion_12x(const Instruction& instruction,
+                                   Primitive::Type input_type,
+                                   Primitive::Type result_type,
+                                   uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), input_type);
+  current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first, dex_pc));
+  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);
@@ -284,6 +457,34 @@
 }
 
 template<typename T>
+void HGraphBuilder::Binop_23x(const Instruction& instruction,
+                              Primitive::Type type,
+                              uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type);
+  HInstruction* second = LoadLocal(instruction.VRegC(), type);
+  current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
+template<typename T>
+void HGraphBuilder::Binop_23x_shift(const Instruction& instruction,
+                                    Primitive::Type type) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type);
+  HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt);
+  current_block_->AddInstruction(new (arena_) T(type, first, second));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
+void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction,
+                                  Primitive::Type type,
+                                  HCompare::Bias bias) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type);
+  HInstruction* second = LoadLocal(instruction.VRegC(), type);
+  current_block_->AddInstruction(new (arena_) HCompare(type, first, second, bias));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
+template<typename T>
 void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) {
   HInstruction* first = LoadLocal(instruction.VRegA(), type);
   HInstruction* second = LoadLocal(instruction.VRegB(), type);
@@ -292,6 +493,24 @@
 }
 
 template<typename T>
+void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type) {
+  HInstruction* first = LoadLocal(instruction.VRegA(), type);
+  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
+  current_block_->AddInstruction(new (arena_) T(type, first, second));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
+template<typename T>
+void HGraphBuilder::Binop_12x(const Instruction& instruction,
+                              Primitive::Type type,
+                              uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegA(), type);
+  HInstruction* second = LoadLocal(instruction.VRegB(), type);
+  current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
+template<typename T>
 void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
   HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
   HInstruction* second = GetIntConstant(instruction.VRegC_22s());
@@ -325,7 +544,7 @@
 }
 
 bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
-                                uint32_t dex_offset,
+                                uint32_t dex_pc,
                                 uint32_t method_idx,
                                 uint32_t number_of_vreg_arguments,
                                 bool is_range,
@@ -366,32 +585,44 @@
   bool is_instance_call = invoke_type != kStatic;
   const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
 
+  MethodReference target_method(dex_file_, method_idx);
+  uintptr_t direct_code;
+  uintptr_t direct_method;
+  int table_index;
+  InvokeType optimized_invoke_type = invoke_type;
+
+  if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true, true,
+                                           &optimized_invoke_type, &target_method, &table_index,
+                                           &direct_code, &direct_method)) {
+    VLOG(compiler) << "Did not compile " << PrettyMethod(method_idx, *dex_file_)
+                   << " because a method call could not be resolved";
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod);
+    return false;
+  }
+  DCHECK(optimized_invoke_type != kSuper);
+
   HInvoke* invoke = nullptr;
-  if (invoke_type == kVirtual) {
-    MethodReference target_method(dex_file_, method_idx);
-    uintptr_t direct_code;
-    uintptr_t direct_method;
-    int vtable_index;
-    // TODO: Add devirtualization support.
-    compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_offset, true, true,
-                                        &invoke_type, &target_method, &vtable_index,
-                                        &direct_code, &direct_method);
-    if (vtable_index == -1) {
-      return false;
-    }
+  if (optimized_invoke_type == kVirtual) {
     invoke = new (arena_) HInvokeVirtual(
-        arena_, number_of_arguments, return_type, dex_offset, vtable_index);
+        arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index);
+  } else if (optimized_invoke_type == kInterface) {
+    invoke = new (arena_) HInvokeInterface(
+        arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index);
   } else {
-    // Treat invoke-direct like static calls for now.
-    invoke = new (arena_) HInvokeStatic(
-        arena_, number_of_arguments, return_type, dex_offset, method_idx);
+    DCHECK(optimized_invoke_type == kDirect || optimized_invoke_type == kStatic);
+    // Sharpening to kDirect only works if we compile PIC.
+    DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect)
+           || compiler_driver_->GetCompilerOptions().GetCompilePic());
+    invoke = new (arena_) HInvokeStaticOrDirect(
+        arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index,
+        optimized_invoke_type);
   }
 
   size_t start_index = 0;
-  Temporaries temps(graph_, is_instance_call ? 1 : 0);
+  Temporaries temps(graph_);
   if (is_instance_call) {
     HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
-    HNullCheck* null_check = new (arena_) HNullCheck(arg, dex_offset);
+    HNullCheck* null_check = new (arena_) HNullCheck(arg, dex_pc);
     current_block_->AddInstruction(null_check);
     temps.Add(null_check);
     invoke->SetArgumentAt(0, null_check);
@@ -402,34 +633,30 @@
   uint32_t argument_index = start_index;
   for (size_t i = start_index; i < number_of_vreg_arguments; i++, argument_index++) {
     Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
-    if (!IsTypeSupported(type)) {
-      return false;
-    }
-    if (!is_range && type == Primitive::kPrimLong && args[i] + 1 != args[i + 1]) {
+    bool is_wide = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble);
+    if (!is_range && is_wide && args[i] + 1 != args[i + 1]) {
       LOG(WARNING) << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol()
-                   << " at " << dex_offset;
+                   << " at " << dex_pc;
       // We do not implement non sequential register pair.
+      MaybeRecordStat(MethodCompilationStat::kNotCompiledNonSequentialRegPair);
       return false;
     }
     HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
     invoke->SetArgumentAt(argument_index, arg);
-    if (type == Primitive::kPrimLong) {
+    if (is_wide) {
       i++;
     }
   }
 
-  if (!IsTypeSupported(return_type)) {
-    return false;
-  }
-
   DCHECK_EQ(argument_index, number_of_arguments);
   current_block_->AddInstruction(invoke);
+  latest_result_ = invoke;
   return true;
 }
 
-bool HGraphBuilder::BuildFieldAccess(const Instruction& instruction,
-                                     uint32_t dex_offset,
-                                     bool is_put) {
+bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
+                                             uint32_t dex_pc,
+                                             bool is_put) {
   uint32_t source_or_dest_reg = instruction.VRegA_22c();
   uint32_t obj_reg = instruction.VRegB_22c();
   uint16_t field_index = instruction.VRegC_22c();
@@ -440,21 +667,16 @@
       compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa)));
 
   if (resolved_field.Get() == nullptr) {
-    return false;
-  }
-  if (resolved_field->IsVolatile()) {
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedField);
     return false;
   }
 
   Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
-  if (!IsTypeSupported(field_type)) {
-    return false;
-  }
 
   HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot);
-  current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_offset));
+  current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_pc));
   if (is_put) {
-    Temporaries temps(graph_, 1);
+    Temporaries temps(graph_);
     HInstruction* null_check = current_block_->GetLastInstruction();
     // We need one temporary for the null check.
     temps.Add(null_check);
@@ -463,33 +685,137 @@
         null_check,
         value,
         field_type,
-        resolved_field->GetOffset()));
+        resolved_field->GetOffset(),
+        resolved_field->IsVolatile()));
   } else {
     current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
         current_block_->GetLastInstruction(),
         field_type,
-        resolved_field->GetOffset()));
+        resolved_field->GetOffset(),
+        resolved_field->IsVolatile()));
 
     UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
   }
   return true;
 }
 
+bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
+                                           uint32_t dex_pc,
+                                           bool is_put) {
+  uint32_t source_or_dest_reg = instruction.VRegA_21c();
+  uint16_t field_index = instruction.VRegB_21c();
+
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<4> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(
+      dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile())));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+  Handle<mirror::ArtField> resolved_field(hs.NewHandle(compiler_driver_->ResolveField(
+      soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true)));
+
+  if (resolved_field.Get() == nullptr) {
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedField);
+    return false;
+  }
+
+  Handle<mirror::Class> referrer_class(hs.NewHandle(compiler_driver_->ResolveCompilingMethodsClass(
+      soa, dex_cache, class_loader, outer_compilation_unit_)));
+
+  // The index at which the field's class is stored in the DexCache's type array.
+  uint32_t storage_index;
+  std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField(
+      dex_cache.Get(), referrer_class.Get(), resolved_field.Get(), field_index, &storage_index);
+  bool can_easily_access = is_put ? pair.second : pair.first;
+  if (!can_easily_access) {
+    return false;
+  }
+
+  // TODO: find out why this check is needed.
+  bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache(
+      *outer_compilation_unit_->GetDexFile(), storage_index);
+  bool is_initialized = resolved_field->GetDeclaringClass()->IsInitialized() && is_in_dex_cache;
+  bool is_referrer_class = (referrer_class.Get() == resolved_field->GetDeclaringClass());
+
+  HLoadClass* constant = new (arena_) HLoadClass(storage_index, is_referrer_class, dex_pc);
+  current_block_->AddInstruction(constant);
+
+  HInstruction* cls = constant;
+  if (!is_initialized && !is_referrer_class) {
+    cls = new (arena_) HClinitCheck(constant, dex_pc);
+    current_block_->AddInstruction(cls);
+  }
+
+  Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
+  if (is_put) {
+    // We need to keep the class alive before loading the value.
+    Temporaries temps(graph_);
+    temps.Add(cls);
+    HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
+    DCHECK_EQ(value->GetType(), field_type);
+    current_block_->AddInstruction(
+        new (arena_) HStaticFieldSet(cls, value, field_type, resolved_field->GetOffset(),
+            resolved_field->IsVolatile()));
+  } else {
+    current_block_->AddInstruction(
+        new (arena_) HStaticFieldGet(cls, field_type, resolved_field->GetOffset(),
+            resolved_field->IsVolatile()));
+    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+  }
+  return true;
+}
+
+void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg,
+                                       uint16_t first_vreg,
+                                       int64_t second_vreg_or_constant,
+                                       uint32_t dex_pc,
+                                       Primitive::Type type,
+                                       bool second_is_constant,
+                                       bool isDiv) {
+  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+  HInstruction* first = LoadLocal(first_vreg, type);
+  HInstruction* second = nullptr;
+  if (second_is_constant) {
+    if (type == Primitive::kPrimInt) {
+      second = GetIntConstant(second_vreg_or_constant);
+    } else {
+      second = GetLongConstant(second_vreg_or_constant);
+    }
+  } else {
+    second = LoadLocal(second_vreg_or_constant, type);
+  }
+
+  if (!second_is_constant
+      || (type == Primitive::kPrimInt && second->AsIntConstant()->GetValue() == 0)
+      || (type == Primitive::kPrimLong && second->AsLongConstant()->GetValue() == 0)) {
+    second = new (arena_) HDivZeroCheck(second, dex_pc);
+    Temporaries temps(graph_);
+    current_block_->AddInstruction(second);
+    temps.Add(current_block_->GetLastInstruction());
+  }
+
+  if (isDiv) {
+    current_block_->AddInstruction(new (arena_) HDiv(type, first, second, dex_pc));
+  } else {
+    current_block_->AddInstruction(new (arena_) HRem(type, first, second, dex_pc));
+  }
+  UpdateLocal(out_vreg, current_block_->GetLastInstruction());
+}
+
 void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
-                                     uint32_t dex_offset,
+                                     uint32_t dex_pc,
                                      bool is_put,
                                      Primitive::Type anticipated_type) {
   uint8_t source_or_dest_reg = instruction.VRegA_23x();
   uint8_t array_reg = instruction.VRegB_23x();
   uint8_t index_reg = instruction.VRegC_23x();
 
-  DCHECK(IsTypeSupported(anticipated_type));
-
   // We need one temporary for the null check, one for the index, and one for the length.
-  Temporaries temps(graph_, 3);
+  Temporaries temps(graph_);
 
   HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot);
-  object = new (arena_) HNullCheck(object, dex_offset);
+  object = new (arena_) HNullCheck(object, dex_pc);
   current_block_->AddInstruction(object);
   temps.Add(object);
 
@@ -497,29 +823,253 @@
   current_block_->AddInstruction(length);
   temps.Add(length);
   HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
-  index = new (arena_) HBoundsCheck(index, length, dex_offset);
+  index = new (arena_) HBoundsCheck(index, length, dex_pc);
   current_block_->AddInstruction(index);
   temps.Add(index);
   if (is_put) {
     HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type);
     // TODO: Insert a type check node if the type is Object.
     current_block_->AddInstruction(new (arena_) HArraySet(
-        object, index, value, anticipated_type, dex_offset));
+        object, index, value, anticipated_type, dex_pc));
   } else {
     current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type));
     UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
   }
 }
 
-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
-    // them after we recognize loops in the graph.
-    current_block_->AddInstruction(new (arena_) HSuspendCheck(dex_offset));
+void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc,
+                                        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_pc, 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_);
+  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_pc));
+  }
+  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_pc) {
+  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_pc));
   }
 }
 
-bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_offset) {
+void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
+  Temporaries temps(graph_);
+  HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
+  HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc);
+  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_pc;
+  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_pc));
+
+  switch (payload->element_width) {
+    case 1:
+      BuildFillArrayData(null_check,
+                         reinterpret_cast<const int8_t*>(data),
+                         element_count,
+                         Primitive::kPrimByte,
+                         dex_pc);
+      break;
+    case 2:
+      BuildFillArrayData(null_check,
+                         reinterpret_cast<const int16_t*>(data),
+                         element_count,
+                         Primitive::kPrimShort,
+                         dex_pc);
+      break;
+    case 4:
+      BuildFillArrayData(null_check,
+                         reinterpret_cast<const int32_t*>(data),
+                         element_count,
+                         Primitive::kPrimInt,
+                         dex_pc);
+      break;
+    case 8:
+      BuildFillWideArrayData(null_check,
+                             reinterpret_cast<const int64_t*>(data),
+                             element_count,
+                             dex_pc);
+      break;
+    default:
+      LOG(FATAL) << "Unknown element width for " << payload->element_width;
+  }
+}
+
+void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
+                                           const int64_t* data,
+                                           uint32_t element_count,
+                                           uint32_t dex_pc) {
+  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_pc));
+  }
+}
+
+bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
+                                   uint8_t destination,
+                                   uint8_t reference,
+                                   uint16_t type_index,
+                                   uint32_t dex_pc) {
+  bool type_known_final;
+  bool type_known_abstract;
+  // `CanAccessTypeWithoutChecks` will tell whether the method being
+  // built is trying to access its own class, so that the generated
+  // code can optimize for this case. However, the optimization does not
+  // work for inlining, so we use `IsCompilingClass` instead.
+  bool dont_use_is_referrers_class;
+  bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
+      dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index,
+      &type_known_final, &type_known_abstract, &dont_use_is_referrers_class);
+  if (!can_access) {
+    MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
+    return false;
+  }
+  HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
+  HLoadClass* cls = new (arena_) HLoadClass(type_index, IsCompilingClass(type_index), dex_pc);
+  current_block_->AddInstruction(cls);
+  // The class needs a temporary before being used by the type check.
+  Temporaries temps(graph_);
+  temps.Add(cls);
+  if (instruction.Opcode() == Instruction::INSTANCE_OF) {
+    current_block_->AddInstruction(
+        new (arena_) HInstanceOf(object, cls, type_known_final, dex_pc));
+    UpdateLocal(destination, current_block_->GetLastInstruction());
+  } else {
+    DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST);
+    current_block_->AddInstruction(
+        new (arena_) HCheckCast(object, cls, type_known_final, dex_pc));
+  }
+  return true;
+}
+
+void HGraphBuilder::BuildPackedSwitch(const Instruction& instruction, uint32_t dex_pc) {
+  SwitchTable table(instruction, dex_pc, false);
+
+  // Value to test against.
+  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+
+  uint16_t num_entries = table.GetNumEntries();
+  // There should be at least one entry here.
+  DCHECK_GT(num_entries, 0U);
+
+  // Chained cmp-and-branch, starting from starting_key.
+  int32_t starting_key = table.GetEntryAt(0);
+
+  for (size_t i = 1; i <= num_entries; i++) {
+    BuildSwitchCaseHelper(instruction, i, i == num_entries, table, value, starting_key + i - 1,
+                          table.GetEntryAt(i), dex_pc);
+  }
+}
+
+void HGraphBuilder::BuildSparseSwitch(const Instruction& instruction, uint32_t dex_pc) {
+  SwitchTable table(instruction, dex_pc, true);
+
+  // Value to test against.
+  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+
+  uint16_t num_entries = table.GetNumEntries();
+  // There should be at least one entry here.
+  DCHECK_GT(num_entries, 0U);
+
+  for (size_t i = 0; i < num_entries; i++) {
+    BuildSwitchCaseHelper(instruction, i, i == static_cast<size_t>(num_entries) - 1, table, value,
+                          table.GetEntryAt(i), table.GetEntryAt(i + num_entries), dex_pc);
+  }
+}
+
+void HGraphBuilder::BuildSwitchCaseHelper(const Instruction& instruction, size_t index,
+                                          bool is_last_case, const SwitchTable& table,
+                                          HInstruction* value, int32_t case_value_int,
+                                          int32_t target_offset, uint32_t dex_pc) {
+  PotentiallyAddSuspendCheck(target_offset, dex_pc);
+
+  // The current case's value.
+  HInstruction* this_case_value = GetIntConstant(case_value_int);
+
+  // Compare value and this_case_value.
+  HEqual* comparison = new (arena_) HEqual(value, this_case_value);
+  current_block_->AddInstruction(comparison);
+  HInstruction* ifinst = new (arena_) HIf(comparison);
+  current_block_->AddInstruction(ifinst);
+
+  // Case hit: use the target offset to determine where to go.
+  HBasicBlock* case_target = FindBlockStartingAt(dex_pc + target_offset);
+  DCHECK(case_target != nullptr);
+  current_block_->AddSuccessor(case_target);
+
+  // Case miss: go to the next case (or default fall-through).
+  // When there is a next case, we use the block stored with the table offset representing this
+  // case (that is where we registered them in ComputeBranchTargets).
+  // When there is no next case, we use the following instruction.
+  // TODO: Find a good way to peel the last iteration to avoid conditional, but still have re-use.
+  if (!is_last_case) {
+    HBasicBlock* next_case_target = FindBlockStartingAt(table.GetDexPcForIndex(index));
+    DCHECK(next_case_target != nullptr);
+    current_block_->AddSuccessor(next_case_target);
+
+    // Need to manually add the block, as there is no dex-pc transition for the cases.
+    graph_->AddBlock(next_case_target);
+
+    current_block_ = next_case_target;
+  } else {
+    HBasicBlock* default_target = FindBlockStartingAt(dex_pc + instruction.SizeInCodeUnits());
+    DCHECK(default_target != nullptr);
+    current_block_->AddSuccessor(default_target);
+    current_block_ = nullptr;
+  }
+}
+
+void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_pc) {
+  if (target_offset <= 0) {
+    // Unconditionnally add a suspend check to backward branches. We can remove
+    // them after we recognize loops in the graph.
+    current_block_->AddInstruction(new (arena_) HSuspendCheck(dex_pc));
+  }
+}
+
+bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_pc) {
   if (current_block_ == nullptr) {
     return true;  // Dead code
   }
@@ -590,8 +1140,7 @@
       break;
     }
 
-    // TODO: these instructions are also used to move floating point values, so what is
-    // the type (int or float)?
+    // Note that the SSA building will refine the types.
     case Instruction::MOVE:
     case Instruction::MOVE_FROM16:
     case Instruction::MOVE_16: {
@@ -600,8 +1149,7 @@
       break;
     }
 
-    // TODO: these instructions are also used to move floating point values, so what is
-    // the type (long or double)?
+    // Note that the SSA building will refine the types.
     case Instruction::MOVE_WIDE:
     case Instruction::MOVE_WIDE_FROM16:
     case Instruction::MOVE_WIDE_16: {
@@ -624,8 +1172,8 @@
     }
 
 #define IF_XX(comparison, cond) \
-    case Instruction::IF_##cond: If_22t<comparison>(instruction, dex_offset); break; \
-    case Instruction::IF_##cond##Z: If_21t<comparison>(instruction, dex_offset); break
+    case Instruction::IF_##cond: If_22t<comparison>(instruction, dex_pc); break; \
+    case Instruction::IF_##cond##Z: If_21t<comparison>(instruction, dex_pc); break
 
     IF_XX(HEqual, EQ);
     IF_XX(HNotEqual, NE);
@@ -638,8 +1186,8 @@
     case Instruction::GOTO_16:
     case Instruction::GOTO_32: {
       int32_t offset = instruction.GetTargetOffset();
-      PotentiallyAddSuspendCheck(offset, dex_offset);
-      HBasicBlock* target = FindBlockStartingAt(offset + dex_offset);
+      PotentiallyAddSuspendCheck(offset, dex_pc);
+      HBasicBlock* target = FindBlockStartingAt(offset + dex_pc);
       DCHECK(target != nullptr);
       current_block_->AddInstruction(new (arena_) HGoto());
       current_block_->AddSuccessor(target);
@@ -648,46 +1196,161 @@
     }
 
     case Instruction::RETURN: {
-      BuildReturn(instruction, Primitive::kPrimInt);
+      DCHECK_NE(return_type_, Primitive::kPrimNot);
+      DCHECK_NE(return_type_, Primitive::kPrimLong);
+      DCHECK_NE(return_type_, Primitive::kPrimDouble);
+      BuildReturn(instruction, return_type_);
       break;
     }
 
     case Instruction::RETURN_OBJECT: {
-      BuildReturn(instruction, Primitive::kPrimNot);
+      DCHECK(return_type_ == Primitive::kPrimNot);
+      BuildReturn(instruction, return_type_);
       break;
     }
 
     case Instruction::RETURN_WIDE: {
-      BuildReturn(instruction, Primitive::kPrimLong);
+      DCHECK(return_type_ == Primitive::kPrimDouble || return_type_ == Primitive::kPrimLong);
+      BuildReturn(instruction, return_type_);
       break;
     }
 
-    case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_DIRECT:
+    case Instruction::INVOKE_INTERFACE:
+    case Instruction::INVOKE_STATIC:
+    case Instruction::INVOKE_SUPER:
     case Instruction::INVOKE_VIRTUAL: {
       uint32_t method_idx = instruction.VRegB_35c();
       uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
       uint32_t args[5];
       instruction.GetVarArgs(args);
-      if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
+      if (!BuildInvoke(instruction, dex_pc, method_idx,
+                       number_of_vreg_arguments, false, args, -1)) {
         return false;
       }
       break;
     }
 
-    case Instruction::INVOKE_STATIC_RANGE:
     case Instruction::INVOKE_DIRECT_RANGE:
+    case Instruction::INVOKE_INTERFACE_RANGE:
+    case Instruction::INVOKE_STATIC_RANGE:
+    case Instruction::INVOKE_SUPER_RANGE:
     case Instruction::INVOKE_VIRTUAL_RANGE: {
       uint32_t method_idx = instruction.VRegB_3rc();
       uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
       uint32_t register_index = instruction.VRegC();
-      if (!BuildInvoke(instruction, dex_offset, method_idx,
+      if (!BuildInvoke(instruction, dex_pc, method_idx,
                        number_of_vreg_arguments, true, nullptr, register_index)) {
         return false;
       }
       break;
     }
 
+    case Instruction::NEG_INT: {
+      Unop_12x<HNeg>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::NEG_LONG: {
+      Unop_12x<HNeg>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::NEG_FLOAT: {
+      Unop_12x<HNeg>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::NEG_DOUBLE: {
+      Unop_12x<HNeg>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
+    case Instruction::NOT_INT: {
+      Unop_12x<HNot>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::NOT_LONG: {
+      Unop_12x<HNot>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::INT_TO_LONG: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong, dex_pc);
+      break;
+    }
+
+    case Instruction::INT_TO_FLOAT: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::INT_TO_DOUBLE: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::LONG_TO_INT: {
+      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt, dex_pc);
+      break;
+    }
+
+    case Instruction::LONG_TO_FLOAT: {
+      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::LONG_TO_DOUBLE: {
+      Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::FLOAT_TO_INT: {
+      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt, dex_pc);
+      break;
+    }
+
+    case Instruction::FLOAT_TO_LONG: {
+      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimLong, dex_pc);
+      break;
+    }
+
+    case Instruction::FLOAT_TO_DOUBLE: {
+      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::DOUBLE_TO_INT: {
+      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimInt, dex_pc);
+      break;
+    }
+
+    case Instruction::DOUBLE_TO_LONG: {
+      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimLong, dex_pc);
+      break;
+    }
+
+    case Instruction::DOUBLE_TO_FLOAT: {
+      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::INT_TO_BYTE: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte, dex_pc);
+      break;
+    }
+
+    case Instruction::INT_TO_SHORT: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimShort, dex_pc);
+      break;
+    }
+
+    case Instruction::INT_TO_CHAR: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimChar, dex_pc);
+      break;
+    }
+
     case Instruction::ADD_INT: {
       Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
       break;
@@ -698,6 +1361,16 @@
       break;
     }
 
+    case Instruction::ADD_DOUBLE: {
+      Binop_23x<HAdd>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
+    case Instruction::ADD_FLOAT: {
+      Binop_23x<HAdd>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
     case Instruction::SUB_INT: {
       Binop_23x<HSub>(instruction, Primitive::kPrimInt);
       break;
@@ -708,16 +1381,160 @@
       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::DIV_INT: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+                         dex_pc, Primitive::kPrimInt, false, true);
+      break;
+    }
+
+    case Instruction::DIV_LONG: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+                         dex_pc, Primitive::kPrimLong, false, true);
+      break;
+    }
+
+    case Instruction::DIV_FLOAT: {
+      Binop_23x<HDiv>(instruction, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::DIV_DOUBLE: {
+      Binop_23x<HDiv>(instruction, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::REM_INT: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+                         dex_pc, Primitive::kPrimInt, false, false);
+      break;
+    }
+
+    case Instruction::REM_LONG: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+                         dex_pc, Primitive::kPrimLong, false, false);
+      break;
+    }
+
+    case Instruction::REM_FLOAT: {
+      Binop_23x<HRem>(instruction, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::REM_DOUBLE: {
+      Binop_23x<HRem>(instruction, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::AND_INT: {
+      Binop_23x<HAnd>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::AND_LONG: {
+      Binop_23x<HAnd>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::SHL_INT: {
+      Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::SHL_LONG: {
+      Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::SHR_INT: {
+      Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::SHR_LONG: {
+      Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::USHR_INT: {
+      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::USHR_LONG: {
+      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::OR_INT: {
+      Binop_23x<HOr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::OR_LONG: {
+      Binop_23x<HOr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::XOR_INT: {
+      Binop_23x<HXor>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::XOR_LONG: {
+      Binop_23x<HXor>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
     case Instruction::ADD_LONG_2ADDR: {
       Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
       break;
     }
 
+    case Instruction::ADD_DOUBLE_2ADDR: {
+      Binop_12x<HAdd>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
+    case Instruction::ADD_FLOAT_2ADDR: {
+      Binop_12x<HAdd>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
     case Instruction::SUB_INT_2ADDR: {
       Binop_12x<HSub>(instruction, Primitive::kPrimInt);
       break;
@@ -728,41 +1545,296 @@
       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::DIV_INT_2ADDR: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
+                         dex_pc, Primitive::kPrimInt, false, true);
+      break;
+    }
+
+    case Instruction::DIV_LONG_2ADDR: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
+                         dex_pc, Primitive::kPrimLong, false, true);
+      break;
+    }
+
+    case Instruction::REM_INT_2ADDR: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
+                         dex_pc, Primitive::kPrimInt, false, false);
+      break;
+    }
+
+    case Instruction::REM_LONG_2ADDR: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
+                         dex_pc, Primitive::kPrimLong, false, false);
+      break;
+    }
+
+    case Instruction::REM_FLOAT_2ADDR: {
+      Binop_12x<HRem>(instruction, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::REM_DOUBLE_2ADDR: {
+      Binop_12x<HRem>(instruction, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::SHL_INT_2ADDR: {
+      Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::SHL_LONG_2ADDR: {
+      Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::SHR_INT_2ADDR: {
+      Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::SHR_LONG_2ADDR: {
+      Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::USHR_INT_2ADDR: {
+      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::USHR_LONG_2ADDR: {
+      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::DIV_FLOAT_2ADDR: {
+      Binop_12x<HDiv>(instruction, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
+    case Instruction::DIV_DOUBLE_2ADDR: {
+      Binop_12x<HDiv>(instruction, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::AND_INT_2ADDR: {
+      Binop_12x<HAnd>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::AND_LONG_2ADDR: {
+      Binop_12x<HAnd>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::OR_INT_2ADDR: {
+      Binop_12x<HOr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::OR_LONG_2ADDR: {
+      Binop_12x<HOr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::XOR_INT_2ADDR: {
+      Binop_12x<HXor>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::XOR_LONG_2ADDR: {
+      Binop_12x<HXor>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
     case Instruction::ADD_INT_LIT16: {
       Binop_22s<HAdd>(instruction, false);
       break;
     }
 
+    case Instruction::AND_INT_LIT16: {
+      Binop_22s<HAnd>(instruction, false);
+      break;
+    }
+
+    case Instruction::OR_INT_LIT16: {
+      Binop_22s<HOr>(instruction, false);
+      break;
+    }
+
+    case Instruction::XOR_INT_LIT16: {
+      Binop_22s<HXor>(instruction, false);
+      break;
+    }
+
     case Instruction::RSUB_INT: {
       Binop_22s<HSub>(instruction, true);
       break;
     }
 
+    case Instruction::MUL_INT_LIT16: {
+      Binop_22s<HMul>(instruction, false);
+      break;
+    }
+
     case Instruction::ADD_INT_LIT8: {
       Binop_22b<HAdd>(instruction, false);
       break;
     }
 
+    case Instruction::AND_INT_LIT8: {
+      Binop_22b<HAnd>(instruction, false);
+      break;
+    }
+
+    case Instruction::OR_INT_LIT8: {
+      Binop_22b<HOr>(instruction, false);
+      break;
+    }
+
+    case Instruction::XOR_INT_LIT8: {
+      Binop_22b<HXor>(instruction, false);
+      break;
+    }
+
     case Instruction::RSUB_INT_LIT8: {
       Binop_22b<HSub>(instruction, true);
       break;
     }
 
+    case Instruction::MUL_INT_LIT8: {
+      Binop_22b<HMul>(instruction, false);
+      break;
+    }
+
+    case Instruction::DIV_INT_LIT16:
+    case Instruction::DIV_INT_LIT8: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+                         dex_pc, Primitive::kPrimInt, true, true);
+      break;
+    }
+
+    case Instruction::REM_INT_LIT16:
+    case Instruction::REM_INT_LIT8: {
+      BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+                         dex_pc, Primitive::kPrimInt, true, false);
+      break;
+    }
+
+    case Instruction::SHL_INT_LIT8: {
+      Binop_22b<HShl>(instruction, false);
+      break;
+    }
+
+    case Instruction::SHR_INT_LIT8: {
+      Binop_22b<HShr>(instruction, false);
+      break;
+    }
+
+    case Instruction::USHR_INT_LIT8: {
+      Binop_22b<HUShr>(instruction, false);
+      break;
+    }
+
     case Instruction::NEW_INSTANCE: {
       current_block_->AddInstruction(
-          new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
+          new (arena_) HNewInstance(dex_pc, instruction.VRegB_21c()));
       UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
       break;
     }
 
+    case Instruction::NEW_ARRAY: {
+      HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+      current_block_->AddInstruction(
+          new (arena_) HNewArray(length, dex_pc, 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_pc, 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_pc, type_index, number_of_vreg_arguments, true, nullptr, register_index);
+      break;
+    }
+
+    case Instruction::FILL_ARRAY_DATA: {
+      BuildFillArrayData(instruction, dex_pc);
+      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: {
-      Binop_23x<HCompare>(instruction, Primitive::kPrimLong);
+      Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias);
+      break;
+    }
+
+    case Instruction::CMPG_FLOAT: {
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias);
+      break;
+    }
+
+    case Instruction::CMPG_DOUBLE: {
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias);
+      break;
+    }
+
+    case Instruction::CMPL_FLOAT: {
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias);
+      break;
+    }
+
+    case Instruction::CMPL_DOUBLE: {
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias);
       break;
     }
 
@@ -776,7 +1848,7 @@
     case Instruction::IGET_BYTE:
     case Instruction::IGET_CHAR:
     case Instruction::IGET_SHORT: {
-      if (!BuildFieldAccess(instruction, dex_offset, false)) {
+      if (!BuildInstanceFieldAccess(instruction, dex_pc, false)) {
         return false;
       }
       break;
@@ -789,7 +1861,33 @@
     case Instruction::IPUT_BYTE:
     case Instruction::IPUT_CHAR:
     case Instruction::IPUT_SHORT: {
-      if (!BuildFieldAccess(instruction, dex_offset, true)) {
+      if (!BuildInstanceFieldAccess(instruction, dex_pc, true)) {
+        return false;
+      }
+      break;
+    }
+
+    case Instruction::SGET:
+    case Instruction::SGET_WIDE:
+    case Instruction::SGET_OBJECT:
+    case Instruction::SGET_BOOLEAN:
+    case Instruction::SGET_BYTE:
+    case Instruction::SGET_CHAR:
+    case Instruction::SGET_SHORT: {
+      if (!BuildStaticFieldAccess(instruction, dex_pc, false)) {
+        return false;
+      }
+      break;
+    }
+
+    case Instruction::SPUT:
+    case Instruction::SPUT_WIDE:
+    case Instruction::SPUT_OBJECT:
+    case Instruction::SPUT_BOOLEAN:
+    case Instruction::SPUT_BYTE:
+    case Instruction::SPUT_CHAR:
+    case Instruction::SPUT_SHORT: {
+      if (!BuildStaticFieldAccess(instruction, dex_pc, true)) {
         return false;
       }
       break;
@@ -797,11 +1895,11 @@
 
 #define ARRAY_XX(kind, anticipated_type)                                          \
     case Instruction::AGET##kind: {                                               \
-      BuildArrayAccess(instruction, dex_offset, false, anticipated_type);         \
+      BuildArrayAccess(instruction, dex_pc, false, anticipated_type);         \
       break;                                                                      \
     }                                                                             \
     case Instruction::APUT##kind: {                                               \
-      BuildArrayAccess(instruction, dex_offset, true, anticipated_type);          \
+      BuildArrayAccess(instruction, dex_pc, true, anticipated_type);          \
       break;                                                                      \
     }
 
@@ -815,16 +1913,121 @@
 
     case Instruction::ARRAY_LENGTH: {
       HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
+      // No need for a temporary for the null check, it is the only input of the following
+      // instruction.
+      object = new (arena_) HNullCheck(object, dex_pc);
+      current_block_->AddInstruction(object);
       current_block_->AddInstruction(new (arena_) HArrayLength(object));
       UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
       break;
     }
 
+    case Instruction::CONST_STRING: {
+      current_block_->AddInstruction(new (arena_) HLoadString(instruction.VRegB_21c(), dex_pc));
+      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+      break;
+    }
+
+    case Instruction::CONST_STRING_JUMBO: {
+      current_block_->AddInstruction(new (arena_) HLoadString(instruction.VRegB_31c(), dex_pc));
+      UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction());
+      break;
+    }
+
+    case Instruction::CONST_CLASS: {
+      uint16_t type_index = instruction.VRegB_21c();
+      bool type_known_final;
+      bool type_known_abstract;
+      bool dont_use_is_referrers_class;
+      // `CanAccessTypeWithoutChecks` will tell whether the method being
+      // built is trying to access its own class, so that the generated
+      // code can optimize for this case. However, the optimization does not
+      // work for inlining, so we use `IsCompilingClass` instead.
+      bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
+          dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index,
+          &type_known_final, &type_known_abstract, &dont_use_is_referrers_class);
+      if (!can_access) {
+        MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
+        return false;
+      }
+      current_block_->AddInstruction(
+          new (arena_) HLoadClass(type_index, IsCompilingClass(type_index), dex_pc));
+      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+      break;
+    }
+
+    case Instruction::MOVE_EXCEPTION: {
+      current_block_->AddInstruction(new (arena_) HLoadException());
+      UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
+      break;
+    }
+
+    case Instruction::THROW: {
+      HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot);
+      current_block_->AddInstruction(new (arena_) HThrow(exception, dex_pc));
+      // A throw instruction must branch to the exit block.
+      current_block_->AddSuccessor(exit_block_);
+      // We finished building this block. Set the current block to null to avoid
+      // adding dead instructions to it.
+      current_block_ = nullptr;
+      break;
+    }
+
+    case Instruction::INSTANCE_OF: {
+      uint8_t destination = instruction.VRegA_22c();
+      uint8_t reference = instruction.VRegB_22c();
+      uint16_t type_index = instruction.VRegC_22c();
+      if (!BuildTypeCheck(instruction, destination, reference, type_index, dex_pc)) {
+        return false;
+      }
+      break;
+    }
+
+    case Instruction::CHECK_CAST: {
+      uint8_t reference = instruction.VRegA_21c();
+      uint16_t type_index = instruction.VRegB_21c();
+      if (!BuildTypeCheck(instruction, -1, reference, type_index, dex_pc)) {
+        return false;
+      }
+      break;
+    }
+
+    case Instruction::MONITOR_ENTER: {
+      current_block_->AddInstruction(new (arena_) HMonitorOperation(
+          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+          HMonitorOperation::kEnter,
+          dex_pc));
+      break;
+    }
+
+    case Instruction::MONITOR_EXIT: {
+      current_block_->AddInstruction(new (arena_) HMonitorOperation(
+          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+          HMonitorOperation::kExit,
+          dex_pc));
+      break;
+    }
+
+    case Instruction::PACKED_SWITCH: {
+      BuildPackedSwitch(instruction, dex_pc);
+      break;
+    }
+
+    case Instruction::SPARSE_SWITCH: {
+      BuildSparseSwitch(instruction, dex_pc);
+      break;
+    }
+
     default:
+      VLOG(compiler) << "Did not compile "
+                     << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
+                     << " because of unhandled instruction "
+                     << instruction.Name();
+      MaybeRecordStat(MethodCompilationStat::kNotCompiledUnhandledInstruction);
       return false;
   }
   return true;
-}
+}  // NOLINT(readability/fn_size)
 
 HIntConstant* HGraphBuilder::GetIntConstant0() {
   if (constant0_ != nullptr) {
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index e143786..cc5f6a0 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -18,23 +18,28 @@
 #define ART_COMPILER_OPTIMIZING_BUILDER_H_
 
 #include "dex_file.h"
+#include "dex_file-inl.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
+#include "optimizing_compiler_stats.h"
 #include "primitive.h"
-#include "utils/allocation.h"
+#include "utils/arena_object.h"
 #include "utils/growable_array.h"
 #include "nodes.h"
 
 namespace art {
 
 class Instruction;
+class SwitchTable;
 
 class HGraphBuilder : public ValueObject {
  public:
   HGraphBuilder(ArenaAllocator* arena,
-                DexCompilationUnit* dex_compilation_unit = nullptr,
-                const DexFile* dex_file = nullptr,
-                CompilerDriver* driver = nullptr)
+                DexCompilationUnit* dex_compilation_unit,
+                const DexCompilationUnit* const outer_compilation_unit,
+                const DexFile* dex_file,
+                CompilerDriver* driver,
+                OptimizingCompilerStats* compiler_stats)
       : arena_(arena),
         branch_targets_(arena, 0),
         locals_(arena, 0),
@@ -46,19 +51,50 @@
         constant1_(nullptr),
         dex_file_(dex_file),
         dex_compilation_unit_(dex_compilation_unit),
-        compiler_driver_(driver) {}
+        compiler_driver_(driver),
+        outer_compilation_unit_(outer_compilation_unit),
+        return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])),
+        code_start_(nullptr),
+        latest_result_(nullptr),
+        compilation_stats_(compiler_stats) {}
 
-  HGraph* BuildGraph(const DexFile::CodeItem& code);
+  // Only for unit testing.
+  HGraphBuilder(ArenaAllocator* arena, Primitive::Type return_type = Primitive::kPrimInt)
+      : arena_(arena),
+        branch_targets_(arena, 0),
+        locals_(arena, 0),
+        entry_block_(nullptr),
+        exit_block_(nullptr),
+        current_block_(nullptr),
+        graph_(nullptr),
+        constant0_(nullptr),
+        constant1_(nullptr),
+        dex_file_(nullptr),
+        dex_compilation_unit_(nullptr),
+        compiler_driver_(nullptr),
+        outer_compilation_unit_(nullptr),
+        return_type_(return_type),
+        code_start_(nullptr),
+        latest_result_(nullptr),
+        compilation_stats_(nullptr) {}
+
+  HGraph* BuildGraph(const DexFile::CodeItem& code, int start_instruction_id = 0);
 
  private:
   // Analyzes the dex instruction and adds HInstruction to the graph
   // to execute that instruction. Returns whether the instruction can
   // be handled.
-  bool AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_offset);
+  bool AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_pc);
 
   // Finds all instructions that start a new block, and populates branch_targets_ with
   // the newly created blocks.
-  void ComputeBranchTargets(const uint16_t* start, const uint16_t* end);
+  // As a side effect, also compute the number of dex instructions, blocks, and
+  // branches.
+  void ComputeBranchTargets(const uint16_t* start,
+                            const uint16_t* end,
+                            size_t* number_of_dex_instructions,
+                            size_t* number_of_block,
+                            size_t* number_of_branches);
   void MaybeUpdateCurrentBlock(size_t index);
   HBasicBlock* FindBlockStartingAt(int32_t index) const;
 
@@ -70,44 +106,136 @@
   HLocal* GetLocalAt(int register_index) const;
   void UpdateLocal(int register_index, HInstruction* instruction) const;
   HInstruction* LoadLocal(int register_index, Primitive::Type type) const;
-  void PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset);
+  void PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_pc);
+  void InitializeParameters(uint16_t number_of_parameters);
 
-  // Temporarily returns whether the compiler supports the parameters
-  // of the method.
-  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>
+  void Binop_23x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+
+  template<typename T>
+  void Binop_23x_shift(const Instruction& instruction, Primitive::Type type);
+
+  void Binop_23x_cmp(const Instruction& instruction, Primitive::Type type, HCompare::Bias bias);
+
+  template<typename T>
   void Binop_12x(const Instruction& instruction, Primitive::Type type);
 
   template<typename T>
+  void Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
+
+  template<typename T>
+  void Binop_12x_shift(const Instruction& instruction, Primitive::Type type);
+
+  template<typename T>
   void Binop_22b(const Instruction& instruction, bool reverse);
 
   template<typename T>
   void Binop_22s(const Instruction& instruction, bool reverse);
 
-  template<typename T> void If_21t(const Instruction& instruction, uint32_t dex_offset);
-  template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_offset);
+  template<typename T> void If_21t(const Instruction& instruction, uint32_t dex_pc);
+  template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_pc);
+
+  void Conversion_12x(const Instruction& instruction,
+                      Primitive::Type input_type,
+                      Primitive::Type result_type,
+                      uint32_t dex_pc);
+
+  void BuildCheckedDivRem(uint16_t out_reg,
+                          uint16_t first_reg,
+                          int64_t second_reg_or_constant,
+                          uint32_t dex_pc,
+                          Primitive::Type type,
+                          bool second_is_lit,
+                          bool is_div);
 
   void BuildReturn(const Instruction& instruction, Primitive::Type type);
 
-  bool BuildFieldAccess(const Instruction& instruction, uint32_t dex_offset, bool is_get);
+  // Builds an instance field access node and returns whether the instruction is supported.
+  bool BuildInstanceFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
+
+  // Builds a static field access node and returns whether the instruction is supported.
+  bool BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
+
   void BuildArrayAccess(const Instruction& instruction,
-                        uint32_t dex_offset,
+                        uint32_t dex_pc,
                         bool is_get,
                         Primitive::Type anticipated_type);
 
   // Builds an invocation node and returns whether the instruction is supported.
   bool BuildInvoke(const Instruction& instruction,
-                   uint32_t dex_offset,
+                   uint32_t dex_pc,
                    uint32_t method_idx,
                    uint32_t number_of_vreg_arguments,
                    bool is_range,
                    uint32_t* args,
                    uint32_t register_index);
 
+  // Builds a new array node and the instructions that fill it.
+  void BuildFilledNewArray(uint32_t dex_pc,
+                           uint32_t type_index,
+                           uint32_t number_of_vreg_arguments,
+                           bool is_range,
+                           uint32_t* args,
+                           uint32_t register_index);
+
+  void BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc);
+
+  // 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_pc);
+
+  // 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 int64_t* data,
+                              uint32_t element_count,
+                              uint32_t dex_pc);
+
+  // Builds a `HInstanceOf`, or a `HCheckCast` instruction.
+  // Returns whether we succeeded in building the instruction.
+  bool BuildTypeCheck(const Instruction& instruction,
+                      uint8_t destination,
+                      uint8_t reference,
+                      uint16_t type_index,
+                      uint32_t dex_pc);
+
+  // Builds an instruction sequence for a packed switch statement.
+  void BuildPackedSwitch(const Instruction& instruction, uint32_t dex_pc);
+
+  // Builds an instruction sequence for a sparse switch statement.
+  void BuildSparseSwitch(const Instruction& instruction, uint32_t dex_pc);
+
+  void BuildSwitchCaseHelper(const Instruction& instruction, size_t index,
+                             bool is_last_case, const SwitchTable& table,
+                             HInstruction* value, int32_t case_value_int,
+                             int32_t target_offset, uint32_t dex_pc);
+
+  bool SkipCompilation(size_t number_of_dex_instructions,
+                       size_t number_of_blocks,
+                       size_t number_of_branches);
+
+  void MaybeRecordStat(MethodCompilationStat compilation_stat);
+
+  // Returns whether `type_index` points to the outer-most compiling method's class.
+  bool IsCompilingClass(uint16_t type_index) const {
+    uint32_t referrer_index = outer_compilation_unit_->GetDexMethodIndex();
+    const DexFile::MethodId& method_id =
+        outer_compilation_unit_->GetDexFile()->GetMethodId(referrer_index);
+    return method_id.class_idx_ == type_index;
+  }
+
   ArenaAllocator* const arena_;
 
   // A list of the size of the dex code holding block information for
@@ -125,10 +253,33 @@
   HIntConstant* constant0_;
   HIntConstant* constant1_;
 
+  // The dex file where the method being compiled is.
   const DexFile* const dex_file_;
+
+  // The compilation unit of the current method being compiled. Note that
+  // it can be an inlined method.
   DexCompilationUnit* const dex_compilation_unit_;
+
   CompilerDriver* const compiler_driver_;
 
+  // The compilation unit of the outermost method being compiled. That is the
+  // method being compiled (and not inlined), and potentially inlining other
+  // methods.
+  const DexCompilationUnit* const outer_compilation_unit_;
+
+  // The return type of the method being compiled.
+  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_;
+
+  OptimizingCompilerStats* compilation_stats_;
+
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
 
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 2a9a7b3..bc9649f 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"
@@ -25,6 +26,9 @@
 #include "gc_map_builder.h"
 #include "leb128.h"
 #include "mapping_table.h"
+#include "mirror/array-inl.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/object_reference.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/assembler.h"
 #include "verifier/dex_gc_map.h"
@@ -32,20 +36,25 @@
 
 namespace art {
 
+size_t CodeGenerator::GetCacheOffset(uint32_t index) {
+  return mirror::ObjectArray<mirror::Object>::OffsetOfElement(index).SizeValue();
+}
+
 void CodeGenerator::CompileBaseline(CodeAllocator* allocator, bool is_leaf) {
   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) {
     MarkNotLeaf();
   }
   ComputeFrameSize(GetGraph()->GetNumberOfLocalVRegs()
-                     + GetGraph()->GetNumberOfTemporaries()
+                     + GetGraph()->GetTemporariesVRegSlots()
                      + 1 /* filler */,
                    0, /* the baseline compiler does not have live registers at slow path */
+                   0, /* the baseline compiler does not have live registers at slow path */
                    GetGraph()->GetMaximumNumberOfOutVRegs()
                      + 1 /* current method */);
   GenerateFrameEntry();
@@ -54,7 +63,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);
@@ -63,11 +72,7 @@
     }
   }
   GenerateSlowPaths();
-
-  size_t code_size = GetAssembler()->CodeSize();
-  uint8_t* buffer = allocator->Allocate(code_size);
-  MemoryRegion code(buffer, code_size);
-  GetAssembler()->FinalizeInstructions(code);
+  Finalize(allocator);
 }
 
 void CodeGenerator::CompileOptimized(CodeAllocator* allocator) {
@@ -76,22 +81,26 @@
   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);
     }
   }
   GenerateSlowPaths();
+  Finalize(allocator);
+}
 
+void CodeGenerator::Finalize(CodeAllocator* allocator) {
   size_t code_size = GetAssembler()->CodeSize();
   uint8_t* buffer = allocator->Allocate(code_size);
+
   MemoryRegion code(buffer, code_size);
   GetAssembler()->FinalizeInstructions(code);
 }
@@ -102,38 +111,57 @@
   }
 }
 
-size_t CodeGenerator::AllocateFreeRegisterInternal(
-    bool* blocked_registers, size_t number_of_registers) const {
-  for (size_t regno = 0; regno < number_of_registers; regno++) {
-    if (!blocked_registers[regno]) {
-      blocked_registers[regno] = true;
-      return regno;
+size_t CodeGenerator::FindFreeEntry(bool* array, size_t length) {
+  for (size_t i = 0; i < length; ++i) {
+    if (!array[i]) {
+      array[i] = true;
+      return i;
     }
   }
+  LOG(FATAL) << "Could not find a register in baseline register allocator";
+  UNREACHABLE();
+  return -1;
+}
+
+size_t CodeGenerator::FindTwoFreeConsecutiveAlignedEntries(bool* array, size_t length) {
+  for (size_t i = 0; i < length - 1; i += 2) {
+    if (!array[i] && !array[i + 1]) {
+      array[i] = true;
+      array[i + 1] = true;
+      return i;
+    }
+  }
+  LOG(FATAL) << "Could not find a register in baseline register allocator";
+  UNREACHABLE();
   return -1;
 }
 
 void CodeGenerator::ComputeFrameSize(size_t number_of_spill_slots,
-                                     size_t maximum_number_of_live_registers,
+                                     size_t maximum_number_of_live_core_registers,
+                                     size_t maximum_number_of_live_fp_registers,
                                      size_t number_of_out_slots) {
   first_register_slot_in_slow_path_ = (number_of_out_slots + number_of_spill_slots) * kVRegSize;
 
   SetFrameSize(RoundUp(
       number_of_spill_slots * kVRegSize
       + number_of_out_slots * kVRegSize
-      + maximum_number_of_live_registers * GetWordSize()
+      + maximum_number_of_live_core_registers * GetWordSize()
+      + maximum_number_of_live_fp_registers * GetFloatingPointSpillSlotSize()
       + FrameEntrySpillSize(),
       kStackAlignment));
 }
 
 Location CodeGenerator::GetTemporaryLocation(HTemporary* temp) const {
   uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs();
+  // The type of the previous instruction tells us if we need a single or double stack slot.
+  Primitive::Type type = temp->GetType();
+  int32_t temp_size = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble) ? 2 : 1;
   // Use the temporary region (right below the dex registers).
   int32_t slot = GetFrameSize() - FrameEntrySpillSize()
                                 - kVRegSize  // filler
                                 - (number_of_locals * kVRegSize)
-                                - ((1 + temp->GetIndex()) * kVRegSize);
-  return Location::StackSlot(slot);
+                                - ((temp_size + temp->GetIndex()) * kVRegSize);
+  return temp_size == 2 ? Location::DoubleStackSlot(slot) : Location::StackSlot(slot);
 }
 
 int32_t CodeGenerator::GetStackSlot(HLocal* local) const {
@@ -156,47 +184,75 @@
   LocationSummary* locations = instruction->GetLocations();
   if (locations == nullptr) return;
 
-  for (size_t i = 0, e = GetNumberOfRegisters(); i < e; ++i) {
-    blocked_registers_[i] = false;
+  for (size_t i = 0, e = GetNumberOfCoreRegisters(); i < e; ++i) {
+    blocked_core_registers_[i] = false;
+  }
+
+  for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
+    blocked_fpu_registers_[i] = false;
+  }
+
+  for (size_t i = 0, e = number_of_register_pairs_; i < e; ++i) {
+    blocked_register_pairs_[i] = false;
   }
 
   // Mark all fixed input, temp and output registers as used.
   for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
     Location loc = locations->InAt(i);
+    // The DCHECKS below check that a register is not specified twice in
+    // the summary.
     if (loc.IsRegister()) {
-      // Check that a register is not specified twice in the summary.
-      DCHECK(!blocked_registers_[loc.GetEncoding()]);
-      blocked_registers_[loc.GetEncoding()] = true;
+      DCHECK(!blocked_core_registers_[loc.reg()]);
+      blocked_core_registers_[loc.reg()] = true;
+    } else if (loc.IsFpuRegister()) {
+      DCHECK(!blocked_fpu_registers_[loc.reg()]);
+      blocked_fpu_registers_[loc.reg()] = true;
+    } else if (loc.IsFpuRegisterPair()) {
+      DCHECK(!blocked_fpu_registers_[loc.AsFpuRegisterPairLow<int>()]);
+      blocked_fpu_registers_[loc.AsFpuRegisterPairLow<int>()] = true;
+      DCHECK(!blocked_fpu_registers_[loc.AsFpuRegisterPairHigh<int>()]);
+      blocked_fpu_registers_[loc.AsFpuRegisterPairHigh<int>()] = true;
+    } else if (loc.IsRegisterPair()) {
+      DCHECK(!blocked_core_registers_[loc.AsRegisterPairLow<int>()]);
+      blocked_core_registers_[loc.AsRegisterPairLow<int>()] = true;
+      DCHECK(!blocked_core_registers_[loc.AsRegisterPairHigh<int>()]);
+      blocked_core_registers_[loc.AsRegisterPairHigh<int>()] = true;
     }
   }
 
   for (size_t i = 0, e = locations->GetTempCount(); i < e; ++i) {
     Location loc = locations->GetTemp(i);
+    // The DCHECKS below check that a register is not specified twice in
+    // the summary.
     if (loc.IsRegister()) {
-      // Check that a register is not specified twice in the summary.
-      DCHECK(!blocked_registers_[loc.GetEncoding()]);
-      blocked_registers_[loc.GetEncoding()] = true;
+      DCHECK(!blocked_core_registers_[loc.reg()]);
+      blocked_core_registers_[loc.reg()] = true;
+    } else if (loc.IsFpuRegister()) {
+      DCHECK(!blocked_fpu_registers_[loc.reg()]);
+      blocked_fpu_registers_[loc.reg()] = true;
+    } else {
+      DCHECK(loc.GetPolicy() == Location::kRequiresRegister
+             || loc.GetPolicy() == Location::kRequiresFpuRegister);
     }
   }
 
-  SetupBlockedRegisters(blocked_registers_);
+  SetupBlockedRegisters();
 
   // Allocate all unallocated input locations.
   for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
     Location loc = locations->InAt(i);
     HInstruction* input = instruction->InputAt(i);
     if (loc.IsUnallocated()) {
-      if (loc.GetPolicy() == Location::kRequiresRegister) {
-        loc = Location::RegisterLocation(
-            AllocateFreeRegister(input->GetType(), blocked_registers_));
+      if ((loc.GetPolicy() == Location::kRequiresRegister)
+          || (loc.GetPolicy() == Location::kRequiresFpuRegister)) {
+        loc = AllocateFreeRegister(input->GetType());
       } else {
         DCHECK_EQ(loc.GetPolicy(), Location::kAny);
         HLoadLocal* load = input->AsLoadLocal();
         if (load != nullptr) {
           loc = GetStackLocation(load);
         } else {
-          loc = Location::RegisterLocation(
-              AllocateFreeRegister(input->GetType(), blocked_registers_));
+          loc = AllocateFreeRegister(input->GetType());
         }
       }
       locations->SetInAt(i, loc);
@@ -207,11 +263,21 @@
   for (size_t i = 0, e = locations->GetTempCount(); i < e; ++i) {
     Location loc = locations->GetTemp(i);
     if (loc.IsUnallocated()) {
-      DCHECK_EQ(loc.GetPolicy(), Location::kRequiresRegister);
-      // TODO: Adjust handling of temps. We currently consider temps to use
-      // core registers. They may also use floating point registers at some point.
-      loc = Location::RegisterLocation(static_cast<ManagedRegister>(
-          AllocateFreeRegister(Primitive::kPrimInt, blocked_registers_)));
+      switch (loc.GetPolicy()) {
+        case Location::kRequiresRegister:
+          // Allocate a core register (large enough to fit a 32-bit integer).
+          loc = AllocateFreeRegister(Primitive::kPrimInt);
+          break;
+
+        case Location::kRequiresFpuRegister:
+          // Allocate a core register (large enough to fit a 64-bit double).
+          loc = AllocateFreeRegister(Primitive::kPrimDouble);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected policy for temporary location "
+                     << loc.GetPolicy();
+      }
       locations->SetTempAt(i, loc);
     }
   }
@@ -220,8 +286,8 @@
     switch (result_location.GetPolicy()) {
       case Location::kAny:
       case Location::kRequiresRegister:
-        result_location = Location::RegisterLocation(
-            AllocateFreeRegister(instruction->GetType(), blocked_registers_));
+      case Location::kRequiresFpuRegister:
+        result_location = AllocateFreeRegister(instruction->GetType());
         break;
       case Location::kSameAsFirstInput:
         result_location = locations->InAt(0);
@@ -237,16 +303,22 @@
       HInstruction* previous = instruction->GetPrevious();
       Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
       Move(previous, temp_location, instruction);
-      previous->GetLocations()->SetOut(temp_location);
     }
     return;
   }
   AllocateRegistersLocally(instruction);
   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
     Location location = instruction->GetLocations()->InAt(i);
+    HInstruction* input = instruction->InputAt(i);
     if (location.IsValid()) {
       // Move the input to the desired location.
-      Move(instruction->InputAt(i), location, instruction);
+      if (input->GetNext()->IsTemporary()) {
+        // If the input was stored in a temporary, use that temporary to
+        // perform the move.
+        Move(input->GetNext(), location, instruction);
+      } else {
+        Move(input, location, instruction);
+      }
     }
   }
 }
@@ -256,25 +328,27 @@
   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) {
+CodeGenerator* CodeGenerator::Create(HGraph* graph,
+                                     InstructionSet instruction_set,
+                                     const InstructionSetFeatures& isa_features,
+                                     const CompilerOptions& compiler_options) {
   switch (instruction_set) {
     case kArm:
     case kThumb2: {
-      return new (allocator) arm::CodeGeneratorARM(graph);
+      return new arm::CodeGeneratorARM(graph,
+          *isa_features.AsArmInstructionSetFeatures(),
+          compiler_options);
+    }
+    case kArm64: {
+      return new arm64::CodeGeneratorARM64(graph, compiler_options);
     }
     case kMips:
       return nullptr;
     case kX86: {
-      return new (allocator) x86::CodeGeneratorX86(graph);
+      return new x86::CodeGeneratorX86(graph, compiler_options);
     }
     case kX86_64: {
-      return new (allocator) x86_64::CodeGeneratorX86_64(graph);
+      return new x86_64::CodeGeneratorX86_64(graph, compiler_options);
     }
     default:
       return nullptr;
@@ -301,24 +375,25 @@
     uint32_t native_offset = pc_info.native_pc;
     uint32_t dex_pc = pc_info.dex_pc;
     const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
-    CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc;
+    CHECK(references != nullptr) << "Missing ref for dex pc 0x" << std::hex << dex_pc;
     builder.AddEntry(native_offset, references);
   }
 }
 
-void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_map) const {
+void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, DefaultSrcMap* src_map) const {
   uint32_t pc2dex_data_size = 0u;
   uint32_t pc2dex_entries = pc_infos_.Size();
   uint32_t pc2dex_offset = 0u;
   int32_t pc2dex_dalvik_offset = 0;
   uint32_t dex2pc_data_size = 0u;
   uint32_t dex2pc_entries = 0u;
+  uint32_t dex2pc_offset = 0u;
+  int32_t dex2pc_dalvik_offset = 0;
 
   if (src_map != nullptr) {
     src_map->reserve(pc2dex_entries);
   }
 
-  // We currently only have pc2dex entries.
   for (size_t i = 0; i < pc2dex_entries; i++) {
     struct PcInfo pc_info = pc_infos_.Get(i);
     pc2dex_data_size += UnsignedLeb128Size(pc_info.native_pc - pc2dex_offset);
@@ -330,6 +405,19 @@
     }
   }
 
+  // Walk over the blocks and find which ones correspond to catch block entries.
+  for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+    HBasicBlock* block = graph_->GetBlocks().Get(i);
+    if (block->IsCatchBlock()) {
+      intptr_t native_pc = GetAddressOf(block);
+      ++dex2pc_entries;
+      dex2pc_data_size += UnsignedLeb128Size(native_pc - dex2pc_offset);
+      dex2pc_data_size += SignedLeb128Size(block->GetDexPc() - dex2pc_dalvik_offset);
+      dex2pc_offset = native_pc;
+      dex2pc_dalvik_offset = block->GetDexPc();
+    }
+  }
+
   uint32_t total_entries = pc2dex_entries + dex2pc_entries;
   uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
   uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
@@ -337,6 +425,7 @@
 
   uint8_t* data_ptr = &(*data)[0];
   uint8_t* write_pos = data_ptr;
+
   write_pos = EncodeUnsignedLeb128(write_pos, total_entries);
   write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries);
   DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size);
@@ -344,6 +433,9 @@
 
   pc2dex_offset = 0u;
   pc2dex_dalvik_offset = 0u;
+  dex2pc_offset = 0u;
+  dex2pc_dalvik_offset = 0u;
+
   for (size_t i = 0; i < pc2dex_entries; i++) {
     struct PcInfo pc_info = pc_infos_.Get(i);
     DCHECK(pc2dex_offset <= pc_info.native_pc);
@@ -352,6 +444,19 @@
     pc2dex_offset = pc_info.native_pc;
     pc2dex_dalvik_offset = pc_info.dex_pc;
   }
+
+  for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+    HBasicBlock* block = graph_->GetBlocks().Get(i);
+    if (block->IsCatchBlock()) {
+      intptr_t native_pc = GetAddressOf(block);
+      write_pos2 = EncodeUnsignedLeb128(write_pos2, native_pc - dex2pc_offset);
+      write_pos2 = EncodeSignedLeb128(write_pos2, block->GetDexPc() - dex2pc_dalvik_offset);
+      dex2pc_offset = native_pc;
+      dex2pc_dalvik_offset = block->GetDexPc();
+    }
+  }
+
+
   DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size + pc2dex_data_size);
   DCHECK_EQ(static_cast<size_t>(write_pos2 - data_ptr), data_size);
 
@@ -368,6 +473,14 @@
       CHECK_EQ(pc_info.dex_pc, it.DexPc());
       ++it;
     }
+    for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+      HBasicBlock* block = graph_->GetBlocks().Get(i);
+      if (block->IsCatchBlock()) {
+        CHECK_EQ(GetAddressOf(block), it2.NativePcOffset());
+        CHECK_EQ(block->GetDexPc(), it2.DexPc());
+        ++it2;
+      }
+    }
     CHECK(it == table.PcToDexEnd());
     CHECK(it2 == table.DexToPcEnd());
   }
@@ -392,6 +505,29 @@
 }
 
 void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc) {
+  if (instruction != nullptr) {
+    // The code generated for some type conversions may call the
+    // runtime, thus normally requiring a subsequent call to this
+    // method.  However, the method verifier does not produce PC
+    // information for certain instructions, which are considered "atomic"
+    // (they cannot join a GC).
+    // Therefore we do not currently record PC information for such
+    // instructions.  As this may change later, we added this special
+    // case so that code generators may nevertheless call
+    // CodeGenerator::RecordPcInfo without triggering an error in
+    // CodeGenerator::BuildNativeGCMap ("Missing ref for dex pc 0x")
+    // thereafter.
+    if (instruction->IsTypeConversion()) {
+      return;
+    }
+    if (instruction->IsRem()) {
+      Primitive::Type type = instruction->AsRem()->GetResultType();
+      if ((type == Primitive::kPrimFloat) || (type == Primitive::kPrimDouble)) {
+        return;
+      }
+    }
+  }
+
   // Collect PC infos for the mapping table.
   struct PcInfo pc_info;
   pc_info.dex_pc = dex_pc;
@@ -435,10 +571,19 @@
           stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, High32Bits(value));
           ++i;
           DCHECK_LT(i, environment_size);
-        } else {
-          DCHECK(current->IsIntConstant());
+        } else if (current->IsDoubleConstant()) {
+          int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue());
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, Low32Bits(value));
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, High32Bits(value));
+          ++i;
+          DCHECK_LT(i, environment_size);
+        } else if (current->IsIntConstant()) {
           int32_t value = current->AsIntConstant()->GetValue();
           stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, value);
+        } else {
+          DCHECK(current->IsFloatConstant());
+          int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue());
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, value);
         }
         break;
       }
@@ -458,10 +603,9 @@
       }
 
       case Location::kRegister : {
-        int id = location.reg().RegId();
+        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);
@@ -469,52 +613,109 @@
         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;
+      }
+
+      case Location::kFpuRegisterPair : {
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInFpuRegister, location.low());
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInFpuRegister, location.high());
+        ++i;
+        DCHECK_LT(i, environment_size);
+        break;
+      }
+
+      case Location::kRegisterPair : {
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInRegister, location.low());
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInRegister, location.high());
+        ++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();
+bool CodeGenerator::CanMoveNullCheckToUser(HNullCheck* null_check) {
+  HInstruction* first_next_not_move = null_check->GetNextDisregardingMoves();
+  return (first_next_not_move != nullptr) && first_next_not_move->CanDoImplicitNullCheck();
+}
+
+void CodeGenerator::MaybeRecordImplicitNullCheck(HInstruction* instr) {
+  // If we are from a static path don't record the pc as we can't throw NPE.
+  // NB: having the checks here makes the code much less verbose in the arch
+  // specific code generators.
+  if (instr->IsStaticFieldSet() || instr->IsStaticFieldGet()) {
+    return;
+  }
+
+  if (!compiler_options_.GetImplicitNullChecks()) {
+    return;
+  }
+
+  if (!instr->CanDoImplicitNullCheck()) {
+    return;
+  }
+
+  // Find the first previous instruction which is not a move.
+  HInstruction* first_prev_not_move = instr->GetPreviousDisregardingMoves();
+
+  // If the instruction is a null check it means that `instr` is the first user
+  // and needs to record the pc.
+  if (first_prev_not_move != nullptr && first_prev_not_move->IsNullCheck()) {
+    HNullCheck* null_check = first_prev_not_move->AsNullCheck();
+    // TODO: The parallel moves modify the environment. Their changes need to be reverted
+    // otherwise the stack maps at the throw point will not be correct.
+    RecordPcInfo(null_check, null_check->GetDexPc());
+  }
 }
 
 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);
       }
+      DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
+      stack_offset += SaveCoreRegister(stack_offset, i);
     }
   }
 
   for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
     if (register_set->ContainsFloatingPointRegister(i)) {
-      LOG(FATAL) << "Unimplemented";
+      DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
+      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);
+      DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
+      stack_offset += RestoreCoreRegister(stack_offset, i);
     }
   }
 
   for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
     if (register_set->ContainsFloatingPointRegister(i)) {
-      LOG(FATAL) << "Unimplemented";
+      DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
+      stack_offset += RestoreFloatingPointRegister(stack_offset, i);
     }
   }
 }
@@ -538,4 +739,11 @@
   }
 }
 
+void CodeGenerator::EmitParallelMoves(Location from1, Location to1, Location from2, Location to2) {
+  HParallelMove parallel_move(GetGraph()->GetArena());
+  parallel_move.AddMove(from1, to1, nullptr);
+  parallel_move.AddMove(from2, to2, nullptr);
+  GetMoveResolver()->EmitNativeCode(&parallel_move);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index b58f3b3..f66aed9 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -17,23 +17,39 @@
 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 
+#include "arch/instruction_set.h"
+#include "arch/instruction_set_features.h"
 #include "base/bit_field.h"
+#include "driver/compiler_options.h"
 #include "globals.h"
-#include "instruction_set.h"
 #include "locations.h"
 #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;
 
+// Binary encoding of 2^32 for type double.
+static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000);
+// Binary encoding of 2^31 for type double.
+static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
+
+// Maximum value for a primitive integer.
+static int32_t constexpr kPrimIntMax = 0x7fffffff;
+// Maximum value for a primitive long.
+static int64_t constexpr kPrimLongMax = 0x7fffffffffffffff;
+
+class Assembler;
 class CodeGenerator;
 class DexCompilationUnit;
+class ParallelMoveResolver;
+class SrcMapElem;
+template <class Alloc>
 class SrcMap;
+using DefaultSrcMap = SrcMap<std::allocator<SrcMapElem>>;
 
 class CodeAllocator {
  public:
@@ -51,36 +67,31 @@
   uintptr_t native_pc;
 };
 
-class SlowPathCode : public ArenaObject {
+class SlowPathCode : public ArenaObject<kArenaAllocSlowPaths> {
  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);
 };
 
-class CodeGenerator : public ArenaObject {
+class CodeGenerator {
  public:
   // Compiles the graph to executable instructions. Returns whether the compilation
   // succeeded.
   void CompileBaseline(CodeAllocator* allocator, bool is_leaf = false);
   void CompileOptimized(CodeAllocator* allocator);
-  static CodeGenerator* Create(ArenaAllocator* allocator,
-                               HGraph* graph,
-                               InstructionSet instruction_set);
+  static CodeGenerator* Create(HGraph* graph,
+                               InstructionSet instruction_set,
+                               const InstructionSetFeatures& isa_features,
+                               const CompilerOptions& compiler_options);
+  virtual ~CodeGenerator() {}
 
   HGraph* GetGraph() const { return graph_; }
 
-  Label* GetLabelOf(HBasicBlock* block) const;
   bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
 
   size_t GetStackSlotOfParameter(HParameterValue* parameter) const {
@@ -90,16 +101,21 @@
         + parameter->GetIndex() * kVRegSize;
   }
 
+  virtual void Initialize() = 0;
+  virtual void Finalize(CodeAllocator* allocator);
   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;
   virtual Assembler* GetAssembler() = 0;
   virtual size_t GetWordSize() const = 0;
+  virtual size_t GetFloatingPointSpillSlotSize() const = 0;
+  virtual uintptr_t GetAddressOf(HBasicBlock* block) const = 0;
   void ComputeFrameSize(size_t number_of_spill_slots,
-                        size_t maximum_number_of_live_registers,
+                        size_t maximum_number_of_live_core_registers,
+                        size_t maximum_number_of_live_fp_registers,
                         size_t number_of_out_slots);
   virtual size_t FrameEntrySpillSize() const = 0;
   int32_t GetStackSlot(HLocal* local) const;
@@ -109,17 +125,35 @@
   void SetFrameSize(uint32_t size) { frame_size_ = size; }
   uint32_t GetCoreSpillMask() const { return core_spill_mask_; }
 
-  virtual size_t GetNumberOfCoreRegisters() const = 0;
-  virtual size_t GetNumberOfFloatingPointRegisters() const = 0;
-  virtual size_t GetNumberOfRegisters() const = 0;
-  virtual void SetupBlockedRegisters(bool* blocked_registers) const = 0;
+  size_t GetNumberOfCoreRegisters() const { return number_of_core_registers_; }
+  size_t GetNumberOfFloatingPointRegisters() const { return number_of_fpu_registers_; }
+  virtual void SetupBlockedRegisters() const = 0;
+
   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;
+
+  const CompilerOptions& GetCompilerOptions() const { return compiler_options_; }
+
+  // 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) {
+    UNUSED(stack_index, reg_id);
+    UNIMPLEMENTED(FATAL);
+    UNREACHABLE();
+  }
+  virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+    UNUSED(stack_index, reg_id);
+    UNIMPLEMENTED(FATAL);
+    UNREACHABLE();
+  }
+  virtual bool NeedsTwoRegisters(Primitive::Type type) const = 0;
 
   void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc);
+  bool CanMoveNullCheckToUser(HNullCheck* null_check);
+  void MaybeRecordImplicitNullCheck(HInstruction* instruction);
 
   void AddSlowPath(SlowPathCode* slow_path) {
     slow_paths_.Add(slow_path);
@@ -127,7 +161,7 @@
 
   void GenerateSlowPaths();
 
-  void BuildMappingTable(std::vector<uint8_t>* vector, SrcMap* src_map) const;
+  void BuildMappingTable(std::vector<uint8_t>* vector, DefaultSrcMap* src_map) const;
   void BuildVMapTable(std::vector<uint8_t>* vector) const;
   void BuildNativeGCMap(
       std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
@@ -150,52 +184,85 @@
   // have not been written to.
   void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const;
 
+  bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; }
+  bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; }
+
+  // Helper that returns the pointer offset of an index in an object array.
+  // Note: this method assumes we always have the same pointer size, regardless
+  // of the architecture.
+  static size_t GetCacheOffset(uint32_t index);
+
+  void EmitParallelMoves(Location from1, Location to1, Location from2, Location to2);
+
+  static bool StoreNeedsWriteBarrier(Primitive::Type type, HInstruction* value) {
+    if (kIsDebugBuild) {
+      if (type == Primitive::kPrimNot && value->IsIntConstant()) {
+        CHECK_EQ(value->AsIntConstant()->GetValue(), 0);
+      }
+    }
+    return type == Primitive::kPrimNot && !value->IsIntConstant();
+  }
+
  protected:
-  CodeGenerator(HGraph* graph, size_t number_of_registers)
+  CodeGenerator(HGraph* graph,
+                size_t number_of_core_registers,
+                size_t number_of_fpu_registers,
+                size_t number_of_register_pairs,
+                const CompilerOptions& compiler_options)
       : frame_size_(kUninitializedFrameSize),
         core_spill_mask_(0),
         first_register_slot_in_slow_path_(0),
+        blocked_core_registers_(graph->GetArena()->AllocArray<bool>(number_of_core_registers)),
+        blocked_fpu_registers_(graph->GetArena()->AllocArray<bool>(number_of_fpu_registers)),
+        blocked_register_pairs_(graph->GetArena()->AllocArray<bool>(number_of_register_pairs)),
+        number_of_core_registers_(number_of_core_registers),
+        number_of_fpu_registers_(number_of_fpu_registers),
+        number_of_register_pairs_(number_of_register_pairs),
         graph_(graph),
-        block_labels_(graph->GetArena(), 0),
+        compiler_options_(compiler_options),
         pc_infos_(graph->GetArena(), 32),
         slow_paths_(graph->GetArena(), 8),
-        blocked_registers_(graph->GetArena()->AllocArray<bool>(number_of_registers)),
         is_leaf_(true),
         stack_map_stream_(graph->GetArena()) {}
-  ~CodeGenerator() {}
 
   // Register allocation logic.
   void AllocateRegistersLocally(HInstruction* instruction) const;
 
   // Backend specific implementation for allocating a register.
-  virtual ManagedRegister AllocateFreeRegister(Primitive::Type type,
-                                               bool* blocked_registers) const = 0;
+  virtual Location AllocateFreeRegister(Primitive::Type type) const = 0;
 
-  // Raw implementation of allocating a register: loops over blocked_registers to find
-  // the first available register.
-  size_t AllocateFreeRegisterInternal(bool* blocked_registers, size_t number_of_registers) const;
+  static size_t FindFreeEntry(bool* array, size_t length);
+  static size_t FindTwoFreeConsecutiveAlignedEntries(bool* array, size_t length);
 
   virtual Location GetStackLocation(HLoadLocal* load) const = 0;
 
+  virtual ParallelMoveResolver* GetMoveResolver() = 0;
+
   // Frame size required for this method.
   uint32_t frame_size_;
   uint32_t core_spill_mask_;
   uint32_t first_register_slot_in_slow_path_;
 
+  // Arrays used when doing register allocation to know which
+  // registers we can allocate. `SetupBlockedRegisters` updates the
+  // arrays.
+  bool* const blocked_core_registers_;
+  bool* const blocked_fpu_registers_;
+  bool* const blocked_register_pairs_;
+  size_t number_of_core_registers_;
+  size_t number_of_fpu_registers_;
+  size_t number_of_register_pairs_;
+
  private:
   void InitLocations(HInstruction* instruction);
   size_t GetStackOffsetOfSavedRegister(size_t index);
 
   HGraph* const graph_;
+  const CompilerOptions& compiler_options_;
 
-  // Labels for each block that will be compiled.
-  GrowableArray<Label> block_labels_;
   GrowableArray<PcInfo> pc_infos_;
   GrowableArray<SlowPathCode*> slow_paths_;
 
-  // Temporary data structure used when doing register allocation.
-  bool* const blocked_registers_;
-
   bool is_leaf_;
 
   StackMapStream stack_map_stream_;
@@ -203,28 +270,42 @@
   DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
 };
 
-template <typename T>
+template <typename C, typename F>
 class CallingConvention {
  public:
-  CallingConvention(const T* registers, int number_of_registers)
-      : registers_(registers), number_of_registers_(number_of_registers) {}
+  CallingConvention(const C* registers,
+                    size_t number_of_registers,
+                    const F* fpu_registers,
+                    size_t number_of_fpu_registers)
+      : registers_(registers),
+        number_of_registers_(number_of_registers),
+        fpu_registers_(fpu_registers),
+        number_of_fpu_registers_(number_of_fpu_registers) {}
 
   size_t GetNumberOfRegisters() const { return number_of_registers_; }
+  size_t GetNumberOfFpuRegisters() const { return number_of_fpu_registers_; }
 
-  T GetRegisterAt(size_t index) const {
+  C GetRegisterAt(size_t index) const {
     DCHECK_LT(index, number_of_registers_);
     return registers_[index];
   }
 
-  uint8_t GetStackOffsetOf(size_t index) const {
+  F GetFpuRegisterAt(size_t index) const {
+    DCHECK_LT(index, number_of_fpu_registers_);
+    return fpu_registers_[index];
+  }
+
+  size_t GetStackOffsetOf(size_t index) const {
     // We still reserve the space for parameters passed by registers.
     // Add one for the method pointer.
     return (index + 1) * kVRegSize;
   }
 
  private:
-  const T* registers_;
+  const C* registers_;
   const size_t number_of_registers_;
+  const F* fpu_registers_;
+  const size_t number_of_fpu_registers_;
 
   DISALLOW_COPY_AND_ASSIGN(CallingConvention);
 };
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 1876cb9..c6a6974 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -16,60 +16,80 @@
 
 #include "code_generator_arm.h"
 
+#include "arch/arm/instruction_set_features_arm.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/class.h"
 #include "thread.h"
-#include "utils/assembler.h"
 #include "utils/arm/assembler_arm.h"
 #include "utils/arm/managed_register_arm.h"
+#include "utils/assembler.h"
 #include "utils/stack_checks.h"
 
 namespace art {
 
-arm::ArmManagedRegister Location::AsArm() const {
-  return reg().AsArm();
-}
-
 namespace arm {
 
-static constexpr bool kExplicitStackOverflowCheck = false;
+static DRegister FromLowSToD(SRegister reg) {
+  DCHECK_EQ(reg % 2, 0);
+  return static_cast<DRegister>(reg / 2);
+}
+
+static bool ExpectedPairLayout(Location location) {
+  // We expected this for both core and fpu register pairs.
+  return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
+}
 
 static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2;  // LR, R6, R7
 static constexpr int kCurrentMethodStackOffset = 0;
 
-static Location ArmCoreLocation(Register reg) {
-  return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
-}
-
-static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
+static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     arraysize(kRuntimeParameterCoreRegisters);
+static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 };
+static constexpr size_t kRuntimeParameterFpuRegistersLength =
+    arraysize(kRuntimeParameterFpuRegisters);
 
-class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
+class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
  public:
   InvokeRuntimeCallingConvention()
       : CallingConvention(kRuntimeParameterCoreRegisters,
-                          kRuntimeParameterCoreRegistersLength) {}
+                          kRuntimeParameterCoreRegistersLength,
+                          kRuntimeParameterFpuRegisters,
+                          kRuntimeParameterFpuRegistersLength) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
 };
 
 #define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
+#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
 
-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) {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     __ Bind(GetEntryLabel());
-    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value();
-    __ ldr(LR, Address(TR, offset));
-    __ blx(LR);
-    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    arm_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
   }
 
  private:
@@ -77,11 +97,27 @@
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
 };
 
-class StackOverflowCheckSlowPathARM : public SlowPathCode {
+class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
+ public:
+  explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
+    __ Bind(GetEntryLabel());
+    arm_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
+  }
+
+ private:
+  HDivZeroCheck* const instruction_;
+  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
+};
+
+class StackOverflowCheckSlowPathARM : public SlowPathCodeARM {
  public:
   StackOverflowCheckSlowPathARM() {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     __ Bind(GetEntryLabel());
     __ LoadFromOffset(kLoadWord, PC, TR,
         QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value());
@@ -91,23 +127,22 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
 };
 
-class SuspendCheckSlowPathARM : public SlowPathCode {
+class SuspendCheckSlowPathARM : public SlowPathCodeARM {
  public:
-  explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
+  SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
       : instruction_(instruction), successor_(successor) {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+  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();
-    __ ldr(LR, Address(TR, offset));
-    __ blx(LR);
-    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    arm_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
     codegen->RestoreLiveRegisters(instruction_->GetLocations());
     if (successor_ == nullptr) {
       __ b(GetReturnLabel());
     } else {
-      __ b(codegen->GetLabelOf(successor_));
+      __ b(arm_codegen->GetLabelOf(successor_));
     }
   }
 
@@ -127,7 +162,7 @@
   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
 };
 
-class BoundsCheckSlowPathARM : public SlowPathCode {
+class BoundsCheckSlowPathARM : public SlowPathCodeARM {
  public:
   BoundsCheckSlowPathARM(HBoundsCheck* instruction,
                          Location index_location,
@@ -136,16 +171,19 @@
         index_location_(index_location),
         length_location_(length_location) {}
 
-  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     __ Bind(GetEntryLabel());
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
     InvokeRuntimeCallingConvention calling_convention;
-    arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
-    arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
-    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
-    __ ldr(LR, Address(TR, offset));
-    __ blx(LR);
-    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    codegen->EmitParallelMoves(
+        index_location_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+        length_location_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+    arm_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
   }
 
  private:
@@ -156,6 +194,139 @@
   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
 };
 
+class LoadClassSlowPathARM : public SlowPathCodeARM {
+ public:
+  LoadClassSlowPathARM(HLoadClass* cls,
+                       HInstruction* at,
+                       uint32_t dex_pc,
+                       bool do_clinit)
+      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
+  }
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = at_->GetLocations();
+
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+    arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+    int32_t entry_point_offset = do_clinit_
+        ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
+        : QUICK_ENTRY_POINT(pInitializeType);
+    arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
+
+    // Move the class to the desired location.
+    Location out = locations->Out();
+    if (out.IsValid()) {
+      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+      arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
+    }
+    codegen->RestoreLiveRegisters(locations);
+    __ b(GetExitLabel());
+  }
+
+ private:
+  // The class this slow path will load.
+  HLoadClass* const cls_;
+
+  // The instruction where this slow path is happening.
+  // (Might be the load class or an initialization check).
+  HInstruction* const at_;
+
+  // The dex PC of `at_`.
+  const uint32_t dex_pc_;
+
+  // Whether to initialize the class.
+  const bool do_clinit_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
+};
+
+class LoadStringSlowPathARM : public SlowPathCodeARM {
+ public:
+  explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+    __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
+    arm_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
+    arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
+
+    codegen->RestoreLiveRegisters(locations);
+    __ b(GetExitLabel());
+  }
+
+ private:
+  HLoadString* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
+};
+
+class TypeCheckSlowPathARM : public SlowPathCodeARM {
+ public:
+  TypeCheckSlowPathARM(HInstruction* instruction,
+                       Location class_to_check,
+                       Location object_class,
+                       uint32_t dex_pc)
+      : instruction_(instruction),
+        class_to_check_(class_to_check),
+        object_class_(object_class),
+        dex_pc_(dex_pc) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(instruction_->IsCheckCast()
+           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
+    InvokeRuntimeCallingConvention calling_convention;
+    codegen->EmitParallelMoves(
+        class_to_check_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+        object_class_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+
+    if (instruction_->IsInstanceOf()) {
+      arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_);
+      arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
+    } else {
+      DCHECK(instruction_->IsCheckCast());
+      arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_);
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ b(GetExitLabel());
+  }
+
+ private:
+  HInstruction* const instruction_;
+  const Location class_to_check_;
+  const Location object_class_;
+  uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
+};
+
+#undef __
+
 #undef __
 #define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
 
@@ -192,54 +363,58 @@
 }
 
 void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << ArmManagedRegister::FromDRegister(DRegister(reg));
+  stream << ArmManagedRegister::FromSRegister(SRegister(reg));
 }
 
-void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ str(static_cast<Register>(reg_id), Address(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) {
-  __ ldr(static_cast<Register>(reg_id), Address(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, kNumberOfRegIds),
+size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+  __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
+  return kArmWordSize;
+}
+
+size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+  __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
+  return kArmWordSize;
+}
+
+CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
+                                   const ArmInstructionSetFeatures& isa_features,
+                                   const CompilerOptions& compiler_options)
+    : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters,
+                    kNumberOfRegisterPairs, compiler_options),
+      block_labels_(graph->GetArena(), 0),
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this),
-      assembler_(true) {}
+      assembler_(true),
+      isa_features_(isa_features) {}
 
 size_t CodeGeneratorARM::FrameEntrySpillSize() const {
   return kNumberOfPushedRegistersAtEntry * kArmWordSize;
 }
 
-static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
-  return blocked_registers + kNumberOfAllocIds;
-}
-
-ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type,
-                                                       bool* blocked_registers) const {
+Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
   switch (type) {
     case Primitive::kPrimLong: {
-      bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
-      size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
+      size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
       ArmManagedRegister pair =
           ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
-      blocked_registers[pair.AsRegisterPairLow()] = true;
-      blocked_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;
-        }
-      }
-      return pair;
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
+
+      blocked_core_registers_[pair.AsRegisterPairLow()] = true;
+      blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
+      UpdateBlockedPairRegisters();
+      return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
     }
 
     case Primitive::kPrimByte:
@@ -248,62 +423,89 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters);
+      int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
       // Block all register pairs that contain `reg`.
-      bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
       for (int i = 0; i < kNumberOfRegisterPairs; i++) {
         ArmManagedRegister current =
             ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
         if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
-          blocked_register_pairs[i] = true;
+          blocked_register_pairs_[i] = true;
         }
       }
-      return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg));
+      return Location::RegisterLocation(reg);
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << type;
+    case Primitive::kPrimFloat: {
+      int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
+      return Location::FpuRegisterLocation(reg);
+    }
+
+    case Primitive::kPrimDouble: {
+      int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
+      DCHECK_EQ(reg % 2, 0);
+      return Location::FpuRegisterPairLocation(reg, reg + 1);
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 
-  return ManagedRegister::NoRegister();
+  return Location();
 }
 
-void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const {
-  bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
-
+void CodeGeneratorARM::SetupBlockedRegisters() const {
   // Don't allocate the dalvik style register pair passing.
-  blocked_register_pairs[R1_R2] = true;
+  blocked_register_pairs_[R1_R2] = true;
 
   // Stack register, LR and PC are always reserved.
-  blocked_registers[SP] = true;
-  blocked_registers[LR] = true;
-  blocked_registers[PC] = true;
-
-  // Reserve R4 for suspend check.
-  blocked_registers[R4] = true;
-  blocked_register_pairs[R4_R5] = true;
+  blocked_core_registers_[SP] = true;
+  blocked_core_registers_[LR] = true;
+  blocked_core_registers_[PC] = true;
 
   // Reserve thread register.
-  blocked_registers[TR] = true;
+  blocked_core_registers_[TR] = true;
 
   // Reserve temp register.
-  blocked_registers[IP] = true;
+  blocked_core_registers_[IP] = true;
 
   // TODO: We currently don't use Quick's callee saved registers.
   // We always save and restore R6 and R7 to make sure we can use three
   // register pairs for long operations.
-  blocked_registers[R5] = true;
-  blocked_registers[R8] = true;
-  blocked_registers[R10] = true;
-  blocked_registers[R11] = true;
+  blocked_core_registers_[R4] = true;
+  blocked_core_registers_[R5] = true;
+  blocked_core_registers_[R8] = true;
+  blocked_core_registers_[R10] = true;
+  blocked_core_registers_[R11] = true;
+
+  blocked_fpu_registers_[S16] = true;
+  blocked_fpu_registers_[S17] = true;
+  blocked_fpu_registers_[S18] = true;
+  blocked_fpu_registers_[S19] = true;
+  blocked_fpu_registers_[S20] = true;
+  blocked_fpu_registers_[S21] = true;
+  blocked_fpu_registers_[S22] = true;
+  blocked_fpu_registers_[S23] = true;
+  blocked_fpu_registers_[S24] = true;
+  blocked_fpu_registers_[S25] = true;
+  blocked_fpu_registers_[S26] = true;
+  blocked_fpu_registers_[S27] = true;
+  blocked_fpu_registers_[S28] = true;
+  blocked_fpu_registers_[S29] = true;
+  blocked_fpu_registers_[S30] = true;
+  blocked_fpu_registers_[S31] = true;
+
+  UpdateBlockedPairRegisters();
 }
 
-size_t CodeGeneratorARM::GetNumberOfRegisters() const {
-  return kNumberOfRegIds;
+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)
@@ -312,19 +514,20 @@
         codegen_(codegen) {}
 
 void CodeGeneratorARM::GenerateFrameEntry() {
-  bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
+  bool skip_overflow_check =
+      IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
   if (!skip_overflow_check) {
-    if (kExplicitStackOverflowCheck) {
-      SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
+    if (GetCompilerOptions().GetImplicitStackOverflowChecks()) {
+      __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
+      __ LoadFromOffset(kLoadWord, IP, IP, 0);
+      RecordPcInfo(nullptr, 0);
+    } else {
+      SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
       AddSlowPath(slow_path);
 
       __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
       __ cmp(SP, ShifterOperand(IP));
       __ b(slow_path->GetEntryLabel(), CC);
-    } else {
-      __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
-      __ ldr(IP, Address(IP, 0));
-      RecordPcInfo(nullptr, 0);
     }
   }
 
@@ -333,7 +536,7 @@
 
   // The return PC has already been pushed on the stack.
   __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
-  __ str(R0, Address(SP, 0));
+  __ StoreToOffset(kStoreWord, R0, SP, 0);
 }
 
 void CodeGeneratorARM::GenerateFrameExit() {
@@ -341,23 +544,21 @@
   __ 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 {
   switch (load->GetType()) {
     case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
       break;
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
-      return Location::StackSlot(GetStackSlot(load->GetLocal()));
-
     case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented type " << load->GetType();
+      return Location::StackSlot(GetStackSlot(load->GetLocal()));
 
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
@@ -380,30 +581,64 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
       uint32_t index = gp_index_++;
+      uint32_t stack_index = stack_index_++;
       if (index < calling_convention.GetNumberOfRegisters()) {
-        return ArmCoreLocation(calling_convention.GetRegisterAt(index));
+        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
       } else {
-        return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
+        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
       }
     }
 
     case Primitive::kPrimLong: {
       uint32_t index = gp_index_;
+      uint32_t stack_index = stack_index_;
       gp_index_ += 2;
+      stack_index_ += 2;
       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
-        return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(
-            calling_convention.GetRegisterPairAt(index)));
-      } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
-        return Location::QuickParameter(index);
+        if (calling_convention.GetRegisterAt(index) == R1) {
+          // Skip R1, and use R2_R3 instead.
+          gp_index_++;
+          index++;
+        }
+      }
+      if (index + 1 < calling_convention.GetNumberOfRegisters()) {
+        DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
+                  calling_convention.GetRegisterAt(index + 1));
+        return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
+                                              calling_convention.GetRegisterAt(index + 1));
       } else {
-        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
+        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
       }
     }
 
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
-      LOG(FATAL) << "Unimplemented parameter type " << type;
-      break;
+    case Primitive::kPrimFloat: {
+      uint32_t stack_index = stack_index_++;
+      if (float_index_ % 2 == 0) {
+        float_index_ = std::max(double_index_, float_index_);
+      }
+      if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
+        return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
+      } else {
+        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
+      }
+    }
+
+    case Primitive::kPrimDouble: {
+      double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
+      uint32_t stack_index = stack_index_;
+      stack_index_ += 2;
+      if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
+        uint32_t index = double_index_;
+        double_index_ += 2;
+        Location result = Location::FpuRegisterPairLocation(
+          calling_convention.GetFpuRegisterAt(index),
+          calling_convention.GetFpuRegisterAt(index + 1));
+        DCHECK(ExpectedPairLayout(result));
+        return result;
+      } else {
+        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
+      }
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
@@ -412,23 +647,66 @@
   return Location();
 }
 
+Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) {
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      return Location::RegisterLocation(R0);
+    }
+
+    case Primitive::kPrimFloat: {
+      return Location::FpuRegisterLocation(S0);
+    }
+
+    case Primitive::kPrimLong: {
+      return Location::RegisterPairLocation(R0, R1);
+    }
+
+    case Primitive::kPrimDouble: {
+      return Location::FpuRegisterPairLocation(S0, S1);
+    }
+
+    case Primitive::kPrimVoid:
+      return Location();
+  }
+  UNREACHABLE();
+  return Location();
+}
+
 void CodeGeneratorARM::Move32(Location destination, Location source) {
   if (source.Equals(destination)) {
     return;
   }
   if (destination.IsRegister()) {
     if (source.IsRegister()) {
-      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
+      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
+    } else if (source.IsFpuRegister()) {
+      __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
     } else {
-      __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex()));
+      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
+    }
+  } else if (destination.IsFpuRegister()) {
+    if (source.IsRegister()) {
+      __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
+    } else if (source.IsFpuRegister()) {
+      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
+    } else {
+      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
     }
   } else {
-    DCHECK(destination.IsStackSlot());
+    DCHECK(destination.IsStackSlot()) << destination;
     if (source.IsRegister()) {
-      __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex()));
+      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
+    } else if (source.IsFpuRegister()) {
+      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
     } else {
-      __ ldr(IP, Address(SP, source.GetStackIndex()));
-      __ str(IP, Address(SP, destination.GetStackIndex()));
+      DCHECK(source.IsStackSlot()) << source;
+      __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
+      __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
     }
   }
 }
@@ -437,64 +715,52 @@
   if (source.Equals(destination)) {
     return;
   }
-  if (destination.IsRegister()) {
-    if (source.IsRegister()) {
-      __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow());
-      __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh());
-    } else if (source.IsQuickParameter()) {
-      uint32_t argument_index = source.GetQuickParameterIndex();
-      InvokeDexCallingConvention calling_convention;
-      __ Mov(destination.AsArm().AsRegisterPairLow(),
-             calling_convention.GetRegisterAt(argument_index));
-      __ ldr(destination.AsArm().AsRegisterPairHigh(),
-             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
+  if (destination.IsRegisterPair()) {
+    if (source.IsRegisterPair()) {
+      EmitParallelMoves(
+          Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
+          Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
+          Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
+          Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
+    } else if (source.IsFpuRegister()) {
+      UNIMPLEMENTED(FATAL);
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      if (destination.AsArm().AsRegisterPair() == R1_R2) {
-        __ ldr(R1, Address(SP, source.GetStackIndex()));
-        __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize)));
-      } else {
-        __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(),
-                          SP, source.GetStackIndex());
-      }
+      DCHECK(ExpectedPairLayout(destination));
+      __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
+                        SP, source.GetStackIndex());
     }
-  } else if (destination.IsQuickParameter()) {
-    InvokeDexCallingConvention calling_convention;
-    uint32_t argument_index = destination.GetQuickParameterIndex();
-    if (source.IsRegister()) {
-      __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow());
-      __ str(source.AsArm().AsRegisterPairHigh(),
-             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
+  } else if (destination.IsFpuRegisterPair()) {
+    if (source.IsDoubleStackSlot()) {
+      __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
+                         SP,
+                         source.GetStackIndex());
     } else {
-      DCHECK(source.IsDoubleStackSlot());
-      __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex()));
-      __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize)));
-      __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1)));
+      UNIMPLEMENTED(FATAL);
     }
   } else {
     DCHECK(destination.IsDoubleStackSlot());
-    if (source.IsRegister()) {
-      if (source.AsArm().AsRegisterPair() == R1_R2) {
-        __ str(R1, Address(SP, destination.GetStackIndex()));
-        __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
+    if (source.IsRegisterPair()) {
+      // No conflict possible, so just do the moves.
+      if (source.AsRegisterPairLow<Register>() == R1) {
+        DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
+        __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
+        __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
       } else {
-        __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(),
+        __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
                          SP, destination.GetStackIndex());
       }
-    } else if (source.IsQuickParameter()) {
-      InvokeDexCallingConvention calling_convention;
-      uint32_t argument_index = source.GetQuickParameterIndex();
-      __ str(calling_convention.GetRegisterAt(argument_index),
-             Address(SP, destination.GetStackIndex()));
-      __ ldr(R0,
-             Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
-      __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
+    } else if (source.IsFpuRegisterPair()) {
+      __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
+                        SP,
+                        destination.GetStackIndex());
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ ldr(IP, Address(SP, source.GetStackIndex()));
-      __ str(IP, Address(SP, destination.GetStackIndex()));
-      __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize)));
-      __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize)));
+      EmitParallelMoves(
+          Location::StackSlot(source.GetStackIndex()),
+          Location::StackSlot(destination.GetStackIndex()),
+          Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
+          Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)));
     }
   }
 }
@@ -505,28 +771,32 @@
     return;
   }
 
-  if (instruction->AsIntConstant() != nullptr) {
-    int32_t value = instruction->AsIntConstant()->GetValue();
-    if (location.IsRegister()) {
-      __ LoadImmediate(location.AsArm().AsCoreRegister(), value);
+  if (locations != nullptr && locations->Out().IsConstant()) {
+    HConstant* const_to_move = locations->Out().GetConstant();
+    if (const_to_move->IsIntConstant()) {
+      int32_t value = const_to_move->AsIntConstant()->GetValue();
+      if (location.IsRegister()) {
+        __ LoadImmediate(location.AsRegister<Register>(), value);
+      } else {
+        DCHECK(location.IsStackSlot());
+        __ LoadImmediate(IP, value);
+        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
+      }
     } else {
-      DCHECK(location.IsStackSlot());
-      __ LoadImmediate(IP, value);
-      __ str(IP, Address(SP, location.GetStackIndex()));
+      DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
+      int64_t value = const_to_move->AsLongConstant()->GetValue();
+      if (location.IsRegisterPair()) {
+        __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
+        __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
+      } else {
+        DCHECK(location.IsDoubleStackSlot());
+        __ LoadImmediate(IP, Low32Bits(value));
+        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
+        __ LoadImmediate(IP, High32Bits(value));
+        __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
+      }
     }
-  } else if (instruction->AsLongConstant() != nullptr) {
-    int64_t value = instruction->AsLongConstant()->GetValue();
-    if (location.IsRegister()) {
-      __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value));
-      __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value));
-    } else {
-      DCHECK(location.IsDoubleStackSlot());
-      __ LoadImmediate(IP, Low32Bits(value));
-      __ str(IP, Address(SP, location.GetStackIndex()));
-      __ LoadImmediate(IP, High32Bits(value));
-      __ str(IP, Address(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:
@@ -535,15 +805,25 @@
       case Primitive::kPrimShort:
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
+      case Primitive::kPrimFloat:
         Move32(location, Location::StackSlot(stack_slot));
         break;
 
       case Primitive::kPrimLong:
+      case Primitive::kPrimDouble:
         Move64(location, Location::DoubleStackSlot(stack_slot));
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+        LOG(FATAL) << "Unexpected type " << instruction->GetType();
+    }
+  } else if (instruction->IsTemporary()) {
+    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
+    if (temp_location.IsStackSlot()) {
+      Move32(location, temp_location);
+    } else {
+      DCHECK(temp_location.IsDoubleStackSlot());
+      Move64(location, temp_location);
     }
   } else {
     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
@@ -554,19 +834,35 @@
       case Primitive::kPrimShort:
       case Primitive::kPrimNot:
       case Primitive::kPrimInt:
+      case Primitive::kPrimFloat:
         Move32(location, locations->Out());
         break;
 
       case Primitive::kPrimLong:
+      case Primitive::kPrimDouble:
         Move64(location, locations->Out());
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+        LOG(FATAL) << "Unexpected type " << instruction->GetType();
     }
   }
 }
 
+void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
+                                     HInstruction* instruction,
+                                     uint32_t dex_pc) {
+  __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
+  __ blx(LR);
+  RecordPcInfo(instruction, dex_pc);
+  DCHECK(instruction->IsSuspendCheck()
+      || instruction->IsBoundsCheck()
+      || instruction->IsNullCheck()
+      || instruction->IsDivZeroCheck()
+      || instruction->GetLocations()->CanCall()
+      || !IsLeafMethod());
+}
+
 void LocationsBuilderARM::VisitGoto(HGoto* got) {
   got->SetLocations(nullptr);
 }
@@ -598,6 +894,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
+  UNUSED(exit);
   if (kIsDebugBuild) {
     __ Comment("Unreachable");
     __ bkpt(0);
@@ -608,47 +905,59 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
   HInstruction* cond = if_instr->InputAt(0);
-  DCHECK(cond->IsCondition());
-  HCondition* condition = cond->AsCondition();
-  if (condition->NeedsMaterialization()) {
+  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
 }
 
 void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
   HInstruction* cond = if_instr->InputAt(0);
-  DCHECK(cond->IsCondition());
-  HCondition* condition = cond->AsCondition();
-  if (condition->NeedsMaterialization()) {
-    // Condition has been materialized, compare the output to 0
-    DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
-    __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(),
-           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 = condition->GetLocations();
-    if (locations->InAt(1).IsRegister()) {
-      __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
-             ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
-    } 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).AsArm().AsCoreRegister(), ShifterOperand(value));
-      } else {
-        Register temp = IP;
-        __ LoadImmediate(temp, value);
-        __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), 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(condition->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).AsRegister<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();
+      DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
+      Register left = locations->InAt(0).AsRegister<Register>();
+      if (locations->InAt(1).IsRegister()) {
+        __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
+      } else {
+        DCHECK(locations->InAt(1).IsConstant());
+        int32_t value =
+            locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+        ShifterOperand operand;
+        if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
+          __ cmp(left, operand);
+        } else {
+          Register temp = IP;
+          __ LoadImmediate(temp, value);
+          __ cmp(left, 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()));
   }
 }
@@ -660,33 +969,33 @@
   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);
   }
 }
 
 void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
   if (!comp->NeedsMaterialization()) return;
-
   LocationSummary* locations = comp->GetLocations();
+  Register left = locations->InAt(0).AsRegister<Register>();
+
   if (locations->InAt(1).IsRegister()) {
-    __ cmp(locations->InAt(0).AsArm().AsCoreRegister(),
-           ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
+    __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<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).AsArm().AsCoreRegister(), ShifterOperand(value));
+    if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
+      __ cmp(left, operand);
     } else {
       Register temp = IP;
       __ LoadImmediate(temp, value);
-      __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp));
+      __ cmp(left, ShifterOperand(temp));
     }
   }
   __ it(ARMCondition(comp->GetCondition()), kItElse);
-  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1),
+  __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
          ARMCondition(comp->GetCondition()));
-  __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0),
+  __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
          ARMOppositeCondition(comp->GetCondition()));
 }
 
@@ -752,6 +1061,7 @@
 
 void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
   // Nothing to do, this is driven by the code generator.
+  UNUSED(load);
 }
 
 void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
@@ -764,19 +1074,22 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
+    case Primitive::kPrimFloat:
       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
       break;
 
     case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
       break;
 
     default:
-      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
+      LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
   }
 }
 
 void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
+  UNUSED(store);
 }
 
 void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
@@ -786,6 +1099,8 @@
 }
 
 void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
+  UNUSED(constant);
 }
 
 void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
@@ -796,6 +1111,29 @@
 
 void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
   // Will be generated at use site.
+  UNUSED(constant);
+}
+
+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.
+  UNUSED(constant);
+}
+
+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.
+  UNUSED(constant);
 }
 
 void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
@@ -803,68 +1141,31 @@
 }
 
 void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
+  UNUSED(ret);
   codegen_->GenerateFrameExit();
 }
 
 void LocationsBuilderARM::VisitReturn(HReturn* ret) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
-  switch (ret->InputAt(0)->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-      locations->SetInAt(0, ArmCoreLocation(R0));
-      break;
-
-    case Primitive::kPrimLong:
-      locations->SetInAt(
-          0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
-      break;
-
-    default:
-      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
-  }
+  locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
 }
 
 void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
-  if (kIsDebugBuild) {
-    switch (ret->InputAt(0)->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0);
-        break;
-
-      case Primitive::kPrimLong:
-        DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1);
-        break;
-
-      default:
-        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
-    }
-  }
+  UNUSED(ret);
   codegen_->GenerateFrameExit();
 }
 
-void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
+void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
   HandleInvoke(invoke);
 }
 
-void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
-  __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
+void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
+  __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
 }
 
-void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
-  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
-  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
-      invoke->GetIndexInDexCache() * kArmWordSize;
+void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
+  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
 
   // TODO: Implement all kinds of calls:
   // 1) boot -> boot
@@ -874,14 +1175,17 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   // temp = method;
-  LoadCurrentMethod(temp);
+  codegen_->LoadCurrentMethod(temp);
   // temp = temp->dex_cache_resolved_methods_;
-  __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
+  __ LoadFromOffset(
+      kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
   // temp = temp[index_in_cache]
-  __ ldr(temp, Address(temp, index_in_cache));
+  __ LoadFromOffset(
+      kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
   // LR = temp[offset_of_quick_compiled_code]
-  __ ldr(LR, Address(temp,
-                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
+  __ LoadFromOffset(kLoadWord, LR, temp,
+                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+                         kArmWordSize).Int32Value());
   // LR()
   __ blx(LR);
 
@@ -889,14 +1193,10 @@
   DCHECK(!codegen_->IsLeafMethod());
 }
 
-void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  HandleInvoke(invoke);
-}
-
 void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(ArmCoreLocation(R0));
+  locations->AddTemp(Location::RegisterLocation(R0));
 
   InvokeDexCallingConventionVisitor calling_convention_visitor;
   for (size_t i = 0; i < invoke->InputCount(); i++) {
@@ -904,33 +1204,15 @@
     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
   }
 
-  switch (invoke->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-      locations->SetOut(ArmCoreLocation(R0));
-      break;
-
-    case Primitive::kPrimLong:
-      locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1)));
-      break;
-
-    case Primitive::kPrimVoid:
-      break;
-
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
-      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
-      break;
-  }
+  locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
 }
 
+void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
 
 void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
+  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
   uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
           invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
   LocationSummary* locations = invoke->GetLocations();
@@ -938,79 +1220,668 @@
   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   // temp = object->GetClass();
   if (receiver.IsStackSlot()) {
-    __ ldr(temp, Address(SP, receiver.GetStackIndex()));
-    __ ldr(temp, Address(temp, class_offset));
+    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
+    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
   } else {
-    __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
+    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
   // temp = temp->GetMethodAt(method_offset);
-  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
-  __ ldr(temp, Address(temp, method_offset));
+  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kArmWordSize).Int32Value();
+  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
   // LR = temp->GetEntryPoint();
-  __ ldr(LR, Address(temp, entry_point));
+  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
   // LR();
   __ blx(LR);
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
+  HandleInvoke(invoke);
+  // Add the hidden argument.
+  invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
+}
+
+void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
+  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
+  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
+  uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+          (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+
+  // Set the hidden argument.
+  __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
+                   invoke->GetDexMethodIndex());
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
+    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
+  } else {
+    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
+  }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
+  // temp = temp->GetImtEntryAt(method_offset);
+  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kArmWordSize).Int32Value();
+  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
+  // LR = temp->GetEntryPoint();
+  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
+  // LR();
+  __ blx(LR);
+  DCHECK(!codegen_->IsLeafMethod());
+  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:
+    case Primitive::kPrimLong: {
+      Location::OutputOverlap output_overlaps = (neg->GetResultType() == Primitive::kPrimLong)
+          ? Location::kOutputOverlap
+          : Location::kNoOutputOverlap;
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), output_overlaps);
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+      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.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
+      break;
+
+    case Primitive::kPrimLong:
+      DCHECK(in.IsRegisterPair());
+      // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
+      __ rsbs(out.AsRegisterPairLow<Register>(),
+              in.AsRegisterPairLow<Register>(),
+              ShifterOperand(0));
+      // We cannot emit an RSC (Reverse Subtract with Carry)
+      // instruction here, as it does not exist in the Thumb-2
+      // instruction set.  We use the following approach
+      // using SBC and SUB instead.
+      //
+      // out.hi = -C
+      __ sbc(out.AsRegisterPairHigh<Register>(),
+             out.AsRegisterPairHigh<Register>(),
+             ShifterOperand(out.AsRegisterPairHigh<Register>()));
+      // out.hi = out.hi - in.hi
+      __ sub(out.AsRegisterPairHigh<Register>(),
+             out.AsRegisterPairHigh<Register>(),
+             ShifterOperand(in.AsRegisterPairHigh<Register>()));
+      break;
+
+    case Primitive::kPrimFloat:
+      DCHECK(in.IsFpuRegister());
+      __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
+      break;
+
+    case Primitive::kPrimDouble:
+      DCHECK(in.IsFpuRegisterPair());
+      __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  DCHECK_NE(result_type, input_type);
+
+  // The float-to-long and double-to-long type conversions rely on a
+  // call to the runtime.
+  LocationSummary::CallKind call_kind =
+      ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
+       && result_type == Primitive::kPrimLong)
+      ? LocationSummary::kCall
+      : LocationSummary::kNoCall;
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
+
+  switch (result_type) {
+    case Primitive::kPrimByte:
+      switch (input_type) {
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-byte' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimShort:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-short' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-int' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-int' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-int' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-long' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat: {
+          // Processing a Dex `float-to-long' instruction.
+          InvokeRuntimeCallingConvention calling_convention;
+          locations->SetInAt(0, Location::FpuRegisterLocation(
+              calling_convention.GetFpuRegisterAt(0)));
+          locations->SetOut(Location::RegisterPairLocation(R0, R1));
+          break;
+        }
+
+        case Primitive::kPrimDouble: {
+          // Processing a Dex `double-to-long' instruction.
+          InvokeRuntimeCallingConvention calling_convention;
+          locations->SetInAt(0, Location::FpuRegisterPairLocation(
+              calling_convention.GetFpuRegisterAt(0),
+              calling_convention.GetFpuRegisterAt(1)));
+          locations->SetOut(Location::RegisterPairLocation(R0, R1));
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimChar:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // Processing a Dex `int-to-char' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    case Primitive::kPrimDouble:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations = conversion->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  DCHECK_NE(result_type, input_type);
+  switch (result_type) {
+    case Primitive::kPrimByte:
+      switch (input_type) {
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-byte' instruction.
+          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimShort:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-short' instruction.
+          __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-int' instruction.
+          DCHECK(out.IsRegister());
+          if (in.IsRegisterPair()) {
+            __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
+          } else {
+            DCHECK(in.IsConstant());
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
+          }
+          break;
+
+        case Primitive::kPrimFloat: {
+          // Processing a Dex `float-to-int' instruction.
+          SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
+          __ vmovs(temp, in.AsFpuRegister<SRegister>());
+          __ vcvtis(temp, temp);
+          __ vmovrs(out.AsRegister<Register>(), temp);
+          break;
+        }
+
+        case Primitive::kPrimDouble: {
+          // Processing a Dex `double-to-int' instruction.
+          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
+          DRegister temp_d = FromLowSToD(temp_s);
+          __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
+          __ vcvtid(temp_s, temp_d);
+          __ vmovrs(out.AsRegister<Register>(), temp_s);
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-long' instruction.
+          DCHECK(out.IsRegisterPair());
+          DCHECK(in.IsRegister());
+          __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
+          // Sign extension.
+          __ Asr(out.AsRegisterPairHigh<Register>(),
+                 out.AsRegisterPairLow<Register>(),
+                 31);
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-long' instruction.
+          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
+                                  conversion,
+                                  conversion->GetDexPc());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-long' instruction.
+          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
+                                  conversion,
+                                  conversion->GetDexPc());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimChar:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // Processing a Dex `int-to-char' instruction.
+          __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar: {
+          // Processing a Dex `int-to-float' instruction.
+          __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
+          __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
+          break;
+        }
+
+        case Primitive::kPrimLong: {
+          // Processing a Dex `long-to-float' instruction.
+          Register low = in.AsRegisterPairLow<Register>();
+          Register high = in.AsRegisterPairHigh<Register>();
+          SRegister output = out.AsFpuRegister<SRegister>();
+          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
+          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
+          SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
+          DRegister temp1_d = FromLowSToD(temp1_s);
+          SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
+          DRegister temp2_d = FromLowSToD(temp2_s);
+
+          // Operations use doubles for precision reasons (each 32-bit
+          // half of a long fits in the 53-bit mantissa of a double,
+          // but not in the 24-bit mantissa of a float).  This is
+          // especially important for the low bits.  The result is
+          // eventually converted to float.
+
+          // temp1_d = int-to-double(high)
+          __ vmovsr(temp1_s, high);
+          __ vcvtdi(temp1_d, temp1_s);
+          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
+          // as an immediate value into `temp2_d` does not work, as
+          // this instruction only transfers 8 significant bits of its
+          // immediate operand.  Instead, use two 32-bit core
+          // registers to load `k2Pow32EncodingForDouble` into
+          // `temp2_d`.
+          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
+          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
+          __ vmovdrr(temp2_d, constant_low, constant_high);
+          // temp1_d = temp1_d * 2^32
+          __ vmuld(temp1_d, temp1_d, temp2_d);
+          // temp2_d = unsigned-to-double(low)
+          __ vmovsr(temp2_s, low);
+          __ vcvtdu(temp2_d, temp2_s);
+          // temp1_d = temp1_d + temp2_d
+          __ vaddd(temp1_d, temp1_d, temp2_d);
+          // output = double-to-float(temp1_d);
+          __ vcvtsd(output, temp1_d);
+          break;
+        }
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-float' instruction.
+          __ vcvtsd(out.AsFpuRegister<SRegister>(),
+                    FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    case Primitive::kPrimDouble:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar: {
+          // Processing a Dex `int-to-double' instruction.
+          __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
+          __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+                    out.AsFpuRegisterPairLow<SRegister>());
+          break;
+        }
+
+        case Primitive::kPrimLong: {
+          // Processing a Dex `long-to-double' instruction.
+          Register low = in.AsRegisterPairLow<Register>();
+          Register high = in.AsRegisterPairHigh<Register>();
+          SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
+          DRegister out_d = FromLowSToD(out_s);
+          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
+          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
+          SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
+          DRegister temp_d = FromLowSToD(temp_s);
+
+          // out_d = int-to-double(high)
+          __ vmovsr(out_s, high);
+          __ vcvtdi(out_d, out_s);
+          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
+          // as an immediate value into `temp_d` does not work, as
+          // this instruction only transfers 8 significant bits of its
+          // immediate operand.  Instead, use two 32-bit core
+          // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
+          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
+          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
+          __ vmovdrr(temp_d, constant_low, constant_high);
+          // out_d = out_d * 2^32
+          __ vmuld(out_d, out_d, temp_d);
+          // temp_d = unsigned-to-double(low)
+          __ vmovsr(temp_s, low);
+          __ vcvtdu(temp_d, temp_s);
+          // out_d = out_d + temp_d
+          __ vaddd(out_d, out_d, temp_d);
+          break;
+        }
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-double' instruction.
+          __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+                    in.AsFpuRegister<SRegister>());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
 void LocationsBuilderARM::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   switch (add->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case Primitive::kPrimInt: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
-      locations->SetOut(Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
       break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   }
 }
 
 void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
   LocationSummary* locations = add->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
   switch (add->GetResultType()) {
     case Primitive::kPrimInt:
-      if (locations->InAt(1).IsRegister()) {
-        __ add(locations->Out().AsArm().AsCoreRegister(),
-               locations->InAt(0).AsArm().AsCoreRegister(),
-               ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
+      if (second.IsRegister()) {
+        __ add(out.AsRegister<Register>(),
+               first.AsRegister<Register>(),
+               ShifterOperand(second.AsRegister<Register>()));
       } else {
-        __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
-                       locations->InAt(0).AsArm().AsCoreRegister(),
-                       locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
+        __ AddConstant(out.AsRegister<Register>(),
+                       first.AsRegister<Register>(),
+                       second.GetConstant()->AsIntConstant()->GetValue());
       }
       break;
 
-    case Primitive::kPrimLong:
-      __ adds(locations->Out().AsArm().AsRegisterPairLow(),
-              locations->InAt(0).AsArm().AsRegisterPairLow(),
-              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
-      __ adc(locations->Out().AsArm().AsRegisterPairHigh(),
-             locations->InAt(0).AsArm().AsRegisterPairHigh(),
-             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
+    case Primitive::kPrimLong: {
+      DCHECK(second.IsRegisterPair());
+      __ adds(out.AsRegisterPairLow<Register>(),
+              first.AsRegisterPairLow<Register>(),
+              ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ adc(out.AsRegisterPairHigh<Register>(),
+             first.AsRegisterPairHigh<Register>(),
+             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+      __ vadds(out.AsFpuRegister<SRegister>(),
+               first.AsFpuRegister<SRegister>(),
+               second.AsFpuRegister<SRegister>());
       break;
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+    case Primitive::kPrimDouble:
+      __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
       break;
 
     default:
-      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   }
 }
 
@@ -1018,83 +1889,538 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
   switch (sub->GetResultType()) {
-    case Primitive::kPrimInt:
-    case Primitive::kPrimLong: {
+    case Primitive::kPrimInt: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
-      locations->SetOut(Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
       break;
-
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+      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().AsArm().AsCoreRegister(),
-               locations->InAt(0).AsArm().AsCoreRegister(),
-               ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister()));
+      if (second.IsRegister()) {
+        __ sub(out.AsRegister<Register>(),
+               first.AsRegister<Register>(),
+               ShifterOperand(second.AsRegister<Register>()));
       } else {
-        __ AddConstant(locations->Out().AsArm().AsCoreRegister(),
-                       locations->InAt(0).AsArm().AsCoreRegister(),
-                       -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
+        __ AddConstant(out.AsRegister<Register>(),
+                       first.AsRegister<Register>(),
+                       -second.GetConstant()->AsIntConstant()->GetValue());
       }
       break;
     }
 
-    case Primitive::kPrimLong:
-      __ subs(locations->Out().AsArm().AsRegisterPairLow(),
-              locations->InAt(0).AsArm().AsRegisterPairLow(),
-              ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow()));
-      __ sbc(locations->Out().AsArm().AsRegisterPairHigh(),
-             locations->InAt(0).AsArm().AsRegisterPairHigh(),
-             ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh()));
+    case Primitive::kPrimLong: {
+      DCHECK(second.IsRegisterPair());
+      __ 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(out.AsFpuRegister<SRegister>(),
+               first.AsFpuRegister<SRegister>(),
+               second.AsFpuRegister<SRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
+      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(), Location::kNoOutputOverlap);
+      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.AsRegister<Register>(),
+             first.AsRegister<Register>(),
+             second.AsRegister<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(out.AsFpuRegister<SRegister>(),
+               first.AsFpuRegister<SRegister>(),
+               second.AsFpuRegister<SRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void LocationsBuilderARM::VisitDiv(HDiv* div) {
+  LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong
+      ? LocationSummary::kCall
+      : LocationSummary::kNoCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
+
+  switch (div->GetResultType()) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+      break;
+    }
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+      locations->SetInAt(1, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
+      locations->SetOut(Location::RegisterPairLocation(R0, R1));
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
+  LocationSummary* locations = div->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+
+  switch (div->GetResultType()) {
+    case Primitive::kPrimInt: {
+      __ sdiv(out.AsRegister<Register>(),
+              first.AsRegister<Register>(),
+              second.AsRegister<Register>());
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
+      DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
+      DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
+
+      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc());
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ vdivs(out.AsFpuRegister<SRegister>(),
+               first.AsFpuRegister<SRegister>(),
+               second.AsFpuRegister<SRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
+  }
+}
+
+void LocationsBuilderARM::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+  LocationSummary::CallKind call_kind = type == Primitive::kPrimInt
+      ? LocationSummary::kNoCall
+      : LocationSummary::kCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
+
+  switch (type) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+      locations->AddTemp(Location::RequiresRegister());
+      break;
+    }
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+      locations->SetInAt(1, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
+      // The runtime helper puts the output in R2,R3.
+      locations->SetOut(Location::RegisterPairLocation(R2, R3));
+      break;
+    }
+    case Primitive::kPrimFloat: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+      locations->SetOut(Location::FpuRegisterLocation(S0));
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::FpuRegisterPairLocation(
+          calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
+      locations->SetInAt(1, Location::FpuRegisterPairLocation(
+          calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
+      locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
+  LocationSummary* locations = rem->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+
+  Primitive::Type type = rem->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt: {
+      Register reg1 = first.AsRegister<Register>();
+      Register reg2 = second.AsRegister<Register>();
+      Register temp = locations->GetTemp(0).AsRegister<Register>();
+
+      // temp = reg1 / reg2  (integer division)
+      // temp = temp * reg2
+      // dest = reg1 - temp
+      __ sdiv(temp, reg1, reg2);
+      __ mul(temp, temp, reg2);
+      __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc());
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
+  codegen_->AddSlowPath(slow_path);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location value = locations->InAt(0);
+
+  switch (instruction->GetType()) {
+    case Primitive::kPrimInt: {
+      if (value.IsRegister()) {
+        __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
+        __ b(slow_path->GetEntryLabel(), EQ);
+      } else {
+        DCHECK(value.IsConstant()) << value;
+        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+          __ b(slow_path->GetEntryLabel());
+        }
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      if (value.IsRegisterPair()) {
+        __ orrs(IP,
+                value.AsRegisterPairLow<Register>(),
+                ShifterOperand(value.AsRegisterPairHigh<Register>()));
+        __ b(slow_path->GetEntryLabel(), EQ);
+      } else {
+        DCHECK(value.IsConstant()) << value;
+        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
+          __ b(slow_path->GetEntryLabel());
+        }
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
+    }
+  }
+}
+
+void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
+  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
+
+  LocationSummary::CallKind call_kind = op->GetResultType() == Primitive::kPrimLong
+      ? LocationSummary::kCall
+      : LocationSummary::kNoCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(op, call_kind);
+
+  switch (op->GetResultType()) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
+      locations->SetOut(Location::RequiresRegister());
+      break;
+    }
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+      locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+      // The runtime helper puts the output in R0,R1.
+      locations->SetOut(Location::RegisterPairLocation(R0, R1));
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
+  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
+
+  LocationSummary* locations = op->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+
+  Primitive::Type type = op->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt: {
+      Register out_reg = out.AsRegister<Register>();
+      Register first_reg = first.AsRegister<Register>();
+      // Arm doesn't mask the shift count so we need to do it ourselves.
+      if (second.IsRegister()) {
+        Register second_reg = second.AsRegister<Register>();
+        __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
+        if (op->IsShl()) {
+          __ Lsl(out_reg, first_reg, second_reg);
+        } else if (op->IsShr()) {
+          __ Asr(out_reg, first_reg, second_reg);
+        } else {
+          __ Lsr(out_reg, first_reg, second_reg);
+        }
+      } else {
+        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
+        uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
+        if (shift_value == 0) {  // arm does not support shifting with 0 immediate.
+          __ Mov(out_reg, first_reg);
+        } else if (op->IsShl()) {
+          __ Lsl(out_reg, first_reg, shift_value);
+        } else if (op->IsShr()) {
+          __ Asr(out_reg, first_reg, shift_value);
+        } else {
+          __ Lsr(out_reg, first_reg, shift_value);
+        }
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      // TODO: Inline the assembly instead of calling the runtime.
+      InvokeRuntimeCallingConvention calling_convention;
+      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegister<Register>());
+      DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
+      DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
+
+      int32_t entry_point_offset;
+      if (op->IsShl()) {
+        entry_point_offset = QUICK_ENTRY_POINT(pShlLong);
+      } else if (op->IsShr()) {
+        entry_point_offset = QUICK_ENTRY_POINT(pShrLong);
+      } else {
+        entry_point_offset = QUICK_ENTRY_POINT(pUshrLong);
+      }
+      __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
+      __ blx(LR);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected operation type " << type;
+  }
+}
+
+void LocationsBuilderARM::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void LocationsBuilderARM::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
+void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
 void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
-  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1)));
-  locations->SetOut(ArmCoreLocation(R0));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(Location::RegisterLocation(R0));
 }
 
 void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
   __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
+}
 
-  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value();
-  __ ldr(LR, Address(TR, offset));
-  __ blx(LR);
+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(2)));
+  locations->SetOut(Location::RegisterLocation(R0));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+}
 
-  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-  DCHECK(!codegen_->IsLeafMethod());
+void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
+  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
 }
 
 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
@@ -1111,65 +2437,108 @@
 
 void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
   // Nothing to do, the parameter is already at its location.
+  UNUSED(instruction);
 }
 
-void LocationsBuilderARM::VisitNot(HNot* instruction) {
+void LocationsBuilderARM::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::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
-void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  __ eor(locations->Out().AsArm().AsCoreRegister(),
-         locations->InAt(0).AsArm().AsCoreRegister(), 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::kPrimInt:
+      __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
+      break;
+
+    case Primitive::kPrimLong:
+      __ mvn(out.AsRegisterPairLow<Register>(),
+             ShifterOperand(in.AsRegisterPairLow<Register>()));
+      __ mvn(out.AsRegisterPairHigh<Register>(),
+             ShifterOperand(in.AsRegisterPairHigh<Register>()));
+      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());
-  locations->SetInAt(1, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
-}
-
-void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
-  Label greater, done;
-  LocationSummary* locations = compare->GetLocations();
   switch (compare->InputAt(0)->GetType()) {
     case Primitive::kPrimLong: {
-      Register output = locations->Out().AsArm().AsCoreRegister();
-      ArmManagedRegister left = locations->InAt(0).AsArm();
-      ArmManagedRegister right = locations->InAt(1).AsArm();
-      Label less, greater, done;
-      __ cmp(left.AsRegisterPairHigh(),
-             ShifterOperand(right.AsRegisterPairHigh()));  // Signed compare.
-      __ b(&less, LT);
-      __ b(&greater, GT);
-      // Do LoadImmediate before any `cmp`, as LoadImmediate might affect
-      // the status flags.
-      __ LoadImmediate(output, 0);
-      __ cmp(left.AsRegisterPairLow(),
-             ShifterOperand(right.AsRegisterPairLow()));  // Unsigned compare.
-      __ b(&done, EQ);
-      __ b(&less, CC);
-
-      __ Bind(&greater);
-      __ LoadImmediate(output, 1);
-      __ b(&done);
-
-      __ Bind(&less);
-      __ LoadImmediate(output, -1);
-
-      __ Bind(&done);
+      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::RequiresRegister());
       break;
     }
     default:
-      LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
+      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
   }
 }
 
+void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
+  LocationSummary* locations = compare->GetLocations();
+  Register out = locations->Out().AsRegister<Register>();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  Label less, greater, done;
+  Primitive::Type type = compare->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong: {
+      __ cmp(left.AsRegisterPairHigh<Register>(),
+             ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
+      __ b(&less, LT);
+      __ b(&greater, GT);
+      // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
+      __ LoadImmediate(out, 0);
+      __ cmp(left.AsRegisterPairLow<Register>(),
+             ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      __ LoadImmediate(out, 0);
+      if (type == Primitive::kPrimFloat) {
+        __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
+      } else {
+        __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
+                 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
+      }
+      __ vmstat();  // transfer FP status register to ARM APSR.
+      __ b(compare->IsGtBias() ? &greater : &less, VS);  // VS for unordered.
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected compare type " << type;
+  }
+  __ b(&done, EQ);
+  __ b(&less, CC);  // CC is for both: unsigned compare for longs and 'less than' for floats.
+
+  __ Bind(&greater);
+  __ LoadImmediate(out, 1);
+  __ b(&done);
+
+  __ Bind(&less);
+  __ LoadImmediate(out, -1);
+
+  __ Bind(&done);
+}
+
 void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -1180,173 +2549,400 @@
 }
 
 void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
+  UNUSED(instruction);
   LOG(FATAL) << "Unreachable";
 }
 
-void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
+  // TODO (ported from quick): revisit Arm barrier kinds
+  DmbOptions flavour = DmbOptions::ISH;  // quiet c++ warnings
+  switch (kind) {
+    case MemBarrierKind::kAnyStore:
+    case MemBarrierKind::kLoadAny:
+    case MemBarrierKind::kAnyAny: {
+      flavour = DmbOptions::ISH;
+      break;
+    }
+    case MemBarrierKind::kStoreStore: {
+      flavour = DmbOptions::ISHST;
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected memory barrier " << kind;
+  }
+  __ dmb(flavour);
+}
+
+void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
+                                                         uint32_t offset,
+                                                         Register out_lo,
+                                                         Register out_hi) {
+  if (offset != 0) {
+    __ LoadImmediate(out_lo, offset);
+    __ add(IP, addr, ShifterOperand(out_lo));
+    addr = IP;
+  }
+  __ ldrexd(out_lo, out_hi, addr);
+}
+
+void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
+                                                          uint32_t offset,
+                                                          Register value_lo,
+                                                          Register value_hi,
+                                                          Register temp1,
+                                                          Register temp2,
+                                                          HInstruction* instruction) {
+  Label fail;
+  if (offset != 0) {
+    __ LoadImmediate(temp1, offset);
+    __ add(IP, addr, ShifterOperand(temp1));
+    addr = IP;
+  }
+  __ Bind(&fail);
+  // We need a load followed by store. (The address used in a STREX instruction must
+  // be the same as the address in the most recently executed LDREX instruction.)
+  __ ldrexd(temp1, temp2, addr);
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
+  __ strexd(temp1, value_lo, value_hi, addr);
+  __ cmp(temp1, ShifterOperand(0));
+  __ b(&fail, NE);
+}
+
+void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
+
+
+  Primitive::Type field_type = field_info.GetFieldType();
+  bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
+  bool generate_volatile = field_info.IsVolatile()
+      && is_wide
+      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   // Temporary registers for the write barrier.
-  if (instruction->GetFieldType() == Primitive::kPrimNot) {
+  // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
+  } else if (generate_volatile) {
+    // Arm encoding have some additional constraints for ldrexd/strexd:
+    // - registers need to be consecutive
+    // - the first register should be even but not R14.
+    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
+    // enable Arm encoding.
+    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
+
+    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());
+    if (field_type == Primitive::kPrimDouble) {
+      // For doubles we need two more registers to copy the value.
+      locations->AddTemp(Location::RegisterLocation(R2));
+      locations->AddTemp(Location::RegisterLocation(R3));
+    }
   }
 }
 
-void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
+                                                 const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
   LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
-  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
-  Primitive::Type field_type = instruction->GetFieldType();
+  Register base = locations->InAt(0).AsRegister<Register>();
+  Location value = locations->InAt(1);
+
+  bool is_volatile = field_info.IsVolatile();
+  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+  Primitive::Type field_type = field_info.GetFieldType();
+  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+  }
 
   switch (field_type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte: {
-      Register value = locations->InAt(1).AsArm().AsCoreRegister();
-      __ StoreToOffset(kStoreByte, value, obj, offset);
+      __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimShort:
     case Primitive::kPrimChar: {
-      Register value = locations->InAt(1).AsArm().AsCoreRegister();
-      __ StoreToOffset(kStoreHalfword, value, obj, offset);
+      __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      Register value = locations->InAt(1).AsArm().AsCoreRegister();
-      __ StoreToOffset(kStoreWord, value, obj, offset);
-      if (field_type == Primitive::kPrimNot) {
-        Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
-        Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
-        codegen_->MarkGCCard(temp, card, obj, value);
+      __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      if (is_volatile && !atomic_ldrd_strd) {
+        GenerateWideAtomicStore(base, offset,
+                                value.AsRegisterPairLow<Register>(),
+                                value.AsRegisterPairHigh<Register>(),
+                                locations->GetTemp(0).AsRegister<Register>(),
+                                locations->GetTemp(1).AsRegister<Register>(),
+                                instruction);
+      } else {
+        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
       }
       break;
     }
 
-    case Primitive::kPrimLong: {
-      ArmManagedRegister value = locations->InAt(1).AsArm();
-      __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
+    case Primitive::kPrimFloat: {
+      __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << field_type;
+    case Primitive::kPrimDouble: {
+      DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
+      if (is_volatile && !atomic_ldrd_strd) {
+        Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
+        Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
+
+        __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
+
+        GenerateWideAtomicStore(base, offset,
+                                value_reg_lo,
+                                value_reg_hi,
+                                locations->GetTemp(2).AsRegister<Register>(),
+                                locations->GetTemp(3).AsRegister<Register>(),
+                                instruction);
+      } else {
+        __ StoreDToOffset(value_reg, base, offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+      }
+      break;
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
+      UNREACHABLE();
+  }
+
+  // Longs and doubles are handled in the switch.
+  if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    Register temp = locations->GetTemp(0).AsRegister<Register>();
+    Register card = locations->GetTemp(1).AsRegister<Register>();
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+  }
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
   }
 }
 
-void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+
+  bool generate_volatile = field_info.IsVolatile()
+      && (field_info.GetFieldType() == Primitive::kPrimDouble)
+      && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+  if (generate_volatile) {
+    // Arm encoding have some additional constraints for ldrexd/strexd:
+    // - registers need to be consecutive
+    // - the first register should be even but not R14.
+    // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
+    // enable Arm encoding.
+    DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
+    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());
+  }
 }
 
-void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
-  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
+                                                 const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
 
-  switch (instruction->GetType()) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register base = locations->InAt(0).AsRegister<Register>();
+  Location out = locations->Out();
+  bool is_volatile = field_info.IsVolatile();
+  bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+  Primitive::Type field_type = field_info.GetFieldType();
+  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+  switch (field_type) {
     case Primitive::kPrimBoolean: {
-      Register out = locations->Out().AsArm().AsCoreRegister();
-      __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
+      __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimByte: {
-      Register out = locations->Out().AsArm().AsCoreRegister();
-      __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
+      __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimShort: {
-      Register out = locations->Out().AsArm().AsCoreRegister();
-      __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
+      __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimChar: {
-      Register out = locations->Out().AsArm().AsCoreRegister();
-      __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
+      __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      Register out = locations->Out().AsArm().AsCoreRegister();
-      __ LoadFromOffset(kLoadWord, out, obj, offset);
+      __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
       break;
     }
 
     case Primitive::kPrimLong: {
-      // TODO: support volatile.
-      ArmManagedRegister out = locations->Out().AsArm();
-      __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
+      if (is_volatile && !atomic_ldrd_strd) {
+        GenerateWideAtomicLoad(base, offset,
+                               out.AsRegisterPairLow<Register>(),
+                               out.AsRegisterPairHigh<Register>());
+      } else {
+        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
+      }
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+    case Primitive::kPrimFloat: {
+      __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
+      if (is_volatile && !atomic_ldrd_strd) {
+        Register lo = locations->GetTemp(0).AsRegister<Register>();
+        Register hi = locations->GetTemp(1).AsRegister<Register>();
+        GenerateWideAtomicLoad(base, offset, lo, hi);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ vmovdrr(out_reg, lo, hi);
+      } else {
+        __ LoadDFromOffset(out_reg, base, offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+      }
+      break;
+    }
 
     case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      LOG(FATAL) << "Unreachable type " << field_type;
+      UNREACHABLE();
   }
+
+  // Doubles are handled in the switch.
+  if (field_type != Primitive::kPrimDouble) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
+  }
+}
+
+void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
 }
 
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  // TODO: Have a normalization phase that makes this instruction never used.
-  locations->SetOut(Location::SameAsFirstInput());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
 }
 
-void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
+void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+    return;
+  }
+  Location obj = instruction->GetLocations()->InAt(0);
+
+  __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
   codegen_->AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
-  DCHECK(obj.Equals(locations->Out()));
 
-  if (obj.IsRegister()) {
-    __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0));
-  }
+  __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
   __ b(slow_path->GetEntryLabel(), EQ);
 }
 
+void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
+  if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+    GenerateImplicitNullCheck(instruction);
+  } else {
+    GenerateExplicitNullCheck(instruction);
+  }
+}
+
 void LocationsBuilderARM::VisitArrayGet(HArrayGet* 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());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
+  Register obj = locations->InAt(0).AsRegister<Register>();
   Location index = locations->InAt(1);
 
   switch (instruction->GetType()) {
     case Primitive::kPrimBoolean: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
-      Register out = locations->Out().AsArm().AsCoreRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
         __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
         __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
       }
       break;
@@ -1354,12 +2950,13 @@
 
     case Primitive::kPrimByte: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
-      Register out = locations->Out().AsArm().AsCoreRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
         __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
         __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
       }
       break;
@@ -1367,12 +2964,13 @@
 
     case Primitive::kPrimShort: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
-      Register out = locations->Out().AsArm().AsCoreRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
         __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
         __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
       }
       break;
@@ -1380,12 +2978,13 @@
 
     case Primitive::kPrimChar: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
-      Register out = locations->Out().AsArm().AsCoreRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
         __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
         __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
       }
       break;
@@ -1395,12 +2994,13 @@
     case Primitive::kPrimNot: {
       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      Register out = locations->Out().AsArm().AsCoreRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
         __ LoadFromOffset(kLoadWord, out, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
         __ LoadFromOffset(kLoadWord, out, IP, data_offset);
       }
       break;
@@ -1408,59 +3008,100 @@
 
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
-      ArmManagedRegister out = locations->Out().AsArm();
+      Location out = locations->Out();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
-        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
-        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
+        __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
       }
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+    case Primitive::kPrimFloat: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+      Location out = locations->Out();
+      DCHECK(out.IsFpuRegister());
+      if (index.IsConstant()) {
+        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
+      } else {
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
+        __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
+      }
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+      Location out = locations->Out();
+      DCHECK(out.IsFpuRegisterPair());
+      if (index.IsConstant()) {
+        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
+      } else {
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
+        __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
+      }
+      break;
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      UNREACHABLE();
   }
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
-  bool is_object = value_type == Primitive::kPrimNot;
+
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+  bool needs_runtime_call = instruction->NeedsTypeCheck();
+
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
-      instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
-  if (is_object) {
+      instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+  if (needs_runtime_call) {
     InvokeRuntimeCallingConvention calling_convention;
-    locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
-    locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
-    locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
+    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+    locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+    locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   } else {
     locations->SetInAt(0, Location::RequiresRegister());
     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
     locations->SetInAt(2, Location::RequiresRegister());
+
+    if (needs_write_barrier) {
+      // Temporary registers for the write barrier.
+      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());
+    }
   }
 }
 
 void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
+  Register obj = locations->InAt(0).AsRegister<Register>();
   Location index = locations->InAt(1);
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_runtime_call = locations->WillCall();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
-      Register value = locations->InAt(2).AsArm().AsCoreRegister();
+      Register value = locations->InAt(2).AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
         __ StoreToOffset(kStoreByte, value, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
         __ StoreToOffset(kStoreByte, value, IP, data_offset);
       }
       break;
@@ -1469,58 +3110,99 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimChar: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
-      Register value = locations->InAt(2).AsArm().AsCoreRegister();
+      Register value = locations->InAt(2).AsRegister<Register>();
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
         __ StoreToOffset(kStoreHalfword, value, obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
         __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
       }
       break;
     }
 
-    case Primitive::kPrimInt: {
-      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      Register value = locations->InAt(2).AsArm().AsCoreRegister();
-      if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-        __ StoreToOffset(kStoreWord, value, obj, offset);
-      } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
-        __ StoreToOffset(kStoreWord, value, IP, data_offset);
-      }
-      break;
-    }
-
+    case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
-      __ ldr(LR, Address(TR, offset));
-      __ blx(LR);
-      codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
-      DCHECK(!codegen_->IsLeafMethod());
+      if (!needs_runtime_call) {
+        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+        Register value = locations->InAt(2).AsRegister<Register>();
+        if (index.IsConstant()) {
+          size_t offset =
+              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+          __ StoreToOffset(kStoreWord, value, obj, offset);
+        } else {
+          DCHECK(index.IsRegister()) << index;
+          __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
+          __ StoreToOffset(kStoreWord, value, IP, data_offset);
+        }
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (needs_write_barrier) {
+          DCHECK_EQ(value_type, Primitive::kPrimNot);
+          Register temp = locations->GetTemp(0).AsRegister<Register>();
+          Register card = locations->GetTemp(1).AsRegister<Register>();
+          codegen_->MarkGCCard(temp, card, obj, value);
+        }
+      } else {
+        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
+                                instruction,
+                                instruction->GetDexPc());
+      }
       break;
     }
 
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
-      ArmManagedRegister value = locations->InAt(2).AsArm();
+      Location value = locations->InAt(2);
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
-        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
+        size_t offset =
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
       } else {
-        __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
-        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
+        __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
       }
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+    case Primitive::kPrimFloat: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+      Location value = locations->InAt(2);
+      DCHECK(value.IsFpuRegister());
+      if (index.IsConstant()) {
+        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
+      } else {
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
+        __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
+      }
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+      Location value = locations->InAt(2);
+      DCHECK(value.IsFpuRegisterPair());
+      if (index.IsConstant()) {
+        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
+      } else {
+        __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
+        __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
+      }
+
+      break;
+    }
 
     case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      LOG(FATAL) << "Unreachable type " << value_type;
+      UNREACHABLE();
+  }
+
+  // Ints and objects are handled in the switch.
+  if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
   }
 }
 
@@ -1528,15 +3210,16 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations = instruction->GetLocations();
   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
-  Register obj = locations->InAt(0).AsArm().AsCoreRegister();
-  Register out = locations->Out().AsArm().AsCoreRegister();
+  Register obj = locations->InAt(0).AsRegister<Register>();
+  Register out = locations->Out().AsRegister<Register>();
   __ LoadFromOffset(kLoadWord, out, obj, offset);
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -1544,18 +3227,19 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  // TODO: Have a normalization phase that makes this instruction never used.
-  locations->SetOut(Location::SameAsFirstInput());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
 }
 
 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);
 
-  Register index = locations->InAt(0).AsArm().AsCoreRegister();
-  Register length = locations->InAt(1).AsArm().AsCoreRegister();
+  Register index = locations->InAt(0).AsRegister<Register>();
+  Register length = locations->InAt(1).AsRegister<Register>();
 
   __ cmp(index, ShifterOperand(length));
   __ b(slow_path->GetEntryLabel(), CS);
@@ -1576,9 +3260,11 @@
 
 void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
   // Nothing to do, this is driven by the code generator.
+  UNUSED(temp);
 }
 
 void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
+  UNUSED(instruction);
   LOG(FATAL) << "Unreachable";
 }
 
@@ -1610,13 +3296,15 @@
       new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
   codegen_->AddSlowPath(slow_path);
 
-  __ AddConstant(R4, R4, -1);
-  __ cmp(R4, ShifterOperand(0));
+  __ LoadFromOffset(
+      kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
+  __ cmp(IP, ShifterOperand(0));
+  // TODO: Figure out the branch offsets and use cbz/cbnz.
   if (successor == nullptr) {
-    __ b(slow_path->GetEntryLabel(), LE);
+    __ b(slow_path->GetEntryLabel(), NE);
     __ Bind(slow_path->GetReturnLabel());
   } else {
-    __ b(codegen_->GetLabelOf(successor), GT);
+    __ b(codegen_->GetLabelOf(successor), EQ);
     __ b(slow_path->GetEntryLabel());
   }
 }
@@ -1632,31 +3320,97 @@
 
   if (source.IsRegister()) {
     if (destination.IsRegister()) {
-      __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister());
+      __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
     } else {
       DCHECK(destination.IsStackSlot());
-      __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(),
+      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
                        SP, destination.GetStackIndex());
     }
   } else if (source.IsStackSlot()) {
     if (destination.IsRegister()) {
-      __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(),
+      __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
                         SP, source.GetStackIndex());
+    } else if (destination.IsFpuRegister()) {
+      __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
     } else {
       DCHECK(destination.IsStackSlot());
       __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
       __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
     }
-  } else {
-    DCHECK(source.IsConstant());
-    DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
-    int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
-    if (destination.IsRegister()) {
-      __ LoadImmediate(destination.AsArm().AsCoreRegister(), value);
+  } else if (source.IsFpuRegister()) {
+    if (destination.IsFpuRegister()) {
+      __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
     } else {
       DCHECK(destination.IsStackSlot());
-      __ LoadImmediate(IP, value);
-      __ str(IP, Address(SP, destination.GetStackIndex()));
+      __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
+    }
+  } else if (source.IsDoubleStackSlot()) {
+    DCHECK(destination.IsDoubleStackSlot()) << destination;
+    __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
+    __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+    __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize));
+    __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
+  } else {
+    DCHECK(source.IsConstant()) << source;
+    HInstruction* constant = source.GetConstant();
+    if (constant->IsIntConstant()) {
+      int32_t value = constant->AsIntConstant()->GetValue();
+      if (destination.IsRegister()) {
+        __ LoadImmediate(destination.AsRegister<Register>(), value);
+      } else {
+        DCHECK(destination.IsStackSlot());
+        __ LoadImmediate(IP, value);
+        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+      }
+    } else if (constant->IsLongConstant()) {
+      int64_t value = constant->AsLongConstant()->GetValue();
+      if (destination.IsRegister()) {
+        // In the presence of long or double constants, the parallel move resolver will
+        // split the move into two, but keeps the same constant for both moves. Here,
+        // we use the low or high part depending on which register this move goes to.
+        if (destination.reg() % 2 == 0) {
+          __ LoadImmediate(destination.AsRegister<Register>(), Low32Bits(value));
+        } else {
+          __ LoadImmediate(destination.AsRegister<Register>(), High32Bits(value));
+        }
+      } else {
+        DCHECK(destination.IsDoubleStackSlot());
+        __ LoadImmediate(IP, Low32Bits(value));
+        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+        __ LoadImmediate(IP, High32Bits(value));
+        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
+      }
+    } else if (constant->IsDoubleConstant()) {
+      double value = constant->AsDoubleConstant()->GetValue();
+      uint64_t int_value = bit_cast<uint64_t, double>(value);
+      if (destination.IsFpuRegister()) {
+        // In the presence of long or double constants, the parallel move resolver will
+        // split the move into two, but keeps the same constant for both moves. Here,
+        // we use the low or high part depending on which register this move goes to.
+        if (destination.reg() % 2 == 0) {
+          __ LoadSImmediate(destination.AsFpuRegister<SRegister>(),
+                            bit_cast<float, uint32_t>(Low32Bits(int_value)));
+        } else {
+          __ LoadSImmediate(destination.AsFpuRegister<SRegister>(),
+                            bit_cast<float, uint32_t>(High32Bits(int_value)));
+        }
+      } else {
+        DCHECK(destination.IsDoubleStackSlot());
+        __ LoadImmediate(IP, Low32Bits(int_value));
+        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+        __ LoadImmediate(IP, High32Bits(int_value));
+        __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
+      }
+    } else {
+      DCHECK(constant->IsFloatConstant()) << constant->DebugName();
+      float value = constant->AsFloatConstant()->GetValue();
+      if (destination.IsFpuRegister()) {
+        __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
+      } else {
+        DCHECK(destination.IsStackSlot());
+        __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
+        __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
+      }
     }
   }
 }
@@ -1684,19 +3438,36 @@
   Location destination = move->GetDestination();
 
   if (source.IsRegister() && destination.IsRegister()) {
-    DCHECK_NE(source.AsArm().AsCoreRegister(), IP);
-    DCHECK_NE(destination.AsArm().AsCoreRegister(), IP);
-    __ Mov(IP, source.AsArm().AsCoreRegister());
-    __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister());
-    __ Mov(destination.AsArm().AsCoreRegister(), IP);
+    DCHECK_NE(source.AsRegister<Register>(), IP);
+    DCHECK_NE(destination.AsRegister<Register>(), IP);
+    __ Mov(IP, source.AsRegister<Register>());
+    __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
+    __ Mov(destination.AsRegister<Register>(), IP);
   } else if (source.IsRegister() && destination.IsStackSlot()) {
-    Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex());
+    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
   } else if (source.IsStackSlot() && destination.IsRegister()) {
-    Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex());
+    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
     Exchange(source.GetStackIndex(), destination.GetStackIndex());
+  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
+    __ vmovrs(IP, source.AsFpuRegister<SRegister>());
+    __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
+    __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
+  } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
+    SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
+                                           : destination.AsFpuRegister<SRegister>();
+    int mem = source.IsFpuRegister()
+        ? destination.GetStackIndex()
+        : source.GetStackIndex();
+
+    __ vmovrs(IP, reg);
+    __ LoadFromOffset(kLoadWord, IP, SP, mem);
+    __ StoreToOffset(kStoreWord, IP, SP, mem);
+  } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
+    Exchange(source.GetStackIndex(), destination.GetStackIndex());
+    Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
   } else {
-    LOG(FATAL) << "Unimplemented";
+    LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
   }
 }
 
@@ -1708,5 +3479,283 @@
   __ Pop(static_cast<Register>(reg));
 }
 
+void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
+  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
+      ? LocationSummary::kCallOnSlowPath
+      : LocationSummary::kNoCall;
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
+  Register out = cls->GetLocations()->Out().AsRegister<Register>();
+  if (cls->IsReferrersClass()) {
+    DCHECK(!cls->CanCallRuntime());
+    DCHECK(!cls->MustGenerateClinitCheck());
+    codegen_->LoadCurrentMethod(out);
+    __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
+  } else {
+    DCHECK(cls->CanCallRuntime());
+    codegen_->LoadCurrentMethod(out);
+    __ LoadFromOffset(
+        kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
+    __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
+
+    SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+    codegen_->AddSlowPath(slow_path);
+    __ cmp(out, ShifterOperand(0));
+    __ b(slow_path->GetEntryLabel(), EQ);
+    if (cls->MustGenerateClinitCheck()) {
+      GenerateClassInitializationCheck(slow_path, out);
+    } else {
+      __ Bind(slow_path->GetExitLabel());
+    }
+  }
+}
+
+void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (check->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
+  // We assume the class is not null.
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
+      check->GetLoadClass(), check, check->GetDexPc(), true);
+  codegen_->AddSlowPath(slow_path);
+  GenerateClassInitializationCheck(slow_path,
+                                   check->GetLocations()->InAt(0).AsRegister<Register>());
+}
+
+void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
+    SlowPathCodeARM* slow_path, Register class_reg) {
+  __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
+  __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
+  __ b(slow_path->GetEntryLabel(), LT);
+  // Even if the initialized flag is set, we may be in a situation where caches are not synced
+  // properly. Therefore, we do a memory fence.
+  __ dmb(ISH);
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
+  codegen_->AddSlowPath(slow_path);
+
+  Register out = load->GetLocations()->Out().AsRegister<Register>();
+  codegen_->LoadCurrentMethod(out);
+  __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value());
+  __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
+  __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
+  __ cmp(out, ShifterOperand(0));
+  __ b(slow_path->GetEntryLabel(), EQ);
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
+  Register out = load->GetLocations()->Out().AsRegister<Register>();
+  int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
+  __ LoadFromOffset(kLoadWord, out, TR, offset);
+  __ LoadImmediate(IP, 0);
+  __ StoreToOffset(kStoreWord, IP, TR, offset);
+}
+
+void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary::CallKind call_kind = instruction->IsClassFinal()
+      ? LocationSummary::kNoCall
+      : LocationSummary::kCallOnSlowPath;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = locations->InAt(0).AsRegister<Register>();
+  Register cls = locations->InAt(1).AsRegister<Register>();
+  Register out = locations->Out().AsRegister<Register>();
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  Label done, zero;
+  SlowPathCodeARM* slow_path = nullptr;
+
+  // Return 0 if `obj` is null.
+  // TODO: avoid this check if we know obj is not null.
+  __ cmp(obj, ShifterOperand(0));
+  __ b(&zero, EQ);
+  // Compare the class of `obj` with `cls`.
+  __ LoadFromOffset(kLoadWord, out, obj, class_offset);
+  __ cmp(out, ShifterOperand(cls));
+  if (instruction->IsClassFinal()) {
+    // Classes must be equal for the instanceof to succeed.
+    __ b(&zero, NE);
+    __ LoadImmediate(out, 1);
+    __ b(&done);
+  } else {
+    // If the classes are not equal, we go into a slow path.
+    DCHECK(locations->OnlyCallsOnSlowPath());
+    slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
+        instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
+    codegen_->AddSlowPath(slow_path);
+    __ b(slow_path->GetEntryLabel(), NE);
+    __ LoadImmediate(out, 1);
+    __ b(&done);
+  }
+  __ Bind(&zero);
+  __ LoadImmediate(out, 0);
+  if (slow_path != nullptr) {
+    __ Bind(slow_path->GetExitLabel());
+  }
+  __ Bind(&done);
+}
+
+void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+      instruction, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = locations->InAt(0).AsRegister<Register>();
+  Register cls = locations->InAt(1).AsRegister<Register>();
+  Register temp = locations->GetTemp(0).AsRegister<Register>();
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
+      instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
+  codegen_->AddSlowPath(slow_path);
+
+  // TODO: avoid this check if we know obj is not null.
+  __ cmp(obj, ShifterOperand(0));
+  __ b(slow_path->GetExitLabel(), EQ);
+  // Compare the class of `obj` with `cls`.
+  __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
+  __ cmp(temp, ShifterOperand(cls));
+  __ b(slow_path->GetEntryLabel(), NE);
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
+  codegen_->InvokeRuntime(instruction->IsEnter()
+        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
+      instruction,
+      instruction->GetDexPc());
+}
+
+void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+
+void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  Location::OutputOverlap output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong)
+      ? Location::kOutputOverlap
+      : Location::kNoOutputOverlap;
+  locations->SetOut(Location::RequiresRegister(), output_overlaps);
+}
+
+void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    Register first = locations->InAt(0).AsRegister<Register>();
+    Register second = locations->InAt(1).AsRegister<Register>();
+    Register out = locations->Out().AsRegister<Register>();
+    if (instruction->IsAnd()) {
+      __ and_(out, first, ShifterOperand(second));
+    } else if (instruction->IsOr()) {
+      __ orr(out, first, ShifterOperand(second));
+    } else {
+      DCHECK(instruction->IsXor());
+      __ eor(out, first, ShifterOperand(second));
+    }
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    Location first = locations->InAt(0);
+    Location second = locations->InAt(1);
+    Location out = locations->Out();
+    if (instruction->IsAnd()) {
+      __ and_(out.AsRegisterPairLow<Register>(),
+              first.AsRegisterPairLow<Register>(),
+              ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ and_(out.AsRegisterPairHigh<Register>(),
+              first.AsRegisterPairHigh<Register>(),
+              ShifterOperand(second.AsRegisterPairHigh<Register>()));
+    } else if (instruction->IsOr()) {
+      __ orr(out.AsRegisterPairLow<Register>(),
+             first.AsRegisterPairLow<Register>(),
+             ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ orr(out.AsRegisterPairHigh<Register>(),
+             first.AsRegisterPairHigh<Register>(),
+             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+    } else {
+      DCHECK(instruction->IsXor());
+      __ eor(out.AsRegisterPairLow<Register>(),
+             first.AsRegisterPairLow<Register>(),
+             ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ eor(out.AsRegisterPairHigh<Register>(),
+             first.AsRegisterPairHigh<Register>(),
+             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+    }
+  }
+}
+
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 8c86b7a..0de6669 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -18,6 +18,8 @@
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_
 
 #include "code_generator.h"
+#include "dex/compiler_enums.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "parallel_move_resolver.h"
 #include "utils/arm/assembler_thumb2.h"
@@ -26,22 +28,24 @@
 namespace arm {
 
 class CodeGeneratorARM;
+class SlowPathCodeARM;
 
-static constexpr size_t kArmWordSize = 4;
+// Use a local definition to prevent copying mistakes.
+static constexpr size_t kArmWordSize = kArmPointerSize;
 
 static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 };
-static constexpr RegisterPair kParameterCorePairRegisters[] = { R1_R2, R2_R3 };
 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+static constexpr SRegister kParameterFpuRegisters[] =
+    { S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15 };
+static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
 
-class InvokeDexCallingConvention : public CallingConvention<Register> {
+class InvokeDexCallingConvention : public CallingConvention<Register, SRegister> {
  public:
   InvokeDexCallingConvention()
-      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
-
-  RegisterPair GetRegisterPairAt(size_t argument_index) {
-    DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
-    return kParameterCorePairRegisters[argument_index];
-  }
+      : CallingConvention(kParameterCoreRegisters,
+                          kParameterCoreRegistersLength,
+                          kParameterFpuRegisters,
+                          kParameterFpuRegistersLength) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
@@ -49,13 +53,18 @@
 
 class InvokeDexCallingConventionVisitor {
  public:
-  InvokeDexCallingConventionVisitor() : gp_index_(0) {}
+  InvokeDexCallingConventionVisitor()
+      : gp_index_(0), float_index_(0), double_index_(0), stack_index_(0) {}
 
   Location GetNextLocation(Primitive::Type type);
+  Location GetReturnLocation(Primitive::Type type);
 
  private:
   InvokeDexCallingConvention calling_convention;
   uint32_t gp_index_;
+  uint32_t float_index_;
+  uint32_t double_index_;
+  uint32_t stack_index_;
 
   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor);
 };
@@ -65,10 +74,10 @@
   ParallelMoveResolverARM(ArenaAllocator* allocator, CodeGeneratorARM* codegen)
       : ParallelMoveResolver(allocator), codegen_(codegen) {}
 
-  virtual void EmitMove(size_t index) OVERRIDE;
-  virtual void EmitSwap(size_t index) OVERRIDE;
-  virtual void SpillScratch(int reg) OVERRIDE;
-  virtual void RestoreScratch(int reg) OVERRIDE;
+  void EmitMove(size_t index) OVERRIDE;
+  void EmitSwap(size_t index) OVERRIDE;
+  void SpillScratch(int reg) OVERRIDE;
+  void RestoreScratch(int reg) OVERRIDE;
 
   ArmAssembler* GetAssembler() const;
 
@@ -86,16 +95,20 @@
   LocationsBuilderARM(HGraph* graph, CodeGeneratorARM* codegen)
       : HGraphVisitor(graph), codegen_(codegen) {}
 
-#define DECLARE_VISIT_INSTRUCTION(name)     \
-  virtual void Visit##name(H##name* instr);
+#define DECLARE_VISIT_INSTRUCTION(name, super)     \
+  void Visit##name(H##name* instr);
 
   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void HandleInvoke(HInvoke* invoke);
-
  private:
+  void HandleInvoke(HInvoke* invoke);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
+  void HandleShift(HBinaryOperation* operation);
+  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
+
   CodeGeneratorARM* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
 
@@ -106,21 +119,34 @@
  public:
   InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
 
-#define DECLARE_VISIT_INSTRUCTION(name)     \
-  virtual void Visit##name(H##name* instr);
+#define DECLARE_VISIT_INSTRUCTION(name, super)     \
+  void Visit##name(H##name* instr);
 
   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
   ArmAssembler* GetAssembler() const { return assembler_; }
-  void LoadCurrentMethod(Register reg);
 
  private:
   // Generate code for the given suspend check. If not null, `successor`
   // is the block to branch to if the suspend check is not needed, and after
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
+  void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
+  void HandleShift(HBinaryOperation* operation);
+  void GenerateMemoryBarrier(MemBarrierKind kind);
+  void GenerateWideAtomicStore(Register addr, uint32_t offset,
+                               Register value_lo, Register value_hi,
+                               Register temp1, Register temp2,
+                               HInstruction* instruction);
+  void GenerateWideAtomicLoad(Register addr, uint32_t offset,
+                              Register out_lo, Register out_hi);
+  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
 
   ArmAssembler* const assembler_;
   CodeGeneratorARM* const codegen_;
@@ -130,57 +156,64 @@
 
 class CodeGeneratorARM : public CodeGenerator {
  public:
-  explicit CodeGeneratorARM(HGraph* graph);
+  CodeGeneratorARM(HGraph* graph,
+                   const ArmInstructionSetFeatures& isa_features,
+                   const CompilerOptions& compiler_options);
   virtual ~CodeGeneratorARM() {}
 
-  virtual void GenerateFrameEntry() OVERRIDE;
-  virtual void GenerateFrameExit() OVERRIDE;
-  virtual void Bind(Label* label) 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;
+  void GenerateFrameEntry() OVERRIDE;
+  void GenerateFrameExit() OVERRIDE;
+  void Bind(HBasicBlock* block) OVERRIDE;
+  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
-  virtual size_t GetWordSize() const OVERRIDE {
+  size_t GetWordSize() const OVERRIDE {
     return kArmWordSize;
   }
 
-  virtual size_t FrameEntrySpillSize() const OVERRIDE;
+  size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
+    // Allocated in S registers, which are word sized.
+    return kArmWordSize;
+  }
 
-  virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+  size_t FrameEntrySpillSize() const OVERRIDE;
+
+  HGraphVisitor* GetLocationBuilder() OVERRIDE {
     return &location_builder_;
   }
 
-  virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+  HGraphVisitor* GetInstructionVisitor() OVERRIDE {
     return &instruction_visitor_;
   }
 
-  virtual ArmAssembler* GetAssembler() OVERRIDE {
+  ArmAssembler* GetAssembler() OVERRIDE {
     return &assembler_;
   }
 
-  virtual void SetupBlockedRegisters(bool* blocked_registers) const OVERRIDE;
-  virtual ManagedRegister AllocateFreeRegister(
-      Primitive::Type type, bool* blocked_registers) const OVERRIDE;
-  virtual size_t GetNumberOfRegisters() const OVERRIDE;
-
-  virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
-
-  virtual size_t GetNumberOfCoreRegisters() const OVERRIDE {
-    return kNumberOfCoreRegisters;
+  uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+    return GetLabelOf(block)->Position();
   }
 
-  virtual size_t GetNumberOfFloatingPointRegisters() const OVERRIDE {
-    return kNumberOfDRegisters;
-  }
+  void SetupBlockedRegisters() const OVERRIDE;
 
-  virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
-  virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+  Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
 
-  ParallelMoveResolverARM* GetMoveResolver() {
+  Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+
+  void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+  void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+
+  // Blocks all register pairs made out of blocked core registers.
+  void UpdateBlockedPairRegisters() const;
+
+  ParallelMoveResolverARM* GetMoveResolver() OVERRIDE {
     return &move_resolver_;
   }
 
-  virtual InstructionSet GetInstructionSet() const OVERRIDE {
+  InstructionSet GetInstructionSet() const OVERRIDE {
     return InstructionSet::kThumb2;
   }
 
@@ -189,14 +222,39 @@
   // Helper method to move a 64bits value between two locations.
   void Move64(Location destination, Location source);
 
+  // Load current method into `reg`.
+  void LoadCurrentMethod(Register reg);
+
+  // Generate code to invoke a runtime entry point.
+  void InvokeRuntime(int32_t offset, HInstruction* instruction, uint32_t dex_pc);
+
   // 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();
+  }
+
+  void Initialize() OVERRIDE {
+    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
+  }
+
+  const ArmInstructionSetFeatures& GetInstructionSetFeatures() const {
+    return isa_features_;
+  }
+
+  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
+    return type == Primitive::kPrimDouble || type == Primitive::kPrimLong;
+  }
+
  private:
+  // Labels for each block that will be compiled.
+  GrowableArray<Label> block_labels_;
   LocationsBuilderARM location_builder_;
   InstructionCodeGeneratorARM instruction_visitor_;
   ParallelMoveResolverARM move_resolver_;
   Thumb2Assembler assembler_;
+  const ArmInstructionSetFeatures& isa_features_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
 };
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
new file mode 100644
index 0000000..760d2be
--- /dev/null
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -0,0 +1,2687 @@
+/*
+ * 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 "entrypoints/quick/quick_entrypoints_enum.h"
+#include "gc/accounting/card_table.h"
+#include "mirror/array-inl.h"
+#include "mirror/art_method.h"
+#include "mirror/class.h"
+#include "offsets.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 {
+
+// TODO: Tune the use of Load-Acquire, Store-Release vs Data Memory Barriers.
+// For now we prefer the use of load-acquire, store-release over explicit memory barriers.
+static constexpr bool kUseAcquireRelease = true;
+static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
+static constexpr int kCurrentMethodStackOffset = 0;
+
+namespace {
+
+bool IsFPType(Primitive::Type type) {
+  return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
+}
+
+bool IsIntegralType(Primitive::Type type) {
+  switch (type) {
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Is64BitType(Primitive::Type type) {
+  return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
+}
+
+// Convenience helpers to ease conversion to and from VIXL operands.
+static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
+              "Unexpected values for register codes.");
+
+int VIXLRegCodeFromART(int code) {
+  if (code == SP) {
+    return vixl::kSPRegInternalCode;
+  }
+  if (code == XZR) {
+    return vixl::kZeroRegCode;
+  }
+  return code;
+}
+
+int ARTRegCodeFromVIXL(int code) {
+  if (code == vixl::kSPRegInternalCode) {
+    return SP;
+  }
+  if (code == vixl::kZeroRegCode) {
+    return XZR;
+  }
+  return code;
+}
+
+Register XRegisterFrom(Location location) {
+  DCHECK(location.IsRegister());
+  return Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
+}
+
+Register WRegisterFrom(Location location) {
+  DCHECK(location.IsRegister());
+  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());
+}
+
+FPRegister DRegisterFrom(Location location) {
+  DCHECK(location.IsFpuRegister());
+  return FPRegister::DRegFromCode(location.reg());
+}
+
+FPRegister SRegisterFrom(Location location) {
+  DCHECK(location.IsFpuRegister());
+  return FPRegister::SRegFromCode(location.reg());
+}
+
+FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
+  DCHECK(IsFPType(type));
+  return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
+}
+
+FPRegister OutputFPRegister(HInstruction* instr) {
+  return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
+}
+
+FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
+  return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
+                        instr->InputAt(input_index)->GetType());
+}
+
+CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
+  return IsFPType(type) ? CPURegister(FPRegisterFrom(location, type))
+                        : CPURegister(RegisterFrom(location, type));
+}
+
+CPURegister OutputCPURegister(HInstruction* instr) {
+  return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr))
+                                    : static_cast<CPURegister>(OutputRegister(instr));
+}
+
+CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
+  return IsFPType(instr->InputAt(index)->GetType())
+      ? static_cast<CPURegister>(InputFPRegisterAt(instr, index))
+      : static_cast<CPURegister>(InputRegisterAt(instr, index));
+}
+
+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, size_t offset = 0) {
+  // A heap reference must be 32bit, so fit in a W register.
+  DCHECK(base.IsW());
+  return MemOperand(base.X(), offset);
+}
+
+MemOperand HeapOperand(const Register& base, Offset offset) {
+  return HeapOperand(base, offset.SizeValue());
+}
+
+MemOperand HeapOperandFrom(Location location, Offset offset) {
+  return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
+}
+
+Location LocationFrom(const Register& reg) {
+  return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
+}
+
+Location LocationFrom(const FPRegister& fpreg) {
+  return Location::FpuRegisterLocation(fpreg.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.
+}
+
+Location ARM64ReturnLocation(Primitive::Type return_type) {
+  DCHECK_NE(return_type, Primitive::kPrimVoid);
+  // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
+  // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
+  // but we use the exact registers for clarity.
+  if (return_type == Primitive::kPrimFloat) {
+    return LocationFrom(s0);
+  } else if (return_type == Primitive::kPrimDouble) {
+    return LocationFrom(d0);
+  } else if (return_type == Primitive::kPrimLong) {
+    return LocationFrom(x0);
+  } else {
+    return LocationFrom(w0);
+  }
+}
+
+static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
+static constexpr size_t kRuntimeParameterCoreRegistersLength =
+    arraysize(kRuntimeParameterCoreRegisters);
+static const FPRegister kRuntimeParameterFpuRegisters[] = { d0, d1, d2, d3, d4, d5, d6, d7 };
+static constexpr size_t kRuntimeParameterFpuRegistersLength =
+    arraysize(kRuntimeParameterCoreRegisters);
+
+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) {
+  return ARM64ReturnLocation(return_type);
+}
+
+#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
+#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
+
+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:
+  BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
+                           Location index_location,
+                           Location length_location)
+      : instruction_(instruction),
+        index_location_(index_location),
+        length_location_(length_location) {}
+
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
+    InvokeRuntimeCallingConvention calling_convention;
+    codegen->EmitParallelMoves(
+        index_location_, LocationFrom(calling_convention.GetRegisterAt(0)),
+        length_location_, LocationFrom(calling_convention.GetRegisterAt(1)));
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
+    CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
+  }
+
+ private:
+  HBoundsCheck* const instruction_;
+  const Location index_location_;
+  const Location length_location_;
+
+  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
+};
+
+class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
+    CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
+  }
+
+ private:
+  HDivZeroCheck* const instruction_;
+  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
+};
+
+class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  LoadClassSlowPathARM64(HLoadClass* cls,
+                         HInstruction* at,
+                         uint32_t dex_pc,
+                         bool do_clinit)
+      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
+  }
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = at_->GetLocations();
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
+    arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
+    int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
+                                            : QUICK_ENTRY_POINT(pInitializeType);
+    arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
+    if (do_clinit_) {
+      CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t, mirror::ArtMethod*>();
+    } else {
+      CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t, mirror::ArtMethod*>();
+    }
+
+    // Move the class to the desired location.
+    Location out = locations->Out();
+    if (out.IsValid()) {
+      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+      Primitive::Type type = at_->GetType();
+      arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ B(GetExitLabel());
+  }
+
+ private:
+  // The class this slow path will load.
+  HLoadClass* const cls_;
+
+  // The instruction where this slow path is happening.
+  // (Might be the load class or an initialization check).
+  HInstruction* const at_;
+
+  // The dex PC of `at_`.
+  const uint32_t dex_pc_;
+
+  // Whether to initialize the class.
+  const bool do_clinit_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
+};
+
+class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
+    __ Mov(calling_convention.GetRegisterAt(0).W(), instruction_->GetStringIndex());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
+    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t, mirror::ArtMethod*>();
+    Primitive::Type type = instruction_->GetType();
+    arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
+
+    codegen->RestoreLiveRegisters(locations);
+    __ B(GetExitLabel());
+  }
+
+ private:
+  HLoadString* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
+};
+
+class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
+    CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
+  }
+
+ private:
+  HNullCheck* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
+};
+
+class StackOverflowCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  StackOverflowCheckSlowPathARM64() {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowStackOverflow), nullptr, 0);
+    CheckEntrypointTypes<kQuickThrowStackOverflow, void, void*>();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM64);
+};
+
+class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
+                                     HBasicBlock* successor)
+      : instruction_(instruction), successor_(successor) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(instruction_->GetLocations());
+    arm64_codegen->InvokeRuntime(
+        QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
+    CheckEntrypointTypes<kQuickTestSuspend, void, void>();
+    codegen->RestoreLiveRegisters(instruction_->GetLocations());
+    if (successor_ == nullptr) {
+      __ B(GetReturnLabel());
+    } else {
+      __ B(arm64_codegen->GetLabelOf(successor_));
+    }
+  }
+
+  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);
+};
+
+class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  TypeCheckSlowPathARM64(HInstruction* instruction,
+                         Location class_to_check,
+                         Location object_class,
+                         uint32_t dex_pc)
+      : instruction_(instruction),
+        class_to_check_(class_to_check),
+        object_class_(object_class),
+        dex_pc_(dex_pc) {}
+
+  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(instruction_->IsCheckCast()
+           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
+
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
+    InvokeRuntimeCallingConvention calling_convention;
+    codegen->EmitParallelMoves(
+        class_to_check_, LocationFrom(calling_convention.GetRegisterAt(0)),
+        object_class_, LocationFrom(calling_convention.GetRegisterAt(1)));
+
+    if (instruction_->IsInstanceOf()) {
+      arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_);
+      Primitive::Type ret_type = instruction_->GetType();
+      Location ret_loc = calling_convention.GetReturnLocation(ret_type);
+      arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
+      CheckEntrypointTypes<kQuickInstanceofNonTrivial, uint32_t,
+                           const mirror::Class*, const mirror::Class*>();
+    } else {
+      DCHECK(instruction_->IsCheckCast());
+      arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_);
+      CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ B(GetExitLabel());
+  }
+
+ private:
+  HInstruction* const instruction_;
+  const Location class_to_check_;
+  const Location object_class_;
+  uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
+};
+
+#undef __
+
+Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
+  Location next_location;
+  if (type == Primitive::kPrimVoid) {
+    LOG(FATAL) << "Unreachable type " << type;
+  }
+
+  if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
+    next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
+  } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) {
+    next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
+  } else {
+    size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
+    next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
+                                      : Location::StackSlot(stack_offset);
+  }
+
+  // Space on the stack is reserved for all arguments.
+  stack_index_ += Is64BitType(type) ? 2 : 1;
+  return next_location;
+}
+
+CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options)
+    : CodeGenerator(graph,
+                    kNumberOfAllocatableRegisters,
+                    kNumberOfAllocatableFPRegisters,
+                    kNumberOfAllocatableRegisterPairs,
+                    compiler_options),
+      block_labels_(nullptr),
+      location_builder_(graph, this),
+      instruction_visitor_(graph, this),
+      move_resolver_(graph->GetArena(), this) {}
+
+#undef __
+#define __ GetVIXLAssembler()->
+
+void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
+  // Ensure we emit the literal pool.
+  __ FinalizeCode();
+  CodeGenerator::Finalize(allocator);
+}
+
+void ParallelMoveResolverARM64::EmitMove(size_t index) {
+  MoveOperands* move = moves_.Get(index);
+  codegen_->MoveLocation(move->GetDestination(), move->GetSource());
+}
+
+void ParallelMoveResolverARM64::EmitSwap(size_t index) {
+  MoveOperands* move = moves_.Get(index);
+  codegen_->SwapLocations(move->GetDestination(), move->GetSource());
+}
+
+void ParallelMoveResolverARM64::RestoreScratch(int reg) {
+  __ Pop(Register(VIXLRegCodeFromART(reg), kXRegSize));
+}
+
+void ParallelMoveResolverARM64::SpillScratch(int reg) {
+  __ Push(Register(VIXLRegCodeFromART(reg), kXRegSize));
+}
+
+void CodeGeneratorARM64::GenerateFrameEntry() {
+  bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kArm64) || !IsLeafMethod();
+  if (do_overflow_check) {
+    UseScratchRegisterScope temps(GetVIXLAssembler());
+    Register temp = temps.AcquireX();
+    if (GetCompilerOptions().GetImplicitStackOverflowChecks()) {
+      __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
+      __ Ldr(wzr, MemOperand(temp, 0));
+      RecordPcInfo(nullptr, 0);
+    } else {
+      SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM64();
+      AddSlowPath(slow_path);
+
+      __ Ldr(temp, MemOperand(tr, Thread::StackEndOffset<kArm64WordSize>().Int32Value()));
+      __ Cmp(sp, temp);
+      __ B(lo, slow_path->GetEntryLabel());
+    }
+  }
+
+  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]                     : current method.
+}
+
+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::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();
+  DCHECK_NE(type, Primitive::kPrimVoid);
+
+  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(GetVIXLAssembler());
+      Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
+      __ Mov(temp, value);
+      __ Str(temp, StackOperandFrom(location));
+    }
+  } else if (instruction->IsTemporary()) {
+    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
+    MoveLocation(location, temp_location, type);
+  } else if (instruction->IsLoadLocal()) {
+    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
+    if (Is64BitType(type)) {
+      MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
+    } else {
+      MoveLocation(location, Location::StackSlot(stack_slot), type);
+    }
+
+  } else {
+    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
+    MoveLocation(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::kPrimInt:
+    case Primitive::kPrimFloat:
+      return Location::StackSlot(GetStackSlot(load->GetLocal()));
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
+      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unexpected type " << type;
+  }
+
+  LOG(FATAL) << "Unreachable";
+  return Location::NoLocation();
+}
+
+void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register card = temps.AcquireX();
+  Register temp = temps.AcquireW();   // Index within the CardTable - 32bit.
+  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.X()));
+  __ Bind(&done);
+}
+
+void CodeGeneratorARM64::SetupBlockedRegisters() const {
+  // Block reserved registers:
+  //   ip0 (VIXL temporary)
+  //   ip1 (VIXL temporary)
+  //   tr
+  //   lr
+  // sp is not part of the allocatable registers, so we don't need to block it.
+  // TODO: Avoid blocking callee-saved registers, and instead preserve them
+  // where necessary.
+  CPURegList reserved_core_registers = vixl_reserved_core_registers;
+  reserved_core_registers.Combine(runtime_reserved_core_registers);
+  reserved_core_registers.Combine(quick_callee_saved_registers);
+  while (!reserved_core_registers.IsEmpty()) {
+    blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
+  }
+  CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
+  reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
+  while (!reserved_core_registers.IsEmpty()) {
+    blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
+  }
+}
+
+Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
+  if (type == Primitive::kPrimVoid) {
+    LOG(FATAL) << "Unreachable type " << type;
+  }
+
+  if (IsFPType(type)) {
+    ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
+    DCHECK_NE(reg, -1);
+    return Location::FpuRegisterLocation(reg);
+  } else {
+    ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
+    DCHECK_NE(reg, -1);
+    return Location::RegisterLocation(reg);
+  }
+}
+
+size_t CodeGeneratorARM64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
+  Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
+  __ Str(reg, MemOperand(sp, stack_index));
+  return kArm64WordSize;
+}
+
+size_t CodeGeneratorARM64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
+  Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
+  __ Ldr(reg, MemOperand(sp, stack_index));
+  return kArm64WordSize;
+}
+
+size_t CodeGeneratorARM64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+  FPRegister reg = FPRegister(reg_id, kDRegSize);
+  __ Str(reg, MemOperand(sp, stack_index));
+  return kArm64WordSize;
+}
+
+size_t CodeGeneratorARM64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+  FPRegister reg = FPRegister(reg_id, kDRegSize);
+  __ Ldr(reg, MemOperand(sp, stack_index));
+  return kArm64WordSize;
+}
+
+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));
+}
+
+void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
+  if (constant->IsIntConstant() || constant->IsLongConstant()) {
+    __ Mov(Register(destination),
+           constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
+                                     : constant->AsLongConstant()->GetValue());
+  } else if (constant->IsFloatConstant()) {
+    __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
+  } else {
+    DCHECK(constant->IsDoubleConstant());
+    __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
+  }
+}
+
+
+static bool CoherentConstantAndType(Location constant, Primitive::Type type) {
+  DCHECK(constant.IsConstant());
+  HConstant* cst = constant.GetConstant();
+  return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
+         (cst->IsLongConstant() && type == Primitive::kPrimLong) ||
+         (cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
+         (cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
+}
+
+void CodeGeneratorARM64::MoveLocation(Location destination, Location source, Primitive::Type type) {
+  if (source.Equals(destination)) {
+    return;
+  }
+
+  // A valid move can always be inferred from the destination and source
+  // locations. When moving from and to a register, the argument type can be
+  // used to generate 32bit instead of 64bit moves. In debug mode we also
+  // checks the coherency of the locations and the type.
+  bool unspecified_type = (type == Primitive::kPrimVoid);
+
+  if (destination.IsRegister() || destination.IsFpuRegister()) {
+    if (unspecified_type) {
+      HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
+      if (source.IsStackSlot() ||
+          (src_cst != nullptr && (src_cst->IsIntConstant() || src_cst->IsFloatConstant()))) {
+        // For stack slots and 32bit constants, a 64bit type is appropriate.
+        type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
+      } else {
+        // If the source is a double stack slot or a 64bit constant, a 64bit
+        // type is appropriate. Else the source is a register, and since the
+        // type has not been specified, we chose a 64bit type to force a 64bit
+        // move.
+        type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
+      }
+    }
+    DCHECK((destination.IsFpuRegister() && IsFPType(type)) ||
+           (destination.IsRegister() && !IsFPType(type)));
+    CPURegister dst = CPURegisterFrom(destination, type);
+    if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
+      DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
+      __ Ldr(dst, StackOperandFrom(source));
+    } else if (source.IsConstant()) {
+      DCHECK(CoherentConstantAndType(source, type));
+      MoveConstant(dst, source.GetConstant());
+    } else {
+      if (destination.IsRegister()) {
+        __ Mov(Register(dst), RegisterFrom(source, type));
+      } else {
+        __ Fmov(FPRegister(dst), FPRegisterFrom(source, type));
+      }
+    }
+
+  } else {  // The destination is not a register. It must be a stack slot.
+    DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
+    if (source.IsRegister() || source.IsFpuRegister()) {
+      if (unspecified_type) {
+        if (source.IsRegister()) {
+          type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
+        } else {
+          type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
+        }
+      }
+      DCHECK((destination.IsDoubleStackSlot() == Is64BitType(type)) &&
+             (source.IsFpuRegister() == IsFPType(type)));
+      __ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
+    } else if (source.IsConstant()) {
+      DCHECK(unspecified_type || CoherentConstantAndType(source, type));
+      UseScratchRegisterScope temps(GetVIXLAssembler());
+      HConstant* src_cst = source.GetConstant();
+      CPURegister temp;
+      if (src_cst->IsIntConstant()) {
+        temp = temps.AcquireW();
+      } else if (src_cst->IsLongConstant()) {
+        temp = temps.AcquireX();
+      } else if (src_cst->IsFloatConstant()) {
+        temp = temps.AcquireS();
+      } else {
+        DCHECK(src_cst->IsDoubleConstant());
+        temp = temps.AcquireD();
+      }
+      MoveConstant(temp, src_cst);
+      __ Str(temp, StackOperandFrom(destination));
+    } else {
+      DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
+      DCHECK(source.IsDoubleStackSlot() == destination.IsDoubleStackSlot());
+      UseScratchRegisterScope temps(GetVIXLAssembler());
+      // There is generally less pressure on FP registers.
+      FPRegister temp = destination.IsDoubleStackSlot() ? temps.AcquireD() : temps.AcquireS();
+      __ Ldr(temp, StackOperandFrom(source));
+      __ Str(temp, StackOperandFrom(destination));
+    }
+  }
+}
+
+void CodeGeneratorARM64::SwapLocations(Location loc1, Location loc2) {
+  DCHECK(!loc1.IsConstant());
+  DCHECK(!loc2.IsConstant());
+
+  if (loc1.Equals(loc2)) {
+    return;
+  }
+
+  UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
+
+  bool is_slot1 = loc1.IsStackSlot() || loc1.IsDoubleStackSlot();
+  bool is_slot2 = loc2.IsStackSlot() || loc2.IsDoubleStackSlot();
+  bool is_fp_reg1 = loc1.IsFpuRegister();
+  bool is_fp_reg2 = loc2.IsFpuRegister();
+
+  if (loc2.IsRegister() && loc1.IsRegister()) {
+    Register r1 = XRegisterFrom(loc1);
+    Register r2 = XRegisterFrom(loc2);
+    Register tmp = temps.AcquireSameSizeAs(r1);
+    __ Mov(tmp, r2);
+    __ Mov(r2, r1);
+    __ Mov(r1, tmp);
+  } else if (is_fp_reg2 && is_fp_reg1) {
+    FPRegister r1 = DRegisterFrom(loc1);
+    FPRegister r2 = DRegisterFrom(loc2);
+    FPRegister tmp = temps.AcquireSameSizeAs(r1);
+    __ Fmov(tmp, r2);
+    __ Fmov(r2, r1);
+    __ Fmov(r1, tmp);
+  } else if (is_slot1 != is_slot2) {
+    MemOperand mem = StackOperandFrom(is_slot1 ? loc1 : loc2);
+    Location reg_loc = is_slot1 ? loc2 : loc1;
+    CPURegister reg, tmp;
+    if (reg_loc.IsFpuRegister()) {
+      reg = DRegisterFrom(reg_loc);
+      tmp = temps.AcquireD();
+    } else {
+      reg = XRegisterFrom(reg_loc);
+      tmp = temps.AcquireX();
+    }
+    __ Ldr(tmp, mem);
+    __ Str(reg, mem);
+    if (reg_loc.IsFpuRegister()) {
+      __ Fmov(FPRegister(reg), FPRegister(tmp));
+    } else {
+      __ Mov(Register(reg), Register(tmp));
+    }
+  } else if (is_slot1 && is_slot2) {
+    MemOperand mem1 = StackOperandFrom(loc1);
+    MemOperand mem2 = StackOperandFrom(loc2);
+    Register tmp1 = loc1.IsStackSlot() ? temps.AcquireW() : temps.AcquireX();
+    Register tmp2 = temps.AcquireSameSizeAs(tmp1);
+    __ Ldr(tmp1, mem1);
+    __ Ldr(tmp2, mem2);
+    __ Str(tmp1, mem2);
+    __ Str(tmp2, mem1);
+  } else {
+    LOG(FATAL) << "Unimplemented";
+  }
+}
+
+void CodeGeneratorARM64::Load(Primitive::Type type,
+                              CPURegister dst,
+                              const MemOperand& src) {
+  switch (type) {
+    case Primitive::kPrimBoolean:
+      __ Ldrb(Register(dst), src);
+      break;
+    case Primitive::kPrimByte:
+      __ Ldrsb(Register(dst), src);
+      break;
+    case Primitive::kPrimShort:
+      __ Ldrsh(Register(dst), src);
+      break;
+    case Primitive::kPrimChar:
+      __ Ldrh(Register(dst), src);
+      break;
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      DCHECK_EQ(dst.Is64Bits(), Is64BitType(type));
+      __ Ldr(dst, src);
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << type;
+  }
+}
+
+void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
+                                     CPURegister dst,
+                                     const MemOperand& src) {
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp_base = temps.AcquireX();
+  Primitive::Type type = instruction->GetType();
+
+  DCHECK(!src.IsRegisterOffset());
+  DCHECK(!src.IsPreIndex());
+  DCHECK(!src.IsPostIndex());
+
+  // TODO(vixl): Let the MacroAssembler handle MemOperand.
+  __ Add(temp_base, src.base(), src.offset());
+  MemOperand base = MemOperand(temp_base);
+  switch (type) {
+    case Primitive::kPrimBoolean:
+      __ Ldarb(Register(dst), base);
+      MaybeRecordImplicitNullCheck(instruction);
+      break;
+    case Primitive::kPrimByte:
+      __ Ldarb(Register(dst), base);
+      MaybeRecordImplicitNullCheck(instruction);
+      __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
+      break;
+    case Primitive::kPrimChar:
+      __ Ldarh(Register(dst), base);
+      MaybeRecordImplicitNullCheck(instruction);
+      break;
+    case Primitive::kPrimShort:
+      __ Ldarh(Register(dst), base);
+      MaybeRecordImplicitNullCheck(instruction);
+      __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
+      break;
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong:
+      DCHECK_EQ(dst.Is64Bits(), Is64BitType(type));
+      __ Ldar(Register(dst), base);
+      MaybeRecordImplicitNullCheck(instruction);
+      break;
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      DCHECK(dst.IsFPRegister());
+      DCHECK_EQ(dst.Is64Bits(), Is64BitType(type));
+
+      Register temp = dst.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
+      __ Ldar(temp, base);
+      MaybeRecordImplicitNullCheck(instruction);
+      __ Fmov(FPRegister(dst), temp);
+      break;
+    }
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << type;
+  }
+}
+
+void CodeGeneratorARM64::Store(Primitive::Type type,
+                               CPURegister src,
+                               const MemOperand& dst) {
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+      __ Strb(Register(src), dst);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      __ Strh(Register(src), dst);
+      break;
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      DCHECK_EQ(src.Is64Bits(), Is64BitType(type));
+      __ Str(src, dst);
+      break;
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << type;
+  }
+}
+
+void CodeGeneratorARM64::StoreRelease(Primitive::Type type,
+                                      CPURegister src,
+                                      const MemOperand& dst) {
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp_base = temps.AcquireX();
+
+  DCHECK(!dst.IsRegisterOffset());
+  DCHECK(!dst.IsPreIndex());
+  DCHECK(!dst.IsPostIndex());
+
+  // TODO(vixl): Let the MacroAssembler handle this.
+  __ Add(temp_base, dst.base(), dst.offset());
+  MemOperand base = MemOperand(temp_base);
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+      __ Stlrb(Register(src), base);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      __ Stlrh(Register(src), base);
+      break;
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong:
+      DCHECK_EQ(src.Is64Bits(), Is64BitType(type));
+      __ Stlr(Register(src), base);
+      break;
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      DCHECK(src.IsFPRegister());
+      DCHECK_EQ(src.Is64Bits(), Is64BitType(type));
+
+      Register temp = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
+      __ Fmov(temp, FPRegister(src));
+      __ Stlr(temp, base);
+      break;
+    }
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << type;
+  }
+}
+
+void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
+  DCHECK(current_method.IsW());
+  __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+}
+
+void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
+                                       HInstruction* instruction,
+                                       uint32_t dex_pc) {
+  __ Ldr(lr, MemOperand(tr, entry_point_offset));
+  __ Blr(lr);
+  if (instruction != nullptr) {
+    RecordPcInfo(instruction, dex_pc);
+    DCHECK(instruction->IsSuspendCheck()
+        || instruction->IsBoundsCheck()
+        || instruction->IsNullCheck()
+        || instruction->IsDivZeroCheck()
+        || !IsLeafMethod());
+    }
+}
+
+void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
+                                                                     vixl::Register class_reg) {
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp = temps.AcquireW();
+  size_t status_offset = mirror::Class::StatusOffset().SizeValue();
+
+  // Even if the initialized flag is set, we need to ensure consistent memory ordering.
+  if (kUseAcquireRelease) {
+    // TODO(vixl): Let the MacroAssembler handle MemOperand.
+    __ Add(temp, class_reg, status_offset);
+    __ Ldar(temp, HeapOperand(temp));
+    __ Cmp(temp, mirror::Class::kStatusInitialized);
+    __ B(lt, slow_path->GetEntryLabel());
+  } else {
+    __ Ldr(temp, HeapOperand(class_reg, status_offset));
+    __ Cmp(temp, mirror::Class::kStatusInitialized);
+    __ B(lt, slow_path->GetEntryLabel());
+    __ Dmb(InnerShareable, BarrierReads);
+  }
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void InstructionCodeGeneratorARM64::GenerateMemoryBarrier(MemBarrierKind kind) {
+  BarrierType type = BarrierAll;
+
+  switch (kind) {
+    case MemBarrierKind::kAnyAny:
+    case MemBarrierKind::kAnyStore: {
+      type = BarrierAll;
+      break;
+    }
+    case MemBarrierKind::kLoadAny: {
+      type = BarrierReads;
+      break;
+    }
+    case MemBarrierKind::kStoreStore: {
+      type = BarrierWrites;
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected memory barrier " << kind;
+  }
+  __ Dmb(InnerShareable, type);
+}
+
+void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
+                                                         HBasicBlock* successor) {
+  SuspendCheckSlowPathARM64* slow_path =
+    new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, successor);
+  codegen_->AddSlowPath(slow_path);
+  UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
+  Register temp = temps.AcquireW();
+
+  __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64WordSize>().SizeValue()));
+  if (successor == nullptr) {
+    __ Cbnz(temp, slow_path->GetEntryLabel());
+    __ Bind(slow_path->GetReturnLabel());
+  } else {
+    __ Cbz(temp, codegen_->GetLabelOf(successor));
+    __ B(slow_path->GetEntryLabel());
+    // slow_path will return to GetLabelOf(successor).
+  }
+}
+
+InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
+                                                             CodeGeneratorARM64* codegen)
+      : HGraphVisitor(graph),
+        assembler_(codegen->GetAssembler()),
+        codegen_(codegen) {}
+
+#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)              \
+  /* No unimplemented IR. */
+
+#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
+
+enum UnimplementedInstructionBreakCode {
+  // Using a base helps identify when we hit such breakpoints.
+  UnimplementedInstructionBreakCodeBaseCode = 0x900,
+#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) {                   \
+    UNUSED(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
+#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
+
+void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
+  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(), Location::kNoOutputOverlap);
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
+  Primitive::Type type = instr->GetType();
+
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      Register dst = OutputRegister(instr);
+      Register lhs = InputRegisterAt(instr, 0);
+      Operand rhs = InputOperandAt(instr, 1);
+      if (instr->IsAdd()) {
+        __ Add(dst, lhs, rhs);
+      } else if (instr->IsAnd()) {
+        __ And(dst, lhs, rhs);
+      } else if (instr->IsOr()) {
+        __ Orr(dst, lhs, rhs);
+      } else if (instr->IsSub()) {
+        __ Sub(dst, lhs, rhs);
+      } else {
+        DCHECK(instr->IsXor());
+        __ Eor(dst, lhs, rhs);
+      }
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      FPRegister dst = OutputFPRegister(instr);
+      FPRegister lhs = InputFPRegisterAt(instr, 0);
+      FPRegister rhs = InputFPRegisterAt(instr, 1);
+      if (instr->IsAdd()) {
+        __ Fadd(dst, lhs, rhs);
+      } else if (instr->IsSub()) {
+        __ Fsub(dst, lhs, rhs);
+      } else {
+        LOG(FATAL) << "Unexpected floating-point binary operation";
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected binary operation type " << type;
+  }
+}
+
+void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
+  DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
+
+  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;
+    }
+    default:
+      LOG(FATAL) << "Unexpected shift type " << type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
+  DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
+
+  Primitive::Type type = instr->GetType();
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      Register dst = OutputRegister(instr);
+      Register lhs = InputRegisterAt(instr, 0);
+      Operand rhs = InputOperandAt(instr, 1);
+      if (rhs.IsImmediate()) {
+        uint32_t shift_value = (type == Primitive::kPrimInt)
+          ? static_cast<uint32_t>(rhs.immediate() & kMaxIntShiftValue)
+          : static_cast<uint32_t>(rhs.immediate() & kMaxLongShiftValue);
+        if (instr->IsShl()) {
+          __ Lsl(dst, lhs, shift_value);
+        } else if (instr->IsShr()) {
+          __ Asr(dst, lhs, shift_value);
+        } else {
+          __ Lsr(dst, lhs, shift_value);
+        }
+      } else {
+        Register rhs_reg = dst.IsX() ? rhs.reg().X() : rhs.reg().W();
+
+        if (instr->IsShl()) {
+          __ Lsl(dst, lhs, rhs_reg);
+        } else if (instr->IsShr()) {
+          __ Asr(dst, lhs, rhs_reg);
+        } else {
+          __ Lsr(dst, lhs, rhs_reg);
+        }
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected shift operation type " << type;
+  }
+}
+
+void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void LocationsBuilderARM64::VisitArrayGet(HArrayGet* 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::VisitArrayGet(HArrayGet* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Primitive::Type type = instruction->GetType();
+  Register obj = InputRegisterAt(instruction, 0);
+  Location index = locations->InAt(1);
+  size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
+  MemOperand source = HeapOperand(obj);
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+
+  if (index.IsConstant()) {
+    offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+    source = HeapOperand(obj, offset);
+  } else {
+    Register temp = temps.AcquireSameSizeAs(obj);
+    Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
+    __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
+    source = HeapOperand(temp, offset);
+  }
+
+  codegen_->Load(type, OutputCPURegister(instruction), source);
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
+}
+
+void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
+  __ Ldr(OutputRegister(instruction),
+         HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
+}
+
+void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
+  Primitive::Type value_type = instruction->GetComponentType();
+  bool is_object = value_type == Primitive::kPrimNot;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+      instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
+  if (is_object) {
+    InvokeRuntimeCallingConvention calling_convention;
+    locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+    locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
+    locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
+  } else {
+    locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+    locations->SetInAt(2, Location::RequiresRegister());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
+  Primitive::Type value_type = instruction->GetComponentType();
+  if (value_type == Primitive::kPrimNot) {
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+    CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
+  } else {
+    LocationSummary* locations = instruction->GetLocations();
+    Register obj = InputRegisterAt(instruction, 0);
+    CPURegister value = InputCPURegisterAt(instruction, 2);
+    Location index = locations->InAt(1);
+    size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
+    MemOperand destination = HeapOperand(obj);
+    UseScratchRegisterScope temps(GetVIXLAssembler());
+
+    if (index.IsConstant()) {
+      offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
+      destination = HeapOperand(obj, offset);
+    } else {
+      Register temp = temps.AcquireSameSizeAs(obj);
+      Register index_reg = InputRegisterAt(instruction, 1);
+      __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
+      destination = HeapOperand(temp, offset);
+    }
+
+    codegen_->Store(value_type, value, destination);
+    codegen_->MaybeRecordImplicitNullCheck(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::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+      instruction, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = InputRegisterAt(instruction, 0);;
+  Register cls = InputRegisterAt(instruction, 1);;
+  Register obj_cls = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
+
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
+      instruction, locations->InAt(1), LocationFrom(obj_cls), instruction->GetDexPc());
+  codegen_->AddSlowPath(slow_path);
+
+  // TODO: avoid this check if we know obj is not null.
+  __ Cbz(obj, slow_path->GetExitLabel());
+  // Compare the class of `obj` with `cls`.
+  __ Ldr(obj_cls, HeapOperand(obj, mirror::Object::ClassOffset()));
+  __ Cmp(obj_cls, cls);
+  __ B(ne, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (check->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
+  // We assume the class is not null.
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
+      check->GetLoadClass(), check, check->GetDexPc(), true);
+  codegen_->AddSlowPath(slow_path);
+  GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
+}
+
+void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
+  Primitive::Type in_type = compare->InputAt(0)->GetType();
+  switch (in_type) {
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
+      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::RequiresRegister());
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected type for compare operation " << in_type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
+  Primitive::Type in_type = compare->InputAt(0)->GetType();
+
+  //  0 if: left == right
+  //  1 if: left  > right
+  // -1 if: left  < right
+  switch (in_type) {
+    case Primitive::kPrimLong: {
+      Register result = OutputRegister(compare);
+      Register left = InputRegisterAt(compare, 0);
+      Operand right = InputOperandAt(compare, 1);
+
+      __ Cmp(left, right);
+      __ Cset(result, ne);
+      __ Cneg(result, result, lt);
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      Register result = OutputRegister(compare);
+      FPRegister left = InputFPRegisterAt(compare, 0);
+      FPRegister right = InputFPRegisterAt(compare, 1);
+
+      __ Fcmp(left, right);
+      if (compare->IsGtBias()) {
+        __ Cset(result, ne);
+      } else {
+        __ Csetm(result, ne);
+      }
+      __ Cneg(result, result, compare->IsGtBias() ? mi : gt);
+      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(), Location::kNoOutputOverlap);
+  }
+}
+
+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);
+  __ Cset(res, 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 DEFINE_CONDITION_VISITORS
+#undef FOR_EACH_CONDITION_INSTRUCTION
+
+void LocationsBuilderARM64::VisitDiv(HDiv* div) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
+  switch (div->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(), Location::kNoOutputOverlap);
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
+  Primitive::Type type = div->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected div type " << type;
+  }
+}
+
+void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  SlowPathCodeARM64* slow_path =
+      new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
+  codegen_->AddSlowPath(slow_path);
+  Location value = instruction->GetLocations()->InAt(0);
+
+  Primitive::Type type = instruction->GetType();
+
+  if ((type != Primitive::kPrimInt) && (type != Primitive::kPrimLong)) {
+      LOG(FATAL) << "Unexpected type " << type << "for DivZeroCheck.";
+    return;
+  }
+
+  if (value.IsConstant()) {
+    int64_t divisor = Int64ConstantFrom(value);
+    if (divisor == 0) {
+      __ B(slow_path->GetEntryLabel());
+    } else {
+      // A division by a non-null constant is valid. We don't need to perform
+      // any check, so simply fall through.
+    }
+  } else {
+    __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
+  }
+}
+
+void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
+  UNUSED(constant);
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM64::VisitExit(HExit* exit) {
+  exit->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
+  UNUSED(exit);
+  if (kIsDebugBuild) {
+    down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
+    __ Brk(__LINE__);    // TODO: Introduce special markers for such code locations.
+  }
+}
+
+void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
+  UNUSED(constant);
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM64::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
+  HBasicBlock* successor = got->GetSuccessor();
+  DCHECK(!successor->IsExitBlock());
+  HBasicBlock* block = got->GetBlock();
+  HInstruction* previous = got->GetPrevious();
+  HLoopInformation* info = block->GetLoopInformation();
+
+  if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
+    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
+    GenerateSuspendCheck(info->GetSuspendCheck(), successor);
+    return;
+  }
+  if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
+    GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
+  }
+  if (!codegen_->GoesToNextBlock(block, 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);
+  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
+    locations->SetInAt(0, Location::RequiresRegister());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
+  HInstruction* cond = if_instr->InputAt(0);
+  HCondition* condition = cond->AsCondition();
+  vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
+  vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+
+  if (cond->IsIntConstant()) {
+    int32_t cond_value = cond->AsIntConstant()->GetValue();
+    if (cond_value == 1) {
+      if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
+        __ B(true_target);
+      }
+      return;
+    } else {
+      DCHECK_EQ(cond_value, 0);
+    }
+  } else if (!cond->IsCondition() || 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 arm64_cond = ARM64Condition(condition->GetCondition());
+    if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
+      if (arm64_cond == eq) {
+        __ Cbz(lhs, true_target);
+      } else {
+        __ Cbnz(lhs, true_target);
+      }
+    } else {
+      __ Cmp(lhs, rhs);
+      __ B(arm64_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, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
+
+  if (instruction->IsVolatile()) {
+    if (kUseAcquireRelease) {
+      // NB: LoadAcquire will record the pc info if needed.
+      codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
+    } else {
+      codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+      // For IRIW sequential consistency kLoadAny is not sufficient.
+      GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+    }
+  } else {
+    codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+}
+
+void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  Register obj = InputRegisterAt(instruction, 0);
+  CPURegister value = InputCPURegisterAt(instruction, 1);
+  Offset offset = instruction->GetFieldOffset();
+  Primitive::Type field_type = instruction->GetFieldType();
+
+  if (instruction->IsVolatile()) {
+    if (kUseAcquireRelease) {
+      codegen_->StoreRelease(field_type, value, HeapOperand(obj, offset));
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+    } else {
+      GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+      codegen_->Store(field_type, value, HeapOperand(obj, offset));
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+      GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+    }
+  } else {
+    codegen_->Store(field_type, value, HeapOperand(obj, offset));
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    codegen_->MarkGCCard(obj, Register(value));
+  }
+}
+
+void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary::CallKind call_kind =
+      instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  // The output does overlap inputs.
+  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = InputRegisterAt(instruction, 0);;
+  Register cls = InputRegisterAt(instruction, 1);;
+  Register out = OutputRegister(instruction);
+
+  vixl::Label done;
+
+  // Return 0 if `obj` is null.
+  // TODO: Avoid this check if we know `obj` is not null.
+  __ Mov(out, 0);
+  __ Cbz(obj, &done);
+
+  // Compare the class of `obj` with `cls`.
+  __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
+  __ Cmp(out, cls);
+  if (instruction->IsClassFinal()) {
+    // Classes must be equal for the instanceof to succeed.
+    __ Cset(out, eq);
+  } else {
+    // If the classes are not equal, we go into a slow path.
+    DCHECK(locations->OnlyCallsOnSlowPath());
+    SlowPathCodeARM64* slow_path =
+        new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
+        instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
+    codegen_->AddSlowPath(slow_path);
+    __ B(ne, slow_path->GetEntryLabel());
+    __ Mov(out, 1);
+    __ Bind(slow_path->GetExitLabel());
+  }
+
+  __ Bind(&done);
+}
+
+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.
+  UNUSED(constant);
+}
+
+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 LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
+  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
+  Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
+  uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+          (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+  Location receiver = invoke->GetLocations()->InAt(0);
+  Offset class_offset = mirror::Object::ClassOffset();
+  Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
+
+  // The register ip1 is required to be used for the hidden argument in
+  // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
+  UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
+  scratch_scope.Exclude(ip1);
+  __ Mov(ip1, invoke->GetDexMethodIndex());
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ Ldr(temp, StackOperandFrom(receiver));
+    __ Ldr(temp, HeapOperand(temp, class_offset));
+  } else {
+    __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
+  }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
+  // temp = temp->GetImtEntryAt(method_offset);
+  __ Ldr(temp, HeapOperand(temp, method_offset));
+  // lr = temp->GetEntryPoint();
+  __ Ldr(lr, HeapOperand(temp, entry_point));
+  // lr();
+  __ Blr(lr);
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* 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->GetDexMethodIndex() * 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;
+  codegen_->LoadCurrentMethod(temp);
+  // temp = temp->dex_cache_resolved_methods_;
+  __ Ldr(temp, HeapOperand(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset()));
+  // temp = temp[index_in_cache];
+  __ Ldr(temp, HeapOperand(temp, index_in_cache));
+  // lr = temp->entry_point_from_quick_compiled_code_;
+  __ Ldr(lr, HeapOperand(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+                          kArm64WordSize)));
+  // 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 = WRegisterFrom(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(kArm64WordSize);
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ Ldr(temp, MemOperand(sp, receiver.GetStackIndex()));
+    __ Ldr(temp, HeapOperand(temp, class_offset));
+  } else {
+    DCHECK(receiver.IsRegister());
+    __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
+  }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
+  // temp = temp->GetMethodAt(method_offset);
+  __ Ldr(temp, HeapOperand(temp, method_offset));
+  // lr = temp->GetEntryPoint();
+  __ Ldr(lr, HeapOperand(temp, entry_point.SizeValue()));
+  // lr();
+  __ Blr(lr);
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
+  LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
+                                                              : LocationSummary::kNoCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
+  Register out = OutputRegister(cls);
+  if (cls->IsReferrersClass()) {
+    DCHECK(!cls->CanCallRuntime());
+    DCHECK(!cls->MustGenerateClinitCheck());
+    codegen_->LoadCurrentMethod(out);
+    __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
+  } else {
+    DCHECK(cls->CanCallRuntime());
+    codegen_->LoadCurrentMethod(out);
+    __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
+    __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+
+    SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+    codegen_->AddSlowPath(slow_path);
+    __ Cbz(out, slow_path->GetEntryLabel());
+    if (cls->MustGenerateClinitCheck()) {
+      GenerateClassInitializationCheck(slow_path, out);
+    } else {
+      __ Bind(slow_path->GetExitLabel());
+    }
+  }
+}
+
+void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
+  MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
+  __ Ldr(OutputRegister(instruction), exception);
+  __ Str(wzr, exception);
+}
+
+void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
+  load->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
+  // Nothing to do, this is driven by the code generator.
+  UNUSED(load);
+}
+
+void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
+  codegen_->AddSlowPath(slow_path);
+
+  Register out = OutputRegister(load);
+  codegen_->LoadCurrentMethod(out);
+  __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
+  __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
+  __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  __ Cbz(out, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+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.
+  UNUSED(constant);
+}
+
+void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
+  codegen_->InvokeRuntime(instruction->IsEnter()
+        ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
+      instruction,
+      instruction->GetDexPc());
+  CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
+}
+
+void LocationsBuilderARM64::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(), Location::kNoOutputOverlap);
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void LocationsBuilderARM64::VisitNewArray(HNewArray* 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(2)));
+  locations->SetOut(LocationFrom(x0));
+  locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(1)));
+  CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
+                       void*, uint32_t, int32_t, mirror::ArtMethod*>();
+}
+
+void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  InvokeRuntimeCallingConvention calling_convention;
+  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(w2));
+  codegen_->LoadCurrentMethod(current_method);
+  __ Mov(type_index, instruction->GetTypeIndex());
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
+  CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
+                       void*, uint32_t, int32_t, mirror::ArtMethod*>();
+}
+
+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));
+  CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*>();
+}
+
+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));
+  codegen_->LoadCurrentMethod(current_method);
+  __ Mov(type_index, instruction->GetTypeIndex());
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
+  CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*>();
+}
+
+void LocationsBuilderARM64::VisitNot(HNot* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
+  switch (instruction->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
+      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::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+    return;
+  }
+  Location obj = instruction->GetLocations()->InAt(0);
+
+  __ Ldr(wzr, HeapOperandFrom(obj, Offset(0)));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void InstructionCodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
+  codegen_->AddSlowPath(slow_path);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location obj = locations->InAt(0);
+
+  __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
+}
+
+void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
+  if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+    GenerateImplicitNullCheck(instruction);
+  } else {
+    GenerateExplicitNullCheck(instruction);
+  }
+}
+
+void LocationsBuilderARM64::VisitOr(HOr* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void LocationsBuilderARM64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "Unreachable";
+}
+
+void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
+  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
+}
+
+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.
+  UNUSED(instruction);
+}
+
+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) {
+  UNUSED(instruction);
+  LOG(FATAL) << "Unreachable";
+}
+
+void LocationsBuilderARM64::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+  LocationSummary::CallKind call_kind = IsFPType(type) ? LocationSummary::kCall
+                                                       : LocationSummary::kNoCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
+
+  switch (type) {
+    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: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
+      locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
+      locations->SetOut(calling_convention.GetReturnLocation(type));
+
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      UseScratchRegisterScope temps(GetVIXLAssembler());
+      Register dividend = InputRegisterAt(rem, 0);
+      Register divisor = InputRegisterAt(rem, 1);
+      Register output = OutputRegister(rem);
+      Register temp = temps.AcquireSameSizeAs(output);
+
+      __ Sdiv(temp, dividend, divisor);
+      __ Msub(output, temp, divisor, dividend);
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      int32_t entry_offset = (type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pFmodf)
+                                                             : QUICK_ENTRY_POINT(pFmod);
+      codegen_->InvokeRuntime(entry_offset, rem, rem->GetDexPc());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  Primitive::Type return_type = instruction->InputAt(0)->GetType();
+  locations->SetInAt(0, ARM64ReturnLocation(return_type));
+}
+
+void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
+  UNUSED(instruction);
+  codegen_->GenerateFrameExit();
+  __ Ret();
+}
+
+void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
+  instruction->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
+  UNUSED(instruction);
+  codegen_->GenerateFrameExit();
+  __ Ret();
+}
+
+void LocationsBuilderARM64::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void LocationsBuilderARM64::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+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::kPrimNot:
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented local type " << field_type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
+  UNUSED(store);
+}
+
+void LocationsBuilderARM64::VisitSub(HSub* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
+
+  if (instruction->IsVolatile()) {
+    if (kUseAcquireRelease) {
+      // NB: LoadAcquire will record the pc info if needed.
+      codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
+    } else {
+      codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
+      // For IRIW sequential consistency kLoadAny is not sufficient.
+      GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+    }
+  } else {
+    codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
+  }
+}
+
+void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  Register cls = InputRegisterAt(instruction, 0);
+  CPURegister value = InputCPURegisterAt(instruction, 1);
+  Offset offset = instruction->GetFieldOffset();
+  Primitive::Type field_type = instruction->GetFieldType();
+
+  if (instruction->IsVolatile()) {
+    if (kUseAcquireRelease) {
+      codegen_->StoreRelease(field_type, value, HeapOperand(cls, offset));
+    } else {
+      GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+      codegen_->Store(field_type, value, HeapOperand(cls, offset));
+      GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+    }
+  } else {
+    codegen_->Store(field_type, value, HeapOperand(cls, offset));
+  }
+
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    codegen_->MarkGCCard(cls, Register(value));
+  }
+}
+
+void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
+  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
+}
+
+void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
+  HBasicBlock* block = instruction->GetBlock();
+  if (block->GetLoopInformation() != nullptr) {
+    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
+    // The back edge will generate the suspend check.
+    return;
+  }
+  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
+    // The goto will generate the suspend check.
+    return;
+  }
+  GenerateSuspendCheck(instruction, nullptr);
+}
+
+void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
+  temp->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
+  // Nothing to do, this is driven by the code generator.
+  UNUSED(temp);
+}
+
+void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
+  codegen_->InvokeRuntime(
+      QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
+  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
+}
+
+void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+  Primitive::Type input_type = conversion->GetInputType();
+  Primitive::Type result_type = conversion->GetResultType();
+  DCHECK_NE(input_type, result_type);
+  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
+      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
+    LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
+  }
+
+  if (IsFPType(input_type)) {
+    locations->SetInAt(0, Location::RequiresFpuRegister());
+  } else {
+    locations->SetInAt(0, Location::RequiresRegister());
+  }
+
+  if (IsFPType(result_type)) {
+    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+  } else {
+    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+
+  DCHECK_NE(input_type, result_type);
+
+  if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
+    int result_size = Primitive::ComponentSize(result_type);
+    int input_size = Primitive::ComponentSize(input_type);
+    int min_size = std::min(result_size, input_size);
+    Register output = OutputRegister(conversion);
+    Register source = InputRegisterAt(conversion, 0);
+    if ((result_type == Primitive::kPrimChar) && (input_size < result_size)) {
+      __ Ubfx(output, source, 0, result_size * kBitsPerByte);
+    } else if ((result_type == Primitive::kPrimChar) ||
+               ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
+      __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
+    } else {
+      __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
+    }
+  } else if (IsFPType(result_type) && IsIntegralType(input_type)) {
+    __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
+  } else if (IsIntegralType(result_type) && IsFPType(input_type)) {
+    CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
+    __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
+  } else if (IsFPType(result_type) && IsFPType(input_type)) {
+    __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
+  } else {
+    LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
+                << " to " << result_type;
+  }
+}
+
+void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
+void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
+void LocationsBuilderARM64::VisitXor(HXor* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
+  HandleBinaryOp(instruction);
+}
+
+#undef __
+#undef QUICK_ENTRY_POINT
+
+}  // 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..27c6fbd
--- /dev/null
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -0,0 +1,301 @@
+/*
+ * 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 "dex/compiler_enums.h"
+#include "driver/compiler_options.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;
+class SlowPathCodeARM64;
+
+// Use a local definition to prevent copying mistakes.
+static constexpr size_t kArm64WordSize = kArm64PointerSize;
+
+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::CPURegList vixl_reserved_core_registers(vixl::ip0, vixl::ip1);
+const vixl::CPURegList vixl_reserved_fp_registers(vixl::d31);
+const vixl::CPURegList runtime_reserved_core_registers(tr, vixl::lr);
+const vixl::CPURegList quick_callee_saved_registers(vixl::CPURegister::kRegister,
+                                                    vixl::kXRegSize,
+                                                    kArm64CalleeSaveRefSpills);
+
+Location ARM64ReturnLocation(Primitive::Type return_type);
+
+class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> {
+ public:
+  InvokeDexCallingConvention()
+      : CallingConvention(kParameterCoreRegisters,
+                          kParameterCoreRegistersLength,
+                          kParameterFPRegisters,
+                          kParameterFPRegistersLength) {}
+
+  Location GetReturnLocation(Primitive::Type return_type) {
+    return ARM64ReturnLocation(return_type);
+  }
+
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
+};
+
+class InvokeDexCallingConventionVisitor {
+ public:
+  InvokeDexCallingConventionVisitor() : gp_index_(0), fp_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 index for floating-point registers.
+  uint32_t fp_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) \
+  void Visit##name(H##name* instr) OVERRIDE;
+  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+#undef DECLARE_VISIT_INSTRUCTION
+
+  void LoadCurrentMethod(XRegister reg);
+
+  Arm64Assembler* GetAssembler() const { return assembler_; }
+  vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
+
+ private:
+  void GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, vixl::Register class_reg);
+  void GenerateMemoryBarrier(MemBarrierKind kind);
+  void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
+  void HandleBinaryOp(HBinaryOperation* instr);
+  void HandleShift(HBinaryOperation* instr);
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
+
+  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) \
+  void Visit##name(H##name* instr) OVERRIDE;
+  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+  void HandleBinaryOp(HBinaryOperation* instr);
+  void HandleShift(HBinaryOperation* instr);
+  void HandleInvoke(HInvoke* instr);
+
+  CodeGeneratorARM64* const codegen_;
+  InvokeDexCallingConventionVisitor parameter_visitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM64);
+};
+
+class ParallelMoveResolverARM64 : public ParallelMoveResolver {
+ public:
+  ParallelMoveResolverARM64(ArenaAllocator* allocator, CodeGeneratorARM64* codegen)
+      : ParallelMoveResolver(allocator), codegen_(codegen) {}
+
+  void EmitMove(size_t index) OVERRIDE;
+  void EmitSwap(size_t index) OVERRIDE;
+  void RestoreScratch(int reg) OVERRIDE;
+  void SpillScratch(int reg) OVERRIDE;
+
+ private:
+  Arm64Assembler* GetAssembler() const;
+  vixl::MacroAssembler* GetVIXLAssembler() const {
+    return GetAssembler()->vixl_masm_;
+  }
+
+  CodeGeneratorARM64* const codegen_;
+
+  DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM64);
+};
+
+class CodeGeneratorARM64 : public CodeGenerator {
+ public:
+  CodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options);
+  virtual ~CodeGeneratorARM64() {}
+
+  void GenerateFrameEntry() OVERRIDE;
+  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();
+  }
+
+  void Bind(HBasicBlock* block) OVERRIDE;
+
+  vixl::Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_ + block->GetBlockId();
+  }
+
+  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+
+  size_t GetWordSize() const OVERRIDE {
+    return kArm64WordSize;
+  }
+
+  size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
+    // Allocated in D registers, which are word sized.
+    return kArm64WordSize;
+  }
+
+  uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+    vixl::Label* block_entry_label = GetLabelOf(block);
+    DCHECK(block_entry_label->IsBound());
+    return block_entry_label->location();
+  }
+
+  size_t FrameEntrySpillSize() const OVERRIDE;
+
+  HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
+  HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
+  Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+  vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
+
+  // Emit a write barrier.
+  void MarkGCCard(vixl::Register object, vixl::Register value);
+
+  // Register allocation.
+
+  void SetupBlockedRegisters() const OVERRIDE;
+  // AllocateFreeRegister() is only used when allocating registers locally
+  // during CompileBaseline().
+  Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+
+  Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+
+  // 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 kNumberOfAllocatableRegisters = vixl::kNumberOfRegisters - 1;
+  static const int kNumberOfAllocatableFPRegisters = vixl::kNumberOfFPRegisters;
+  static constexpr int kNumberOfAllocatableRegisterPairs = 0;
+
+  void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+  void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return InstructionSet::kArm64;
+  }
+
+  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();
+    }
+  }
+
+  void Finalize(CodeAllocator* allocator) OVERRIDE;
+
+  // Code generation helpers.
+  void MoveConstant(vixl::CPURegister destination, HConstant* constant);
+  // The type is optional. When specified it must be coherent with the
+  // locations, and is used for optimisation and debugging.
+  void MoveLocation(Location destination, Location source,
+                    Primitive::Type type = Primitive::kPrimVoid);
+  void SwapLocations(Location loc_1, Location loc_2);
+  void Load(Primitive::Type type, vixl::CPURegister dst, const vixl::MemOperand& src);
+  void Store(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
+  void LoadCurrentMethod(vixl::Register current_method);
+  void LoadAcquire(HInstruction* instruction, vixl::CPURegister dst, const vixl::MemOperand& src);
+  void StoreRelease(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
+
+  // Generate code to invoke a runtime entry point.
+  void InvokeRuntime(int32_t offset, HInstruction* instruction, uint32_t dex_pc);
+
+  ParallelMoveResolverARM64* GetMoveResolver() { return &move_resolver_; }
+
+  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+    return false;
+  }
+
+ private:
+  // Labels for each block that will be compiled.
+  vixl::Label* block_labels_;
+
+  LocationsBuilderARM64 location_builder_;
+  InstructionCodeGeneratorARM64 instruction_visitor_;
+  ParallelMoveResolverARM64 move_resolver_;
+  Arm64Assembler assembler_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64);
+};
+
+inline Arm64Assembler* ParallelMoveResolverARM64::GetAssembler() const {
+  return codegen_->GetAssembler();
+}
+
+}  // 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 ea67dfd..2d30412 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -18,7 +18,7 @@
 
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
-#include "mirror/array.h"
+#include "mirror/array-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/class.h"
 #include "thread.h"
@@ -29,30 +29,29 @@
 
 namespace art {
 
-x86::X86ManagedRegister Location::AsX86() const {
-  return reg().AsX86();
-}
-
 namespace x86 {
 
-static constexpr bool kExplicitStackOverflowCheck = false;
-
 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
 static constexpr int kCurrentMethodStackOffset = 0;
 
-static Location X86CpuLocation(Register reg) {
-  return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
-}
-
-static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
+static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX };
 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     arraysize(kRuntimeParameterCoreRegisters);
+static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { };
+static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
 
-class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
+static constexpr int kC2ConditionMask = 0x400;
+
+// Marker for places that can be updated once we don't follow the quick ABI.
+static constexpr bool kFollowsQuickABI = true;
+
+class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
  public:
   InvokeRuntimeCallingConvention()
       : CallingConvention(kRuntimeParameterCoreRegisters,
-                          kRuntimeParameterCoreRegistersLength) {}
+                          kRuntimeParameterCoreRegistersLength,
+                          kRuntimeParameterFpuRegisters,
+                          kRuntimeParameterFpuRegistersLength) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
@@ -60,7 +59,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) {}
 
@@ -75,7 +88,42 @@
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
 };
 
-class StackOverflowCheckSlowPathX86 : public SlowPathCode {
+class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
+ public:
+  explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+  }
+
+ private:
+  HDivZeroCheck* const instruction_;
+  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
+};
+
+class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
+ public:
+  explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    if (is_div_) {
+      __ negl(reg_);
+    } else {
+      __ movl(reg_, Immediate(0));
+    }
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  Register reg_;
+  bool is_div_;
+  DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
+};
+
+class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
   StackOverflowCheckSlowPathX86() {}
 
@@ -90,19 +138,26 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86);
 };
 
-class BoundsCheckSlowPathX86 : public SlowPathCode {
+class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
   BoundsCheckSlowPathX86(HBoundsCheck* instruction,
                          Location index_location,
                          Location length_location)
-      : instruction_(instruction), index_location_(index_location), length_location_(length_location) {}
+      : 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());
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
     InvokeRuntimeCallingConvention calling_convention;
-    x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
-    x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
+    x86_codegen->EmitParallelMoves(
+        index_location_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+        length_location_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
     codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
   }
@@ -115,12 +170,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)));
@@ -129,7 +185,7 @@
     if (successor_ == nullptr) {
       __ jmp(GetReturnLabel());
     } else {
-      __ jmp(codegen->GetLabelOf(successor_));
+      __ jmp(x86_codegen->GetLabelOf(successor_));
     }
   }
 
@@ -146,6 +202,142 @@
   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
 };
 
+class LoadStringSlowPathX86 : public SlowPathCodeX86 {
+ public:
+  explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+    CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+    __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
+    __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
+    codegen->RestoreLiveRegisters(locations);
+
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  HLoadString* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
+};
+
+class LoadClassSlowPathX86 : public SlowPathCodeX86 {
+ public:
+  LoadClassSlowPathX86(HLoadClass* cls,
+                       HInstruction* at,
+                       uint32_t dex_pc,
+                       bool do_clinit)
+      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
+  }
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = at_->GetLocations();
+    CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
+    x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+    __ fs()->call(Address::Absolute(do_clinit_
+        ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
+        : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
+    codegen->RecordPcInfo(at_, dex_pc_);
+
+    // Move the class to the desired location.
+    Location out = locations->Out();
+    if (out.IsValid()) {
+      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+      x86_codegen->Move32(out, Location::RegisterLocation(EAX));
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  // The class this slow path will load.
+  HLoadClass* const cls_;
+
+  // The instruction where this slow path is happening.
+  // (Might be the load class or an initialization check).
+  HInstruction* const at_;
+
+  // The dex PC of `at_`.
+  const uint32_t dex_pc_;
+
+  // Whether to initialize the class.
+  const bool do_clinit_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
+};
+
+class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
+ public:
+  TypeCheckSlowPathX86(HInstruction* instruction,
+                       Location class_to_check,
+                       Location object_class,
+                       uint32_t dex_pc)
+      : instruction_(instruction),
+        class_to_check_(class_to_check),
+        object_class_(object_class),
+        dex_pc_(dex_pc) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(instruction_->IsCheckCast()
+           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+    CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
+    InvokeRuntimeCallingConvention calling_convention;
+    x86_codegen->EmitParallelMoves(
+        class_to_check_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+        object_class_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+
+    if (instruction_->IsInstanceOf()) {
+      __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
+                                                              pInstanceofNonTrivial)));
+    } else {
+      DCHECK(instruction_->IsCheckCast());
+      __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
+    }
+
+    codegen->RecordPcInfo(instruction_, dex_pc_);
+    if (instruction_->IsInstanceOf()) {
+      x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
+    }
+    codegen->RestoreLiveRegisters(locations);
+
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  HInstruction* const instruction_;
+  const Location class_to_check_;
+  const Location object_class_;
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
+};
+
 #undef __
 #define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
 
@@ -171,16 +363,20 @@
   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, kNumberOfRegIds),
+CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
+    : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfXmmRegisters,
+                    kNumberOfRegisterPairs, compiler_options),
+      block_labels_(graph->GetArena(), 0),
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this) {}
@@ -189,32 +385,18 @@
   return kNumberOfPushedRegistersAtEntry * kX86WordSize;
 }
 
-static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
-  return blocked_registers + kNumberOfAllocIds;
-}
-
-ManagedRegister CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type,
-                                                       bool* blocked_registers) const {
+Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
   switch (type) {
     case Primitive::kPrimLong: {
-      bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
-      size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
+      size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
       X86ManagedRegister pair =
           X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
-      blocked_registers[pair.AsRegisterPairLow()] = true;
-      blocked_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;
-        }
-      }
-      return pair;
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
+      blocked_core_registers_[pair.AsRegisterPairLow()] = true;
+      blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
+      UpdateBlockedPairRegisters();
+      return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
     }
 
     case Primitive::kPrimByte:
@@ -224,51 +406,56 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
       Register reg = static_cast<Register>(
-          AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters));
+          FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
       // Block all register pairs that contain `reg`.
-      bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
       for (int i = 0; i < kNumberOfRegisterPairs; i++) {
         X86ManagedRegister current =
             X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
         if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
-          blocked_register_pairs[i] = true;
+          blocked_register_pairs_[i] = true;
         }
       }
-      return X86ManagedRegister::FromCpuRegister(reg);
+      return Location::RegisterLocation(reg);
     }
 
     case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << type;
+    case Primitive::kPrimDouble: {
+      return Location::FpuRegisterLocation(
+          FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 
-  return ManagedRegister::NoRegister();
+  return Location();
 }
 
-void CodeGeneratorX86::SetupBlockedRegisters(bool* blocked_registers) const {
-  bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
-
+void CodeGeneratorX86::SetupBlockedRegisters() const {
   // Don't allocate the dalvik style register pair passing.
-  blocked_register_pairs[ECX_EDX] = true;
+  blocked_register_pairs_[ECX_EDX] = true;
 
   // Stack register is always reserved.
-  blocked_registers[ESP] = true;
+  blocked_core_registers_[ESP] = true;
 
   // TODO: We currently don't use Quick's callee saved registers.
-  blocked_registers[EBP] = true;
-  blocked_registers[ESI] = true;
-  blocked_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;
+  DCHECK(kFollowsQuickABI);
+  blocked_core_registers_[EBP] = true;
+  blocked_core_registers_[ESI] = true;
+  blocked_core_registers_[EDI] = true;
+
+  UpdateBlockedPairRegisters();
 }
 
-size_t CodeGeneratorX86::GetNumberOfRegisters() const {
-  return kNumberOfRegIds;
+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)
@@ -281,8 +468,11 @@
   static const int kFakeReturnRegister = 8;
   core_spill_mask_ |= (1 << kFakeReturnRegister);
 
-  bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
-  if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
+  bool skip_overflow_check =
+      IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
+  bool implicitStackOverflowChecks = GetCompilerOptions().GetImplicitStackOverflowChecks();
+
+  if (!skip_overflow_check && implicitStackOverflowChecks) {
     __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
     RecordPcInfo(nullptr, 0);
   }
@@ -290,8 +480,8 @@
   // The return PC has already been pushed on the stack.
   __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
 
-  if (!skip_overflow_check && kExplicitStackOverflowCheck) {
-    SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
+  if (!skip_overflow_check && !implicitStackOverflowChecks) {
+    SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
     AddSlowPath(slow_path);
 
     __ fs()->cmpl(ESP, Address::Absolute(Thread::StackEndOffset<kX86WordSize>()));
@@ -305,27 +495,25 @@
   __ 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) {
+void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
   __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
 }
 
 Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
   switch (load->GetType()) {
     case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
       break;
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
-      return Location::StackSlot(GetStackSlot(load->GetLocal()));
-
     case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented type " << load->GetType();
+      return Location::StackSlot(GetStackSlot(load->GetLocal()));
 
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
@@ -346,33 +534,33 @@
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
     case Primitive::kPrimNot: {
       uint32_t index = gp_index_++;
       if (index < calling_convention.GetNumberOfRegisters()) {
-        return X86CpuLocation(calling_convention.GetRegisterAt(index));
+        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
       } else {
         return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
       }
     }
 
-    case Primitive::kPrimLong: {
+    case Primitive::kPrimLong:
+    case Primitive::kPrimDouble: {
       uint32_t index = gp_index_;
       gp_index_ += 2;
       if (index + 1 < calling_convention.GetNumberOfRegisters()) {
-        return Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
-            calling_convention.GetRegisterPairAt(index)));
+        X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
+            calling_convention.GetRegisterPairAt(index));
+        return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
       } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
-        return Location::QuickParameter(index);
+        // On X86, the register index and stack index of a quick parameter is the same, since
+        // we are passing floating pointer values in core registers.
+        return Location::QuickParameter(index, index);
       } else {
         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
       }
     }
 
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
-      LOG(FATAL) << "Unimplemented parameter type " << type;
-      break;
-
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
       break;
@@ -386,14 +574,28 @@
   }
   if (destination.IsRegister()) {
     if (source.IsRegister()) {
-      __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
+      __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
+    } else if (source.IsFpuRegister()) {
+      __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
     } else {
       DCHECK(source.IsStackSlot());
-      __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
+      __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
+    }
+  } else if (destination.IsFpuRegister()) {
+    if (source.IsRegister()) {
+      __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
+    } else if (source.IsFpuRegister()) {
+      __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
+    } else {
+      DCHECK(source.IsStackSlot());
+      __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
     }
   } else {
+    DCHECK(destination.IsStackSlot()) << destination;
     if (source.IsRegister()) {
-      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
+      __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
+    } else if (source.IsFpuRegister()) {
+      __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
     } else {
       DCHECK(source.IsStackSlot());
       __ pushl(Address(ESP, source.GetStackIndex()));
@@ -406,79 +608,129 @@
   if (source.Equals(destination)) {
     return;
   }
-  if (destination.IsRegister()) {
-    if (source.IsRegister()) {
-      __ movl(destination.AsX86().AsRegisterPairLow(), source.AsX86().AsRegisterPairLow());
-      __ movl(destination.AsX86().AsRegisterPairHigh(), source.AsX86().AsRegisterPairHigh());
+  if (destination.IsRegisterPair()) {
+    if (source.IsRegisterPair()) {
+      EmitParallelMoves(
+          Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
+          Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
+          Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
+          Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
+    } else if (source.IsFpuRegister()) {
+      LOG(FATAL) << "Unimplemented";
     } else if (source.IsQuickParameter()) {
-      uint32_t argument_index = source.GetQuickParameterIndex();
+      uint16_t register_index = source.GetQuickParameterRegisterIndex();
+      uint16_t stack_index = source.GetQuickParameterStackIndex();
       InvokeDexCallingConvention calling_convention;
-      __ movl(destination.AsX86().AsRegisterPairLow(),
-              calling_convention.GetRegisterAt(argument_index));
-      __ movl(destination.AsX86().AsRegisterPairHigh(), Address(ESP,
-          calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
+      EmitParallelMoves(
+          Location::RegisterLocation(calling_convention.GetRegisterAt(register_index)),
+          Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
+          Location::StackSlot(
+              calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize()),
+          Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()));
     } else {
+      // No conflict possible, so just do the moves.
       DCHECK(source.IsDoubleStackSlot());
-      __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex()));
-      __ movl(destination.AsX86().AsRegisterPairHigh(),
+      __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
+      __ movl(destination.AsRegisterPairHigh<Register>(),
               Address(ESP, source.GetHighStackIndex(kX86WordSize)));
     }
   } else if (destination.IsQuickParameter()) {
     InvokeDexCallingConvention calling_convention;
-    uint32_t argument_index = destination.GetQuickParameterIndex();
-    if (source.IsRegister()) {
-      __ movl(calling_convention.GetRegisterAt(argument_index), source.AsX86().AsRegisterPairLow());
-      __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)),
-              source.AsX86().AsRegisterPairHigh());
+    uint16_t register_index = destination.GetQuickParameterRegisterIndex();
+    uint16_t stack_index = destination.GetQuickParameterStackIndex();
+    if (source.IsRegisterPair()) {
+      LOG(FATAL) << "Unimplemented";
+    } else if (source.IsFpuRegister()) {
+      LOG(FATAL) << "Unimplemented";
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ movl(calling_convention.GetRegisterAt(argument_index),
-              Address(ESP, source.GetStackIndex()));
-      __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
-      __ popl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)));
+      EmitParallelMoves(
+          Location::StackSlot(source.GetStackIndex()),
+          Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index)),
+          Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
+          Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index + 1)));
+      __ movl(calling_convention.GetRegisterAt(register_index), Address(ESP, source.GetStackIndex()));
+    }
+  } else if (destination.IsFpuRegister()) {
+    if (source.IsDoubleStackSlot()) {
+      __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
+    } else {
+      LOG(FATAL) << "Unimplemented";
     }
   } else {
-    DCHECK(destination.IsDoubleStackSlot());
-    if (source.IsRegister()) {
-      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow());
+    DCHECK(destination.IsDoubleStackSlot()) << destination;
+    if (source.IsRegisterPair()) {
+      // No conflict possible, so just do the moves.
+      __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
       __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
-              source.AsX86().AsRegisterPairHigh());
+              source.AsRegisterPairHigh<Register>());
     } else if (source.IsQuickParameter()) {
+      // No conflict possible, so just do the move.
       InvokeDexCallingConvention calling_convention;
-      uint32_t argument_index = source.GetQuickParameterIndex();
+      uint16_t register_index = source.GetQuickParameterRegisterIndex();
+      uint16_t stack_index = source.GetQuickParameterStackIndex();
+      // Just move the low part. The only time a source is a quick parameter is
+      // when moving the parameter to its stack locations. And the (Java) caller
+      // of this method has already done that.
       __ movl(Address(ESP, destination.GetStackIndex()),
-              calling_convention.GetRegisterAt(argument_index));
-      __ pushl(Address(ESP,
-          calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
-      __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
+              calling_convention.GetRegisterAt(register_index));
+      DCHECK_EQ(calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize(),
+                static_cast<size_t>(destination.GetHighStackIndex(kX86WordSize)));
+    } else if (source.IsFpuRegister()) {
+      __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ pushl(Address(ESP, source.GetStackIndex()));
-      __ popl(Address(ESP, destination.GetStackIndex()));
-      __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
-      __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
+      EmitParallelMoves(
+          Location::StackSlot(source.GetStackIndex()),
+          Location::StackSlot(destination.GetStackIndex()),
+          Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
+          Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)));
     }
   }
 }
 
 void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
-  if (instruction->AsIntConstant() != nullptr) {
-    Immediate imm(instruction->AsIntConstant()->GetValue());
-    if (location.IsRegister()) {
-      __ movl(location.AsX86().AsCpuRegister(), imm);
-    } else {
-      __ movl(Address(ESP, location.GetStackIndex()), imm);
+  LocationSummary* locations = instruction->GetLocations();
+  if (locations != nullptr && locations->Out().Equals(location)) {
+    return;
+  }
+
+  if (locations != nullptr && locations->Out().IsConstant()) {
+    HConstant* const_to_move = locations->Out().GetConstant();
+    if (const_to_move->IsIntConstant()) {
+      Immediate imm(const_to_move->AsIntConstant()->GetValue());
+      if (location.IsRegister()) {
+        __ movl(location.AsRegister<Register>(), imm);
+      } else if (location.IsStackSlot()) {
+        __ movl(Address(ESP, location.GetStackIndex()), imm);
+      } else {
+        DCHECK(location.IsConstant());
+        DCHECK_EQ(location.GetConstant(), const_to_move);
+      }
+    } else if (const_to_move->IsLongConstant()) {
+      int64_t value = const_to_move->AsLongConstant()->GetValue();
+      if (location.IsRegisterPair()) {
+        __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
+        __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
+      } 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->AsLongConstant() != nullptr) {
-    int64_t value = instruction->AsLongConstant()->GetValue();
-    if (location.IsRegister()) {
-      __ movl(location.AsX86().AsRegisterPairLow(), Immediate(Low32Bits(value)));
-      __ movl(location.AsX86().AsRegisterPairHigh(), Immediate(High32Bits(value)));
+  } else if (instruction->IsTemporary()) {
+    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
+    if (temp_location.IsStackSlot()) {
+      Move32(location, temp_location);
     } else {
-      __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
-      __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
+      DCHECK(temp_location.IsDoubleStackSlot());
+      Move64(location, temp_location);
     }
-  } else if (instruction->AsLoadLocal() != nullptr) {
+  } else if (instruction->IsLoadLocal()) {
+    int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
     switch (instruction->GetType()) {
       case Primitive::kPrimBoolean:
       case Primitive::kPrimByte:
@@ -486,12 +738,13 @@
       case Primitive::kPrimShort:
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
-        Move32(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
+      case Primitive::kPrimFloat:
+        Move32(location, Location::StackSlot(slot));
         break;
 
       case Primitive::kPrimLong:
-        Move64(location, Location::DoubleStackSlot(
-            GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
+      case Primitive::kPrimDouble:
+        Move64(location, Location::DoubleStackSlot(slot));
         break;
 
       default:
@@ -506,15 +759,17 @@
       case Primitive::kPrimShort:
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
-        Move32(location, instruction->GetLocations()->Out());
+      case Primitive::kPrimFloat:
+        Move32(location, locations->Out());
         break;
 
       case Primitive::kPrimLong:
-        Move64(location, instruction->GetLocations()->Out());
+      case Primitive::kPrimDouble:
+        Move64(location, locations->Out());
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+        LOG(FATAL) << "Unexpected type " << instruction->GetType();
     }
   }
 }
@@ -550,6 +805,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
+  UNUSED(exit);
   if (kIsDebugBuild) {
     __ Comment("Unreachable");
     __ int3();
@@ -560,47 +816,67 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
   HInstruction* cond = if_instr->InputAt(0);
-  DCHECK(cond->IsCondition());
-  HCondition* condition = cond->AsCondition();
-  if (condition->NeedsMaterialization()) {
+  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
     locations->SetInAt(0, Location::Any());
   }
 }
 
 void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
   HInstruction* cond = if_instr->InputAt(0);
-  DCHECK(cond->IsCondition());
-  HCondition* condition = cond->AsCondition();
-  if (condition->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.
-    if (!condition->IsBeforeWhenDisregardMoves(if_instr)) {
-      // Materialized condition, compare against 0
-      Location lhs = if_instr->GetLocations()->InAt(0);
-      if (lhs.IsRegister()) {
-        __ cmpl(lhs.AsX86().AsCpuRegister(), 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()));
-  } else {
-    Location lhs = condition->GetLocations()->InAt(0);
-    Location rhs = condition->GetLocations()->InAt(1);
-    // LHS is guaranteed to be in a register (see LocationsBuilderX86::VisitCondition).
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.AsX86().AsCpuRegister(), rhs.AsX86().AsCpuRegister());
-    } else if (rhs.IsConstant()) {
-      HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
-      Immediate imm(instruction->AsIntConstant()->GetValue());
-      __ cmpl(lhs.AsX86().AsCpuRegister(), imm);
+      return;
     } else {
-      __ cmpl(lhs.AsX86().AsCpuRegister(), Address(ESP, rhs.GetStackIndex()));
+      DCHECK_EQ(cond_value, 0);
     }
-    __ j(X86Condition(condition->GetCondition()),
-         codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+  } 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.AsRegister<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.AsRegister<Register>(), rhs.AsRegister<Register>());
+      } else if (rhs.IsConstant()) {
+        HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
+        Immediate imm(instruction->AsIntConstant()->GetValue());
+        __ cmpl(lhs.AsRegister<Register>(), imm);
+      } else {
+        __ cmpl(lhs.AsRegister<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()));
   }
 }
@@ -619,6 +895,7 @@
 
 void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
   // Nothing to do, this is driven by the code generator.
+  UNUSED(load);
 }
 
 void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
@@ -631,20 +908,23 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
+    case Primitive::kPrimFloat:
       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
       break;
 
     case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
       break;
 
     default:
-      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
+      LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
   }
   store->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
+  UNUSED(store);
 }
 
 void LocationsBuilderX86::VisitCondition(HCondition* comp) {
@@ -660,18 +940,18 @@
 void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
   if (comp->NeedsMaterialization()) {
     LocationSummary* locations = comp->GetLocations();
-    Register reg = locations->Out().AsX86().AsCpuRegister();
+    Register reg = locations->Out().AsRegister<Register>();
     // Clear register: setcc only sets the low byte.
     __ xorl(reg, reg);
     if (locations->InAt(1).IsRegister()) {
-      __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
-              locations->InAt(1).AsX86().AsCpuRegister());
+      __ cmpl(locations->InAt(0).AsRegister<Register>(),
+              locations->InAt(1).AsRegister<Register>());
     } else if (locations->InAt(1).IsConstant()) {
       HConstant* instruction = locations->InAt(1).GetConstant();
       Immediate imm(instruction->AsIntConstant()->GetValue());
-      __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(), imm);
+      __ cmpl(locations->InAt(0).AsRegister<Register>(), imm);
     } else {
-      __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
+      __ cmpl(locations->InAt(0).AsRegister<Register>(),
               Address(ESP, locations->InAt(1).GetStackIndex()));
     }
     __ setb(X86Condition(comp->GetCondition()), reg);
@@ -733,6 +1013,8 @@
 }
 
 void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
+  UNUSED(constant);
 }
 
 void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
@@ -743,6 +1025,29 @@
 
 void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
   // Will be generated at use site.
+  UNUSED(constant);
+}
+
+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.
+  UNUSED(constant);
+}
+
+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.
+  UNUSED(constant);
 }
 
 void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
@@ -750,6 +1055,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
+  UNUSED(ret);
   codegen_->GenerateFrameExit();
   __ ret();
 }
@@ -764,16 +1070,22 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
-      locations->SetInAt(0, X86CpuLocation(EAX));
+      locations->SetInAt(0, Location::RegisterLocation(EAX));
       break;
 
     case Primitive::kPrimLong:
       locations->SetInAt(
-          0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+          0, Location::RegisterPairLocation(EAX, EDX));
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(
+          0, Location::FpuRegisterLocation(XMM0));
       break;
 
     default:
-      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+      LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
   }
 }
 
@@ -786,30 +1098,33 @@
       case Primitive::kPrimShort:
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
-        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsCpuRegister(), EAX);
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
         break;
 
       case Primitive::kPrimLong:
-        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsRegisterPair(), EAX_EDX);
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
+        break;
+
+      case Primitive::kPrimFloat:
+      case Primitive::kPrimDouble:
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+        LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
     }
   }
   codegen_->GenerateFrameExit();
   __ ret();
 }
 
-void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
+void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
   HandleInvoke(invoke);
 }
 
-void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
-  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
-  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
-      invoke->GetIndexInDexCache() * kX86WordSize;
+void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
+  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
 
   // TODO: Implement all kinds of calls:
   // 1) boot -> boot
@@ -819,13 +1134,14 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   // temp = method;
-  LoadCurrentMethod(temp);
+  codegen_->LoadCurrentMethod(temp);
   // temp = temp->dex_cache_resolved_methods_;
   __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
   // temp = temp[index_in_cache]
-  __ movl(temp, Address(temp, index_in_cache));
+  __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
   // (temp + offset_of_quick_compiled_code)()
-  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
+  __ call(Address(
+      temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
 
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
@@ -838,7 +1154,7 @@
 void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(X86CpuLocation(EAX));
+  locations->AddTemp(Location::RegisterLocation(EAX));
 
   InvokeDexCallingConventionVisitor calling_convention_visitor;
   for (size_t i = 0; i < invoke->InputCount(); i++) {
@@ -853,11 +1169,11 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
-      locations->SetOut(X86CpuLocation(EAX));
+      locations->SetOut(Location::RegisterLocation(EAX));
       break;
 
     case Primitive::kPrimLong:
-      locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
+      locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
       break;
 
     case Primitive::kPrimVoid:
@@ -865,7 +1181,7 @@
 
     case Primitive::kPrimDouble:
     case Primitive::kPrimFloat:
-      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
+      locations->SetOut(Location::FpuRegisterLocation(XMM0));
       break;
   }
 
@@ -873,7 +1189,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
+  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
   uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
           invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
   LocationSummary* locations = invoke->GetLocations();
@@ -884,17 +1200,628 @@
     __ movl(temp, Address(ESP, receiver.GetStackIndex()));
     __ movl(temp, Address(temp, class_offset));
   } else {
-    __ movl(temp, Address(receiver.AsX86().AsCpuRegister(), class_offset));
+    __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
   }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
   // temp = temp->GetMethodAt(method_offset);
   __ movl(temp, Address(temp, method_offset));
   // call temp->GetEntryPoint();
-  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
+  __ call(Address(
+      temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
 
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
+  HandleInvoke(invoke);
+  // Add the hidden argument.
+  invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM0));
+}
+
+void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
+  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
+  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
+  uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+          (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+
+  // Set the hidden argument.
+  __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
+  __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ movl(temp, Address(ESP, receiver.GetStackIndex()));
+    __ movl(temp, Address(temp, class_offset));
+  } else {
+    __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
+  }
+    codegen_->MaybeRecordImplicitNullCheck(invoke);
+  // temp = temp->GetImtEntryAt(method_offset);
+  __ movl(temp, Address(temp, method_offset));
+  // call temp->GetEntryPoint();
+  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kX86WordSize).Int32Value()));
+
+  DCHECK(!codegen_->IsLeafMethod());
+  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:
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+
+    case Primitive::kPrimFloat:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresFpuRegister());
+      break;
+
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      locations->AddTemp(Location::RequiresFpuRegister());
+      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());
+      DCHECK(in.Equals(out));
+      __ negl(out.AsRegister<Register>());
+      break;
+
+    case Primitive::kPrimLong:
+      DCHECK(in.IsRegisterPair());
+      DCHECK(in.Equals(out));
+      __ negl(out.AsRegisterPairLow<Register>());
+      // Negation is similar to subtraction from zero.  The least
+      // significant byte triggers a borrow when it is different from
+      // zero; to take it into account, add 1 to the most significant
+      // byte if the carry flag (CF) is set to 1 after the first NEGL
+      // operation.
+      __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
+      __ negl(out.AsRegisterPairHigh<Register>());
+      break;
+
+    case Primitive::kPrimFloat: {
+      DCHECK(in.Equals(out));
+      Register constant = locations->GetTemp(0).AsRegister<Register>();
+      XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+      // Implement float negation with an exclusive or with value
+      // 0x80000000 (mask for bit 31, representing the sign of a
+      // single-precision floating-point number).
+      __ movl(constant, Immediate(INT32_C(0x80000000)));
+      __ movd(mask, constant);
+      __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      DCHECK(in.Equals(out));
+      XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+      // Implement double negation with an exclusive or with value
+      // 0x8000000000000000 (mask for bit 63, representing the sign of
+      // a double-precision floating-point number).
+      __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
+      __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  DCHECK_NE(result_type, input_type);
+
+  // The float-to-long and double-to-long type conversions rely on a
+  // call to the runtime.
+  LocationSummary::CallKind call_kind =
+      ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
+       && result_type == Primitive::kPrimLong)
+      ? LocationSummary::kCall
+      : LocationSummary::kNoCall;
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
+
+  switch (result_type) {
+    case Primitive::kPrimByte:
+      switch (input_type) {
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-byte' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimShort:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-short' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-int' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-int' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-int' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-long' instruction.
+          locations->SetInAt(0, Location::RegisterLocation(EAX));
+          locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+          break;
+
+        case Primitive::kPrimFloat: {
+          // Processing a Dex `float-to-long' instruction.
+          InvokeRuntimeCallingConvention calling_convention;
+          // Note that on x86 floating-point parameters are passed
+          // through core registers (here, EAX).
+          locations->SetInAt(0, Location::RegisterLocation(
+              calling_convention.GetRegisterAt(0)));
+          // The runtime helper puts the result in EAX, EDX.
+          locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+          break;
+        }
+
+        case Primitive::kPrimDouble: {
+          // Processing a Dex `double-to-long' instruction.
+          InvokeRuntimeCallingConvention calling_convention;
+          // Note that on x86 floating-point parameters are passed
+          // through core registers (here, EAX and ECX).
+          locations->SetInAt(0, Location::RegisterPairLocation(
+              calling_convention.GetRegisterAt(0),
+              calling_convention.GetRegisterAt(1)));
+          // The runtime helper puts the result in EAX, EDX.
+          locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+          break;
+        }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimChar:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // Processing a Dex `int-to-char' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    case Primitive::kPrimDouble:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations = conversion->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  DCHECK_NE(result_type, input_type);
+  switch (result_type) {
+    case Primitive::kPrimByte:
+      switch (input_type) {
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-byte' instruction.
+          if (in.IsRegister()) {
+            __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
+          } else if (in.IsStackSlot()) {
+            __ movsxb(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsIntConstant());
+            int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
+          }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimShort:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-short' instruction.
+          if (in.IsRegister()) {
+            __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
+          } else if (in.IsStackSlot()) {
+            __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsIntConstant());
+            int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
+          }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-int' instruction.
+          if (in.IsRegisterPair()) {
+            __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.IsConstant());
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
+          }
+          break;
+
+        case Primitive::kPrimFloat: {
+          // Processing a Dex `float-to-int' instruction.
+          XmmRegister input = in.AsFpuRegister<XmmRegister>();
+          Register output = out.AsRegister<Register>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          Label done, nan;
+
+          __ movl(output, Immediate(kPrimIntMax));
+          // temp = int-to-float(output)
+          __ cvtsi2ss(temp, output);
+          // if input >= temp goto done
+          __ comiss(input, temp);
+          __ j(kAboveEqual, &done);
+          // if input == NaN goto nan
+          __ j(kUnordered, &nan);
+          // output = float-to-int-truncate(input)
+          __ cvttss2si(output, input);
+          __ jmp(&done);
+          __ Bind(&nan);
+          //  output = 0
+          __ xorl(output, output);
+          __ Bind(&done);
+          break;
+        }
+
+        case Primitive::kPrimDouble: {
+          // Processing a Dex `double-to-int' instruction.
+          XmmRegister input = in.AsFpuRegister<XmmRegister>();
+          Register output = out.AsRegister<Register>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          Label done, nan;
+
+          __ movl(output, Immediate(kPrimIntMax));
+          // temp = int-to-double(output)
+          __ cvtsi2sd(temp, output);
+          // if input >= temp goto done
+          __ comisd(input, temp);
+          __ j(kAboveEqual, &done);
+          // if input == NaN goto nan
+          __ j(kUnordered, &nan);
+          // output = double-to-int-truncate(input)
+          __ cvttsd2si(output, input);
+          __ jmp(&done);
+          __ Bind(&nan);
+          //  output = 0
+          __ xorl(output, output);
+          __ Bind(&done);
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-long' instruction.
+          DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
+          DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
+          DCHECK_EQ(in.AsRegister<Register>(), EAX);
+          __ cdq();
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-long' instruction.
+          __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
+          codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-long' instruction.
+          __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
+          codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimChar:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // Processing a Dex `Process a Dex `int-to-char'' instruction.
+          if (in.IsRegister()) {
+            __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
+          } else if (in.IsStackSlot()) {
+            __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsIntConstant());
+            int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
+          }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-float' instruction.
+          __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
+          break;
+
+        case Primitive::kPrimLong: {
+          // Processing a Dex `long-to-float' instruction.
+          Register low = in.AsRegisterPairLow<Register>();
+          Register high = in.AsRegisterPairHigh<Register>();
+          XmmRegister result = out.AsFpuRegister<XmmRegister>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+
+          // Operations use doubles for precision reasons (each 32-bit
+          // half of a long fits in the 53-bit mantissa of a double,
+          // but not in the 24-bit mantissa of a float).  This is
+          // especially important for the low bits.  The result is
+          // eventually converted to float.
+
+          // low = low - 2^31 (to prevent bit 31 of `low` to be
+          // interpreted as a sign bit)
+          __ subl(low, Immediate(0x80000000));
+          // temp = int-to-double(high)
+          __ cvtsi2sd(temp, high);
+          // temp = temp * 2^32
+          __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
+          __ mulsd(temp, constant);
+          // result = int-to-double(low)
+          __ cvtsi2sd(result, low);
+          // result = result + 2^31 (restore the original value of `low`)
+          __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
+          __ addsd(result, constant);
+          // result = result + temp
+          __ addsd(result, temp);
+          // result = double-to-float(result)
+          __ cvtsd2ss(result, result);
+          break;
+        }
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-float' instruction.
+          __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    case Primitive::kPrimDouble:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-double' instruction.
+          __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
+          break;
+
+        case Primitive::kPrimLong: {
+          // Processing a Dex `long-to-double' instruction.
+          Register low = in.AsRegisterPairLow<Register>();
+          Register high = in.AsRegisterPairHigh<Register>();
+          XmmRegister result = out.AsFpuRegister<XmmRegister>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+
+          // low = low - 2^31 (to prevent bit 31 of `low` to be
+          // interpreted as a sign bit)
+          __ subl(low, Immediate(0x80000000));
+          // temp = int-to-double(high)
+          __ cvtsi2sd(temp, high);
+          // temp = temp * 2^32
+          __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
+          __ mulsd(temp, constant);
+          // result = int-to-double(low)
+          __ cvtsi2sd(result, low);
+          // result = result + 2^31 (restore the original value of `low`)
+          __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
+          __ addsd(result, constant);
+          // result = result + temp
+          __ addsd(result, temp);
+          break;
+        }
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-double' instruction.
+          __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
 void LocationsBuilderX86::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -907,64 +1834,70 @@
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
+      locations->SetOut(Location::SameAsFirstInput());
       break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+      break;
   }
 }
 
 void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
   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(locations->InAt(0).AsX86().AsCpuRegister(),
-                locations->Out().AsX86().AsCpuRegister());
-      if (locations->InAt(1).IsRegister()) {
-        __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
-                locations->InAt(1).AsX86().AsCpuRegister());
-      } else if (locations->InAt(1).IsConstant()) {
-        HConstant* instruction = locations->InAt(1).GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ addl(locations->InAt(0).AsX86().AsCpuRegister(), imm);
+      if (second.IsRegister()) {
+        __ addl(first.AsRegister<Register>(), second.AsRegister<Register>());
+      } else if (second.IsConstant()) {
+        __ addl(first.AsRegister<Register>(),
+                Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
       } else {
-        __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
-                Address(ESP, locations->InAt(1).GetStackIndex()));
+        __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
 
     case Primitive::kPrimLong: {
-      DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
-                locations->Out().AsX86().AsRegisterPair());
-      if (locations->InAt(1).IsRegister()) {
-        __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
-                locations->InAt(1).AsX86().AsRegisterPairLow());
-        __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
-                locations->InAt(1).AsX86().AsRegisterPairHigh());
+      if (second.IsRegisterPair()) {
+        __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
       } else {
-        __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
-                Address(ESP, locations->InAt(1).GetStackIndex()));
-        __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
-                Address(ESP, locations->InAt(1).GetHighStackIndex(kX86WordSize)));
+        __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ adcl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
       }
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+    case Primitive::kPrimFloat: {
+      if (second.IsFpuRegister()) {
+        __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else {
+        __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      if (second.IsFpuRegister()) {
+        __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else {
+        __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   }
 }
 
@@ -979,80 +1912,644 @@
       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::VisitSub(HSub* sub) {
   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(locations->InAt(0).AsX86().AsCpuRegister(),
-                locations->Out().AsX86().AsCpuRegister());
-      if (locations->InAt(1).IsRegister()) {
-        __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
-                locations->InAt(1).AsX86().AsCpuRegister());
-      } else if (locations->InAt(1).IsConstant()) {
-        HConstant* instruction = locations->InAt(1).GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ subl(locations->InAt(0).AsX86().AsCpuRegister(), imm);
+      if (second.IsRegister()) {
+        __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
+      } else if (second.IsConstant()) {
+        __ subl(first.AsRegister<Register>(),
+                Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
       } else {
-        __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
-                Address(ESP, locations->InAt(1).GetStackIndex()));
+        __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
 
     case Primitive::kPrimLong: {
-      DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
-                locations->Out().AsX86().AsRegisterPair());
-      if (locations->InAt(1).IsRegister()) {
-        __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
-                locations->InAt(1).AsX86().AsRegisterPairLow());
-        __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
-                locations->InAt(1).AsX86().AsRegisterPairHigh());
+      if (second.IsRegisterPair()) {
+        __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
       } else {
-        __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
-                Address(ESP, locations->InAt(1).GetStackIndex()));
-        __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
-                Address(ESP, locations->InAt(1).GetHighStackIndex(kX86WordSize)));
+        __ 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.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<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.AsRegister<Register>(), second.AsRegister<Register>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ imull(first.AsRegister<Register>(), imm);
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ imull(first.AsRegister<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).AsRegister<Register>();
+      Register edx = locations->GetTemp(1).AsRegister<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.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, uint32_t temp_offset,
+                                                  uint32_t stack_adjustment, bool is_float) {
+  if (source.IsStackSlot()) {
+    DCHECK(is_float);
+    __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
+  } else if (source.IsDoubleStackSlot()) {
+    DCHECK(!is_float);
+    __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
+  } else {
+    // Write the value to the temporary location on the stack and load to FP stack.
+    if (is_float) {
+      Location stack_temp = Location::StackSlot(temp_offset);
+      codegen_->Move32(stack_temp, source);
+      __ flds(Address(ESP, temp_offset));
+    } else {
+      Location stack_temp = Location::DoubleStackSlot(temp_offset);
+      codegen_->Move64(stack_temp, source);
+      __ fldl(Address(ESP, temp_offset));
+    }
+  }
+}
+
+void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
+  Primitive::Type type = rem->GetResultType();
+  bool is_float = type == Primitive::kPrimFloat;
+  size_t elem_size = Primitive::ComponentSize(type);
+  LocationSummary* locations = rem->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  Location out = locations->Out();
+
+  // Create stack space for 2 elements.
+  // TODO: enhance register allocator to ask for stack temporaries.
+  __ subl(ESP, Immediate(2 * elem_size));
+
+  // Load the values to the FP stack in reverse order, using temporaries if needed.
+  PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
+  PushOntoFPStack(first, 0, 2 * elem_size, is_float);
+
+  // Loop doing FPREM until we stabilize.
+  Label retry;
+  __ Bind(&retry);
+  __ fprem();
+
+  // Move FP status to AX.
+  __ fstsw();
+
+  // And see if the argument reduction is complete. This is signaled by the
+  // C2 FPU flag bit set to 0.
+  __ andl(EAX, Immediate(kC2ConditionMask));
+  __ j(kNotEqual, &retry);
+
+  // We have settled on the final value. Retrieve it into an XMM register.
+  // Store FP top of stack to real stack.
+  if (is_float) {
+    __ fsts(Address(ESP, 0));
+  } else {
+    __ fstl(Address(ESP, 0));
+  }
+
+  // Pop the 2 items from the FP stack.
+  __ fucompp();
+
+  // Load the value from the stack into an XMM register.
+  DCHECK(out.IsFpuRegister()) << out;
+  if (is_float) {
+    __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
+  } else {
+    __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
+  }
+
+  // And remove the temporary stack space we allocated.
+  __ addl(ESP, Immediate(2 * elem_size));
+}
+
+void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  bool is_div = instruction->IsDiv();
+
+  switch (instruction->GetResultType()) {
+    case Primitive::kPrimInt: {
+      Register second_reg = second.AsRegister<Register>();
+      DCHECK_EQ(EAX, first.AsRegister<Register>());
+      DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
+
+      SlowPathCodeX86* slow_path =
+          new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
+                                                                 is_div);
+      codegen_->AddSlowPath(slow_path);
+
+      // 0x80000000/-1 triggers an arithmetic exception!
+      // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
+      // it's safe to just use negl instead of more complex comparisons.
+
+      __ cmpl(second_reg, Immediate(-1));
+      __ j(kEqual, slow_path->GetEntryLabel());
+
+      // edx:eax <- sign-extended of eax
+      __ cdq();
+      // eax = quotient, edx = remainder
+      __ idivl(second_reg);
+
+      __ Bind(slow_path->GetExitLabel());
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
+      DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
+      DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
+      DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
+
+      if (is_div) {
+        __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
+      } else {
+        __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
+      }
+      uint32_t dex_pc = is_div
+          ? instruction->AsDiv()->GetDexPc()
+          : instruction->AsRem()->GetDexPc();
+      codegen_->RecordPcInfo(instruction, dex_pc);
+
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
+  }
+}
+
+void LocationsBuilderX86::VisitDiv(HDiv* div) {
+  LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong
+      ? LocationSummary::kCall
+      : LocationSummary::kNoCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
+
+  switch (div->GetResultType()) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RegisterLocation(EAX));
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      // Intel uses edx:eax as the dividend.
+      locations->AddTemp(Location::RegisterLocation(EDX));
+      break;
+    }
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+      locations->SetInAt(1, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
+      // Runtime helper puts the result in EAX, EDX.
+      locations->SetOut(Location::RegisterPairLocation(EAX, 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 div type " << div->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
+  LocationSummary* locations = div->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+
+  switch (div->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      GenerateDivRemIntegral(div);
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      DCHECK(first.Equals(out));
+      __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      DCHECK(first.Equals(out));
+      __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
+  }
+}
+
+void LocationsBuilderX86::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+  LocationSummary* locations =
+    new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
+
+  switch (type) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RegisterLocation(EAX));
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RegisterLocation(EDX));
+      break;
+    }
+    case Primitive::kPrimLong: {
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+      locations->SetInAt(1, Location::RegisterPairLocation(
+          calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
+      // Runtime helper puts the result in EAX, EDX.
+      locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+      break;
+    }
+    case Primitive::kPrimDouble:
+    case Primitive::kPrimFloat: {
+      locations->SetInAt(0, Location::Any());
+      locations->SetInAt(1, Location::Any());
+      locations->SetOut(Location::RequiresFpuRegister());
+      locations->AddTemp(Location::RegisterLocation(EAX));
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      GenerateDivRemIntegral(rem);
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      GenerateRemFP(rem);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  switch (instruction->GetType()) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::Any());
+      break;
+    }
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
+      if (!instruction->IsConstant()) {
+        locations->AddTemp(Location::RequiresRegister());
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
+  }
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
+  codegen_->AddSlowPath(slow_path);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location value = locations->InAt(0);
+
+  switch (instruction->GetType()) {
+    case Primitive::kPrimInt: {
+      if (value.IsRegister()) {
+        __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else if (value.IsStackSlot()) {
+        __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else {
+        DCHECK(value.IsConstant()) << value;
+        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+        __ jmp(slow_path->GetEntryLabel());
+        }
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      if (value.IsRegisterPair()) {
+        Register temp = locations->GetTemp(0).AsRegister<Register>();
+        __ movl(temp, value.AsRegisterPairLow<Register>());
+        __ orl(temp, value.AsRegisterPairHigh<Register>());
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else {
+        DCHECK(value.IsConstant()) << value;
+        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
+          __ jmp(slow_path->GetEntryLabel());
+        }
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
+  }
+}
+
+void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
+  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
+
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
+
+  switch (op->GetResultType()) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      // The shift count needs to be in CL.
+      locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      // The shift count needs to be in CL.
+      locations->SetInAt(1, Location::RegisterLocation(ECX));
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected op type " << op->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
+  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
+
+  LocationSummary* locations = op->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  switch (op->GetResultType()) {
+    case Primitive::kPrimInt: {
+      Register first_reg = first.AsRegister<Register>();
+      if (second.IsRegister()) {
+        Register second_reg = second.AsRegister<Register>();
+        DCHECK_EQ(ECX, second_reg);
+        if (op->IsShl()) {
+          __ shll(first_reg, second_reg);
+        } else if (op->IsShr()) {
+          __ sarl(first_reg, second_reg);
+        } else {
+          __ shrl(first_reg, second_reg);
+        }
+      } else {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
+        if (op->IsShl()) {
+          __ shll(first_reg, imm);
+        } else if (op->IsShr()) {
+          __ sarl(first_reg, imm);
+        } else {
+          __ shrl(first_reg, imm);
+        }
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      Register second_reg = second.AsRegister<Register>();
+      DCHECK_EQ(ECX, second_reg);
+      if (op->IsShl()) {
+        GenerateShlLong(first, second_reg);
+      } else if (op->IsShr()) {
+        GenerateShrLong(first, second_reg);
+      } else {
+        GenerateUShrLong(first, second_reg);
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected op type " << op->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
+  Label done;
+  __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
+  __ shll(loc.AsRegisterPairLow<Register>(), shifter);
+  __ testl(shifter, Immediate(32));
+  __ j(kEqual, &done);
+  __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
+  __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
+  __ Bind(&done);
+}
+
+void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
+  Label done;
+  __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
+  __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
+  __ testl(shifter, Immediate(32));
+  __ j(kEqual, &done);
+  __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
+  __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
+  __ Bind(&done);
+}
+
+void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
+  Label done;
+  __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
+  __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
+  __ testl(shifter, Immediate(32));
+  __ j(kEqual, &done);
+  __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
+  __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
+  __ Bind(&done);
+}
+
+void LocationsBuilderX86::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void LocationsBuilderX86::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
+void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
 void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
-  locations->SetOut(X86CpuLocation(EAX));
+  locations->SetOut(Location::RegisterLocation(EAX));
   InvokeRuntimeCallingConvention calling_convention;
-  locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(1)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
 }
 
 void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
   __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
 
   __ fs()->call(
@@ -1062,6 +2559,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(2)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+}
+
+void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
+  __ 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);
@@ -1075,72 +2594,112 @@
 }
 
 void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
+  UNUSED(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();
+  Location in = locations->InAt(0);
   Location out = locations->Out();
-  DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), out.AsX86().AsCpuRegister());
-  __ xorl(out.AsX86().AsCpuRegister(), Immediate(1));
+  DCHECK(in.Equals(out));
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt:
+      __ notl(out.AsRegister<Register>());
+      break;
+
+    case Primitive::kPrimLong:
+      __ notl(out.AsRegisterPairLow<Register>());
+      __ notl(out.AsRegisterPairHigh<Register>());
+      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());
-  locations->SetInAt(1, Location::Any());
-  locations->SetOut(Location::RequiresRegister());
-}
-
-void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
-  Label greater, done;
-  LocationSummary* locations = compare->GetLocations();
   switch (compare->InputAt(0)->GetType()) {
     case Primitive::kPrimLong: {
-      Label less, greater, done;
-      Register output = locations->Out().AsX86().AsCpuRegister();
-      X86ManagedRegister left = locations->InAt(0).AsX86();
-      Location right = locations->InAt(1);
-      if (right.IsRegister()) {
-        __ cmpl(left.AsRegisterPairHigh(), right.AsX86().AsRegisterPairHigh());
-      } else {
-        DCHECK(right.IsDoubleStackSlot());
-        __ cmpl(left.AsRegisterPairHigh(), Address(ESP, right.GetHighStackIndex(kX86WordSize)));
-      }
-      __ j(kLess, &less);  // Signed compare.
-      __ j(kGreater, &greater);  // Signed compare.
-      if (right.IsRegister()) {
-        __ cmpl(left.AsRegisterPairLow(), right.AsX86().AsRegisterPairLow());
-      } else {
-        DCHECK(right.IsDoubleStackSlot());
-        __ cmpl(left.AsRegisterPairLow(), Address(ESP, right.GetStackIndex()));
-      }
-      __ movl(output, Immediate(0));
-      __ j(kEqual, &done);
-      __ j(kBelow, &less);  // Unsigned compare.
-
-      __ Bind(&greater);
-      __ movl(output, Immediate(1));
-      __ jmp(&done);
-
-      __ Bind(&less);
-      __ movl(output, Immediate(-1));
-
-      __ Bind(&done);
+      locations->SetInAt(0, Location::RequiresRegister());
+      // TODO: we set any here but we don't handle constants
+      locations->SetInAt(1, Location::Any());
+      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::RequiresRegister());
       break;
     }
     default:
-      LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
+      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
   }
 }
 
+void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
+  LocationSummary* locations = compare->GetLocations();
+  Register out = locations->Out().AsRegister<Register>();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  Label less, greater, done;
+  switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimLong: {
+      if (right.IsRegisterPair()) {
+        __ cmpl(left.AsRegisterPairHigh<Register>(), right.AsRegisterPairHigh<Register>());
+      } else {
+        DCHECK(right.IsDoubleStackSlot());
+        __ cmpl(left.AsRegisterPairHigh<Register>(),
+                Address(ESP, right.GetHighStackIndex(kX86WordSize)));
+      }
+      __ j(kLess, &less);  // Signed compare.
+      __ j(kGreater, &greater);  // Signed compare.
+      if (right.IsRegisterPair()) {
+        __ cmpl(left.AsRegisterPairLow<Register>(), right.AsRegisterPairLow<Register>());
+      } else {
+        DCHECK(right.IsDoubleStackSlot());
+        __ cmpl(left.AsRegisterPairLow<Register>(), Address(ESP, right.GetStackIndex()));
+      }
+      break;
+    }
+    case Primitive::kPrimFloat: {
+      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
+  }
+  __ movl(out, Immediate(0));
+  __ j(kEqual, &done);
+  __ j(kBelow, &less);  // kBelow is for CF (unsigned & floats).
+
+  __ Bind(&greater);
+  __ movl(out, Immediate(1));
+  __ jmp(&done);
+
+  __ Bind(&less);
+  __ movl(out, Immediate(-1));
+
+  __ Bind(&done);
+}
+
 void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -1151,77 +2710,32 @@
 }
 
 void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
+  UNUSED(instruction);
   LOG(FATAL) << "Unreachable";
 }
 
-void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  Primitive::Type field_type = instruction->GetFieldType();
-  if (field_type == Primitive::kPrimBoolean || field_type == Primitive::kPrimByte) {
-    // Ensure the value is in a byte register.
-    locations->SetInAt(1, X86CpuLocation(EAX));
-  } else {
-    locations->SetInAt(1, Location::RequiresRegister());
-  }
-  // Temporary registers for the write barrier.
-  if (field_type == Primitive::kPrimNot) {
-    locations->AddTemp(Location::RequiresRegister());
-    // Ensure the card is in a byte register.
-    locations->AddTemp(X86CpuLocation(ECX));
+void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
+  /*
+   * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
+   * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
+   * For those cases, all we need to ensure is that there is a scheduling barrier in place.
+   */
+  switch (kind) {
+    case MemBarrierKind::kAnyAny: {
+      __ mfence();
+      break;
+    }
+    case MemBarrierKind::kAnyStore:
+    case MemBarrierKind::kLoadAny:
+    case MemBarrierKind::kStoreStore: {
+      // nop
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected memory barrier " << kind;
   }
 }
 
-void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsX86().AsCpuRegister();
-  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
-  Primitive::Type field_type = instruction->GetFieldType();
-
-  switch (field_type) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte: {
-      ByteRegister value = locations->InAt(1).AsX86().AsByteRegister();
-      __ movb(Address(obj, offset), value);
-      break;
-    }
-
-    case Primitive::kPrimShort:
-    case Primitive::kPrimChar: {
-      Register value = locations->InAt(1).AsX86().AsCpuRegister();
-      __ movw(Address(obj, offset), value);
-      break;
-    }
-
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
-      Register value = locations->InAt(1).AsX86().AsCpuRegister();
-      __ movl(Address(obj, offset), value);
-
-      if (field_type == Primitive::kPrimNot) {
-        Register temp = locations->GetTemp(0).AsX86().AsCpuRegister();
-        Register card = locations->GetTemp(1).AsX86().AsCpuRegister();
-        codegen_->MarkGCCard(temp, card, obj, value);
-      }
-      break;
-    }
-
-    case Primitive::kPrimLong: {
-      X86ManagedRegister value = locations->InAt(1).AsX86();
-      __ movl(Address(obj, offset), value.AsRegisterPairLow());
-      __ movl(Address(obj, kX86WordSize + offset), value.AsRegisterPairHigh());
-      break;
-    }
-
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << field_type;
-
-    case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << field_type;
-  }
-}
 
 void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
   Label is_null;
@@ -1235,150 +2749,359 @@
   __ Bind(&is_null);
 }
 
-void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+
+  if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
+    // Long values can be loaded atomically into an XMM using movsd.
+    // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
+    // and then copy the XMM into the output 32bits at a time).
+    locations->AddTemp(Location::RequiresFpuRegister());
+  }
 }
 
-void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsX86().AsCpuRegister();
-  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
+                                                 const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
 
-  switch (instruction->GetType()) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register base = locations->InAt(0).AsRegister<Register>();
+  Location out = locations->Out();
+  bool is_volatile = field_info.IsVolatile();
+  Primitive::Type field_type = field_info.GetFieldType();
+  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+  switch (field_type) {
     case Primitive::kPrimBoolean: {
-      Register out = locations->Out().AsX86().AsCpuRegister();
-      __ movzxb(out, Address(obj, offset));
+      __ movzxb(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
     case Primitive::kPrimByte: {
-      Register out = locations->Out().AsX86().AsCpuRegister();
-      __ movsxb(out, Address(obj, offset));
+      __ movsxb(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
     case Primitive::kPrimShort: {
-      Register out = locations->Out().AsX86().AsCpuRegister();
-      __ movsxw(out, Address(obj, offset));
+      __ movsxw(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
     case Primitive::kPrimChar: {
-      Register out = locations->Out().AsX86().AsCpuRegister();
-      __ movzxw(out, Address(obj, offset));
+      __ movzxw(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      Register out = locations->Out().AsX86().AsCpuRegister();
-      __ movl(out, Address(obj, offset));
+      __ movl(out.AsRegister<Register>(), Address(base, offset));
       break;
     }
 
     case Primitive::kPrimLong: {
-      // TODO: support volatile.
-      X86ManagedRegister out = locations->Out().AsX86();
-      __ movl(out.AsRegisterPairLow(), Address(obj, offset));
-      __ movl(out.AsRegisterPairHigh(), Address(obj, kX86WordSize + offset));
+      if (is_volatile) {
+        XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+        __ movsd(temp, Address(base, offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ movd(out.AsRegisterPairLow<Register>(), temp);
+        __ psrlq(temp, Immediate(32));
+        __ movd(out.AsRegisterPairHigh<Register>(), temp);
+      } else {
+        __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
+      }
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+    case Primitive::kPrimFloat: {
+      __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
+      break;
+    }
 
     case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      LOG(FATAL) << "Unreachable type " << field_type;
+      UNREACHABLE();
   }
+
+  // Longs are handled in the switch.
+  if (field_type != Primitive::kPrimLong) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
+  }
+}
+
+void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  bool is_volatile = field_info.IsVolatile();
+  Primitive::Type field_type = field_info.GetFieldType();
+  bool is_byte_type = (field_type == Primitive::kPrimBoolean)
+    || (field_type == Primitive::kPrimByte);
+
+  // The register allocator does not support multiple
+  // inputs that die at entry with one in a specific register.
+  if (is_byte_type) {
+    // Ensure the value is in a byte register.
+    locations->SetInAt(1, Location::RegisterLocation(EAX));
+  } else {
+    locations->SetInAt(1, Location::RequiresRegister());
+  }
+  // Temporary registers for the write barrier.
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    locations->AddTemp(Location::RequiresRegister());
+    // Ensure the card is in a byte register.
+    locations->AddTemp(Location::RegisterLocation(ECX));
+  } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
+    // 64bits value can be atomically written to an address with movsd and an XMM register.
+    // We need two XMM registers because there's no easier way to (bit) copy a register pair
+    // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
+    // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
+    // isolated cases when we need this it isn't worth adding the extra complexity.
+    locations->AddTemp(Location::RequiresFpuRegister());
+    locations->AddTemp(Location::RequiresFpuRegister());
+  }
+}
+
+void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
+                                                 const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Register base = locations->InAt(0).AsRegister<Register>();
+  Location value = locations->InAt(1);
+  bool is_volatile = field_info.IsVolatile();
+  Primitive::Type field_type = field_info.GetFieldType();
+  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+  }
+
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte: {
+      __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
+      break;
+    }
+
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar: {
+      __ movw(Address(base, offset), value.AsRegister<Register>());
+      break;
+    }
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      __ movl(Address(base, offset), value.AsRegister<Register>());
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      if (is_volatile) {
+        XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+        XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+        __ movd(temp1, value.AsRegisterPairLow<Register>());
+        __ movd(temp2, value.AsRegisterPairHigh<Register>());
+        __ punpckldq(temp1, temp2);
+        __ movsd(Address(base, offset), temp1);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+      } else {
+        __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
+      }
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << field_type;
+      UNREACHABLE();
+  }
+
+  // Longs are handled in the switch.
+  if (field_type != Primitive::kPrimLong) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
+  }
+
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    Register temp = locations->GetTemp(0).AsRegister<Register>();
+    Register card = locations->GetTemp(1).AsRegister<Register>();
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+  }
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+  }
+}
+
+void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
 }
 
 void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::Any());
-  // TODO: Have a normalization phase that makes this instruction never used.
-  locations->SetOut(Location::SameAsFirstInput());
+  Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
+      ? Location::RequiresRegister()
+      : Location::Any();
+  locations->SetInAt(0, loc);
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
 }
 
-void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
+void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+    return;
+  }
+  LocationSummary* locations = instruction->GetLocations();
+  Location obj = locations->InAt(0);
+
+  __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
   codegen_->AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
-  DCHECK(obj.Equals(locations->Out()));
 
   if (obj.IsRegister()) {
-    __ cmpl(obj.AsX86().AsCpuRegister(), Immediate(0));
-  } else {
-    DCHECK(locations->InAt(0).IsStackSlot());
+    __ cmpl(obj.AsRegister<Register>(), Immediate(0));
+  } else if (obj.IsStackSlot()) {
     __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
+  } else {
+    DCHECK(obj.IsConstant()) << obj;
+    DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
+    __ jmp(slow_path->GetEntryLabel());
+    return;
   }
   __ j(kEqual, slow_path->GetEntryLabel());
 }
 
+void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
+  if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+    GenerateImplicitNullCheck(instruction);
+  } else {
+    GenerateExplicitNullCheck(instruction);
+  }
+}
+
 void LocationsBuilderX86::VisitArrayGet(HArrayGet* 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());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsX86().AsCpuRegister();
+  Register obj = locations->InAt(0).AsRegister<Register>();
   Location index = locations->InAt(1);
 
-  switch (instruction->GetType()) {
+  Primitive::Type type = instruction->GetType();
+  switch (type) {
     case Primitive::kPrimBoolean: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
-      Register out = locations->Out().AsX86().AsCpuRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
         __ movzxb(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
       } else {
-        __ movzxb(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset));
+        __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimByte: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
-      Register out = locations->Out().AsX86().AsCpuRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
         __ movsxb(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
       } else {
-        __ movsxb(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset));
+        __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimShort: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
-      Register out = locations->Out().AsX86().AsCpuRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
         __ movsxw(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
       } else {
-        __ movsxw(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset));
+        __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimChar: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
-      Register out = locations->Out().AsX86().AsCpuRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
         __ movzxw(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
       } else {
-        __ movzxw(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset));
+        __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
       }
       break;
     }
@@ -1386,128 +3109,222 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      Register out = locations->Out().AsX86().AsCpuRegister();
+      Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
         __ movl(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
       } else {
-        __ movl(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset));
+        __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
-      X86ManagedRegister out = locations->Out().AsX86();
+      Location out = locations->Out();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
-        __ movl(out.AsRegisterPairLow(), Address(obj, offset));
-        __ movl(out.AsRegisterPairHigh(), Address(obj, offset + kX86WordSize));
+        __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
       } else {
-        __ movl(out.AsRegisterPairLow(),
-                Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset));
-        __ movl(out.AsRegisterPairHigh(),
-                Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize));
+        __ movl(out.AsRegisterPairLow<Register>(),
+                Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ movl(out.AsRegisterPairHigh<Register>(),
+                Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
       }
       break;
     }
 
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
-
+      LOG(FATAL) << "Unimplemented register type " << type;
+      UNREACHABLE();
     case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      LOG(FATAL) << "Unreachable type " << type;
+      UNREACHABLE();
+  }
+
+  if (type != Primitive::kPrimLong) {
+    codegen_->MaybeRecordImplicitNullCheck(instruction);
   }
 }
 
 void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+
+  DCHECK(kFollowsQuickABI);
+  bool not_enough_registers = needs_write_barrier
+      && !instruction->GetValue()->IsConstant()
+      && !instruction->GetIndex()->IsConstant();
+  bool needs_runtime_call = instruction->NeedsTypeCheck() || not_enough_registers;
+
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
       instruction,
-      value_type == Primitive::kPrimNot ? LocationSummary::kCall : LocationSummary::kNoCall);
+      needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
 
-  if (value_type == Primitive::kPrimNot) {
+  if (needs_runtime_call) {
     InvokeRuntimeCallingConvention calling_convention;
-    locations->SetInAt(0, X86CpuLocation(calling_convention.GetRegisterAt(0)));
-    locations->SetInAt(1, X86CpuLocation(calling_convention.GetRegisterAt(1)));
-    locations->SetInAt(2, X86CpuLocation(calling_convention.GetRegisterAt(2)));
+    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+    locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+    locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   } else {
+    bool is_byte_type = (value_type == Primitive::kPrimBoolean)
+        || (value_type == Primitive::kPrimByte);
+    // 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.
     locations->SetInAt(0, Location::RequiresRegister());
     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
-    if (value_type == Primitive::kPrimBoolean || value_type == Primitive::kPrimByte) {
+    if (is_byte_type) {
       // Ensure the value is in a byte register.
-      locations->SetInAt(2, X86CpuLocation(EAX));
+      locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
     } else {
-      locations->SetInAt(2, Location::RequiresRegister());
+      locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
+    }
+    // Temporary registers for the write barrier.
+    if (needs_write_barrier) {
+      locations->AddTemp(Location::RequiresRegister());
+      // Ensure the card is in a byte register.
+      locations->AddTemp(Location::RegisterLocation(ECX));
     }
   }
 }
 
 void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  Register obj = locations->InAt(0).AsX86().AsCpuRegister();
+  Register obj = locations->InAt(0).AsRegister<Register>();
   Location index = locations->InAt(1);
+  Location value = locations->InAt(2);
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_runtime_call = locations->WillCall();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
-      ByteRegister value = locations->InAt(2).AsX86().AsByteRegister();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
-        __ movb(Address(obj, offset), value);
+        if (value.IsRegister()) {
+          __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
+        } else {
+          __ movb(Address(obj, offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       } else {
-        __ movb(Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset), value);
+        if (value.IsRegister()) {
+          __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
+                  value.AsRegister<ByteRegister>());
+        } else {
+          __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
       break;
     }
 
     case Primitive::kPrimShort:
     case Primitive::kPrimChar: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
-      Register value = locations->InAt(2).AsX86().AsCpuRegister();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
-        __ movw(Address(obj, offset), value);
+        if (value.IsRegister()) {
+          __ movw(Address(obj, offset), value.AsRegister<Register>());
+        } else {
+          __ movw(Address(obj, offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       } else {
-        __ movw(Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset), value);
+        if (value.IsRegister()) {
+          __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
+                  value.AsRegister<Register>());
+        } else {
+          __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
       break;
     }
 
-    case Primitive::kPrimInt: {
-      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      Register value = locations->InAt(2).AsX86().AsCpuRegister();
-      if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-        __ movl(Address(obj, offset), value);
-      } else {
-        __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset), value);
-      }
-      break;
-    }
-
+    case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      DCHECK(!codegen_->IsLeafMethod());
-      __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
-      codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+      if (!needs_runtime_call) {
+        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+        if (index.IsConstant()) {
+          size_t offset =
+              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, offset), value.AsRegister<Register>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        } else {
+          DCHECK(index.IsRegister()) << index;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
+                    value.AsRegister<Register>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        }
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+        if (needs_write_barrier) {
+          Register temp = locations->GetTemp(0).AsRegister<Register>();
+          Register card = locations->GetTemp(1).AsRegister<Register>();
+          codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
+        }
+      } else {
+        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        DCHECK(!codegen_->IsLeafMethod());
+        __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
+        codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+      }
       break;
     }
 
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
-      X86ManagedRegister value = locations->InAt(2).AsX86();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
-        __ movl(Address(obj, offset), value.AsRegisterPairLow());
-        __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh());
+        if (value.IsRegisterPair()) {
+          __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
+          codegen_->MaybeRecordImplicitNullCheck(instruction);
+          __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
+        } else {
+          DCHECK(value.IsConstant());
+          int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
+          __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
+          codegen_->MaybeRecordImplicitNullCheck(instruction);
+          __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
+        }
       } else {
-        __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset),
-                value.AsRegisterPairLow());
-        __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize),
-                value.AsRegisterPairHigh());
+        if (value.IsRegisterPair()) {
+          __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
+                  value.AsRegisterPairLow<Register>());
+          codegen_->MaybeRecordImplicitNullCheck(instruction);
+          __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
+                  value.AsRegisterPairHigh<Register>());
+        } else {
+          DCHECK(value.IsConstant());
+          int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
+          __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
+                  Immediate(Low32Bits(val)));
+          codegen_->MaybeRecordImplicitNullCheck(instruction);
+          __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
+                  Immediate(High32Bits(val)));
+        }
       }
       break;
     }
@@ -1515,25 +3332,27 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
       LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
-
+      UNREACHABLE();
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      UNREACHABLE();
   }
 }
 
 void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   instruction->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations = instruction->GetLocations();
   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
-  Register obj = locations->InAt(0).AsX86().AsCpuRegister();
-  Register out = locations->Out().AsX86().AsCpuRegister();
+  Register obj = locations->InAt(0).AsRegister<Register>();
+  Register out = locations->Out().AsRegister<Register>();
   __ movl(out, Address(obj, offset));
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -1541,18 +3360,19 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  // TODO: Have a normalization phase that makes this instruction never used.
-  locations->SetOut(Location::SameAsFirstInput());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
 }
 
 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);
 
-  Register index = locations->InAt(0).AsX86().AsCpuRegister();
-  Register length = locations->InAt(1).AsX86().AsCpuRegister();
+  Register index = locations->InAt(0).AsRegister<Register>();
+  Register length = locations->InAt(1).AsRegister<Register>();
 
   __ cmpl(index, length);
   __ j(kAboveEqual, slow_path->GetEntryLabel());
@@ -1564,9 +3384,11 @@
 
 void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
   // Nothing to do, this is driven by the code generator.
+  UNUSED(temp);
 }
 
 void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
+  UNUSED(instruction);
   LOG(FATAL) << "Unreachable";
 }
 
@@ -1627,14 +3449,14 @@
 
   if (source.IsRegister()) {
     if (destination.IsRegister()) {
-      __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
+      __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
     } else {
       DCHECK(destination.IsStackSlot());
-      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
+      __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
     }
   } else if (source.IsStackSlot()) {
     if (destination.IsRegister()) {
-      __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
+      __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
     } else {
       DCHECK(destination.IsStackSlot());
       MoveMemoryToMemory(destination.GetStackIndex(),
@@ -1644,12 +3466,12 @@
     HIntConstant* instruction = source.GetConstant()->AsIntConstant();
     Immediate imm(instruction->AsIntConstant()->GetValue());
     if (destination.IsRegister()) {
-      __ movl(destination.AsX86().AsCpuRegister(), imm);
+      __ movl(destination.AsRegister<Register>(), imm);
     } else {
       __ movl(Address(ESP, destination.GetStackIndex()), imm);
     }
   } else {
-    LOG(FATAL) << "Unimplemented";
+    LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
   }
 }
 
@@ -1686,11 +3508,11 @@
   Location destination = move->GetDestination();
 
   if (source.IsRegister() && destination.IsRegister()) {
-    __ xchgl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
+    __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
   } else if (source.IsRegister() && destination.IsStackSlot()) {
-    Exchange(source.AsX86().AsCpuRegister(), destination.GetStackIndex());
+    Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
   } else if (source.IsStackSlot() && destination.IsRegister()) {
-    Exchange(destination.AsX86().AsCpuRegister(), source.GetStackIndex());
+    Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
     Exchange(destination.GetStackIndex(), source.GetStackIndex());
   } else {
@@ -1706,5 +3528,312 @@
   __ popl(static_cast<Register>(reg));
 }
 
+void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
+  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
+      ? LocationSummary::kCallOnSlowPath
+      : LocationSummary::kNoCall;
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
+  Register out = cls->GetLocations()->Out().AsRegister<Register>();
+  if (cls->IsReferrersClass()) {
+    DCHECK(!cls->CanCallRuntime());
+    DCHECK(!cls->MustGenerateClinitCheck());
+    codegen_->LoadCurrentMethod(out);
+    __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
+  } else {
+    DCHECK(cls->CanCallRuntime());
+    codegen_->LoadCurrentMethod(out);
+    __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
+    __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+
+    SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+    codegen_->AddSlowPath(slow_path);
+    __ testl(out, out);
+    __ j(kEqual, slow_path->GetEntryLabel());
+    if (cls->MustGenerateClinitCheck()) {
+      GenerateClassInitializationCheck(slow_path, out);
+    } else {
+      __ Bind(slow_path->GetExitLabel());
+    }
+  }
+}
+
+void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (check->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
+  // We assume the class to not be null.
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
+      check->GetLoadClass(), check, check->GetDexPc(), true);
+  codegen_->AddSlowPath(slow_path);
+  GenerateClassInitializationCheck(slow_path,
+                                   check->GetLocations()->InAt(0).AsRegister<Register>());
+}
+
+void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
+    SlowPathCodeX86* slow_path, Register class_reg) {
+  __ cmpl(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
+          Immediate(mirror::Class::kStatusInitialized));
+  __ j(kLess, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+  // No need for memory fence, thanks to the X86 memory model.
+}
+
+void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
+  codegen_->AddSlowPath(slow_path);
+
+  Register out = load->GetLocations()->Out().AsRegister<Register>();
+  codegen_->LoadCurrentMethod(out);
+  __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
+  __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
+  __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  __ testl(out, out);
+  __ j(kEqual, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
+  Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
+  __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
+  __ fs()->movl(address, Immediate(0));
+}
+
+void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
+  __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary::CallKind call_kind = instruction->IsClassFinal()
+      ? LocationSummary::kNoCall
+      : LocationSummary::kCallOnSlowPath;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = locations->InAt(0).AsRegister<Register>();
+  Location cls = locations->InAt(1);
+  Register out = locations->Out().AsRegister<Register>();
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  Label done, zero;
+  SlowPathCodeX86* slow_path = nullptr;
+
+  // Return 0 if `obj` is null.
+  // TODO: avoid this check if we know obj is not null.
+  __ testl(obj, obj);
+  __ j(kEqual, &zero);
+  __ movl(out, Address(obj, class_offset));
+  // Compare the class of `obj` with `cls`.
+  if (cls.IsRegister()) {
+    __ cmpl(out, cls.AsRegister<Register>());
+  } else {
+    DCHECK(cls.IsStackSlot()) << cls;
+    __ cmpl(out, Address(ESP, cls.GetStackIndex()));
+  }
+
+  if (instruction->IsClassFinal()) {
+    // Classes must be equal for the instanceof to succeed.
+    __ j(kNotEqual, &zero);
+    __ movl(out, Immediate(1));
+    __ jmp(&done);
+  } else {
+    // If the classes are not equal, we go into a slow path.
+    DCHECK(locations->OnlyCallsOnSlowPath());
+    slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
+        instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
+    codegen_->AddSlowPath(slow_path);
+    __ j(kNotEqual, slow_path->GetEntryLabel());
+    __ movl(out, Immediate(1));
+    __ jmp(&done);
+  }
+  __ Bind(&zero);
+  __ movl(out, Immediate(0));
+  if (slow_path != nullptr) {
+    __ Bind(slow_path->GetExitLabel());
+  }
+  __ Bind(&done);
+}
+
+void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+      instruction, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register obj = locations->InAt(0).AsRegister<Register>();
+  Location cls = locations->InAt(1);
+  Register temp = locations->GetTemp(0).AsRegister<Register>();
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
+      instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
+  codegen_->AddSlowPath(slow_path);
+
+  // TODO: avoid this check if we know obj is not null.
+  __ testl(obj, obj);
+  __ j(kEqual, slow_path->GetExitLabel());
+  __ movl(temp, Address(obj, class_offset));
+
+  // Compare the class of `obj` with `cls`.
+  if (cls.IsRegister()) {
+    __ cmpl(temp, cls.AsRegister<Register>());
+  } else {
+    DCHECK(cls.IsStackSlot()) << cls;
+    __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
+  }
+
+  __ j(kNotEqual, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
+  __ fs()->call(Address::Absolute(instruction->IsEnter()
+        ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
+        : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+
+void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    if (second.IsRegister()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
+      }
+    } else if (second.IsConstant()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegister<Register>(),
+                Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegister<Register>(),
+               Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegister<Register>(),
+                Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
+      }
+    } else {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
+      }
+    }
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    if (second.IsRegisterPair()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
+      }
+    } else {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ andl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ orl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ xorl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
+      }
+    }
+  }
+}
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 23145bf..a9086f8 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -18,6 +18,8 @@
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_
 
 #include "code_generator.h"
+#include "dex/compiler_enums.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "parallel_move_resolver.h"
 #include "utils/x86/assembler_x86.h"
@@ -25,18 +27,25 @@
 namespace art {
 namespace x86 {
 
-static constexpr size_t kX86WordSize = 4;
+// Use a local definition to prevent copying mistakes.
+static constexpr size_t kX86WordSize = kX86PointerSize;
 
 class CodeGeneratorX86;
+class SlowPathCodeX86;
 
 static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX };
 static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX };
 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+static constexpr XmmRegister kParameterFpuRegisters[] = { };
+static constexpr size_t kParameterFpuRegistersLength = 0;
 
-class InvokeDexCallingConvention : public CallingConvention<Register> {
+class InvokeDexCallingConvention : public CallingConvention<Register, XmmRegister> {
  public:
-  InvokeDexCallingConvention()
-      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
+  InvokeDexCallingConvention() : CallingConvention(
+      kParameterCoreRegisters,
+      kParameterCoreRegistersLength,
+      kParameterFpuRegisters,
+      kParameterFpuRegistersLength) {}
 
   RegisterPair GetRegisterPairAt(size_t argument_index) {
     DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
@@ -65,10 +74,10 @@
   ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen)
       : ParallelMoveResolver(allocator), codegen_(codegen) {}
 
-  virtual void EmitMove(size_t index) OVERRIDE;
-  virtual void EmitSwap(size_t index) OVERRIDE;
-  virtual void SpillScratch(int reg) OVERRIDE;
-  virtual void RestoreScratch(int reg) OVERRIDE;
+  void EmitMove(size_t index) OVERRIDE;
+  void EmitSwap(size_t index) OVERRIDE;
+  void SpillScratch(int reg) OVERRIDE;
+  void RestoreScratch(int reg) OVERRIDE;
 
   X86Assembler* GetAssembler() const;
 
@@ -87,16 +96,20 @@
   LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen)
       : HGraphVisitor(graph), codegen_(codegen) {}
 
-#define DECLARE_VISIT_INSTRUCTION(name)     \
-  virtual void Visit##name(H##name* instr);
+#define DECLARE_VISIT_INSTRUCTION(name, super)     \
+  void Visit##name(H##name* instr) OVERRIDE;
 
   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void HandleInvoke(HInvoke* invoke);
-
  private:
+  void HandleBitwiseOperation(HBinaryOperation* instruction);
+  void HandleInvoke(HInvoke* invoke);
+  void HandleShift(HBinaryOperation* instruction);
+  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
+
   CodeGeneratorX86* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
 
@@ -107,15 +120,13 @@
  public:
   InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen);
 
-#define DECLARE_VISIT_INSTRUCTION(name)     \
-  virtual void Visit##name(H##name* instr);
+#define DECLARE_VISIT_INSTRUCTION(name, super)     \
+  void Visit##name(H##name* instr) OVERRIDE;
 
   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void LoadCurrentMethod(Register reg);
-
   X86Assembler* GetAssembler() const { return assembler_; }
 
  private:
@@ -123,6 +134,22 @@
   // is the block to branch to if the suspend check is not needed, and after
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
+  void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg);
+  void HandleBitwiseOperation(HBinaryOperation* instruction);
+  void GenerateDivRemIntegral(HBinaryOperation* instruction);
+  void GenerateRemFP(HRem *rem);
+  void HandleShift(HBinaryOperation* instruction);
+  void GenerateShlLong(const Location& loc, Register shifter);
+  void GenerateShrLong(const Location& loc, Register shifter);
+  void GenerateUShrLong(const Location& loc, Register shifter);
+  void GenerateMemoryBarrier(MemBarrierKind kind);
+  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
+  void PushOntoFPStack(Location source, uint32_t temp_offset,
+                       uint32_t stack_adjustment, bool is_float);
+
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
 
   X86Assembler* const assembler_;
   CodeGeneratorX86* const codegen_;
@@ -132,57 +159,60 @@
 
 class CodeGeneratorX86 : public CodeGenerator {
  public:
-  explicit CodeGeneratorX86(HGraph* graph);
+  CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options);
   virtual ~CodeGeneratorX86() {}
 
-  virtual void GenerateFrameEntry() OVERRIDE;
-  virtual void GenerateFrameExit() OVERRIDE;
-  virtual void Bind(Label* label) 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;
+  void GenerateFrameEntry() OVERRIDE;
+  void GenerateFrameExit() OVERRIDE;
+  void Bind(HBasicBlock* block) OVERRIDE;
+  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
-  virtual size_t GetWordSize() const OVERRIDE {
+  size_t GetWordSize() const OVERRIDE {
     return kX86WordSize;
   }
 
-  virtual size_t FrameEntrySpillSize() const OVERRIDE;
+  size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
+    // 8 bytes == 2 words for each spill.
+    return 2 * kX86WordSize;
+  }
 
-  virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+  size_t FrameEntrySpillSize() const OVERRIDE;
+
+  HGraphVisitor* GetLocationBuilder() OVERRIDE {
     return &location_builder_;
   }
 
-  virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+  HGraphVisitor* GetInstructionVisitor() OVERRIDE {
     return &instruction_visitor_;
   }
 
-  virtual X86Assembler* GetAssembler() OVERRIDE {
+  X86Assembler* GetAssembler() OVERRIDE {
     return &assembler_;
   }
 
-  virtual size_t GetNumberOfRegisters() const OVERRIDE;
-  virtual void SetupBlockedRegisters(bool* blocked_registers) const OVERRIDE;
-  virtual ManagedRegister AllocateFreeRegister(
-      Primitive::Type type, bool* blocked_registers) const OVERRIDE;
-
-  virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
-
-  virtual size_t GetNumberOfCoreRegisters() const OVERRIDE {
-    return kNumberOfCpuRegisters;
+  uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+    return GetLabelOf(block)->Position();
   }
 
-  virtual size_t GetNumberOfFloatingPointRegisters() const OVERRIDE {
-    return kNumberOfXmmRegisters;
-  }
+  void SetupBlockedRegisters() const OVERRIDE;
 
-  virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
-  virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+  Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
 
-  ParallelMoveResolverX86* GetMoveResolver() {
+  Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+
+  void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+  void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+
+  // Blocks all register pairs made out of blocked core registers.
+  void UpdateBlockedPairRegisters() const;
+
+  ParallelMoveResolverX86* GetMoveResolver() OVERRIDE {
     return &move_resolver_;
   }
 
-  virtual InstructionSet GetInstructionSet() const OVERRIDE {
+  InstructionSet GetInstructionSet() const OVERRIDE {
     return InstructionSet::kX86;
   }
 
@@ -194,7 +224,23 @@
   // Emit a write barrier.
   void MarkGCCard(Register temp, Register card, Register object, Register value);
 
+  void LoadCurrentMethod(Register reg);
+
+  Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_.GetRawStorage() + block->GetBlockId();
+  }
+
+  void Initialize() OVERRIDE {
+    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
+  }
+
+  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
+    return type == Primitive::kPrimLong;
+  }
+
  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 78c7d9d..da83b76 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -18,7 +18,9 @@
 
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
-#include "mirror/array.h"
+#include "intrinsics.h"
+#include "intrinsics_x86_64.h"
+#include "mirror/array-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/class.h"
 #include "mirror/object_reference.h"
@@ -30,33 +32,30 @@
 
 namespace art {
 
-x86_64::X86_64ManagedRegister Location::AsX86_64() const {
-  return reg().AsX86_64();
-}
-
 namespace x86_64 {
 
-static constexpr bool kExplicitStackOverflowCheck = false;
-
 // Some x86_64 instructions require a register to be available as temp.
 static constexpr Register TMP = R11;
 
 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
 static constexpr int kCurrentMethodStackOffset = 0;
 
-static Location X86_64CpuLocation(Register reg) {
-  return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
-}
-
 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     arraysize(kRuntimeParameterCoreRegisters);
+static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 };
+static constexpr size_t kRuntimeParameterFpuRegistersLength =
+    arraysize(kRuntimeParameterFpuRegisters);
 
-class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
+static constexpr int kC2ConditionMask = 0x400;
+
+class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
  public:
   InvokeRuntimeCallingConvention()
       : CallingConvention(kRuntimeParameterCoreRegisters,
-                          kRuntimeParameterCoreRegistersLength) {}
+                          kRuntimeParameterCoreRegistersLength,
+                          kRuntimeParameterFpuRegisters,
+                          kRuntimeParameterFpuRegistersLength) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
@@ -64,7 +63,7 @@
 
 #define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
 
-class NullCheckSlowPathX86_64 : public SlowPathCode {
+class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
   explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
 
@@ -80,7 +79,55 @@
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
 };
 
-class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
+class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+  explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    __ gs()->call(
+        Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+  }
+
+ private:
+  HDivZeroCheck* const instruction_;
+  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
+};
+
+class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+  explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div)
+      : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    if (type_ == Primitive::kPrimInt) {
+      if (is_div_) {
+        __ negl(cpu_reg_);
+      } else {
+        __ movl(cpu_reg_, Immediate(0));
+      }
+
+    } else {
+      DCHECK_EQ(Primitive::kPrimLong, type_);
+      if (is_div_) {
+        __ negq(cpu_reg_);
+      } else {
+        __ movq(cpu_reg_, Immediate(0));
+      }
+    }
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  const CpuRegister cpu_reg_;
+  const Primitive::Type type_;
+  const bool is_div_;
+  DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64);
+};
+
+class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
   StackOverflowCheckSlowPathX86_64() {}
 
@@ -96,12 +143,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));
@@ -110,7 +158,7 @@
     if (successor_ == nullptr) {
       __ jmp(GetReturnLabel());
     } else {
-      __ jmp(codegen->GetLabelOf(successor_));
+      __ jmp(x64_codegen->GetLabelOf(successor_));
     }
   }
 
@@ -127,7 +175,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,
@@ -137,11 +185,15 @@
         length_location_(length_location) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
     __ Bind(GetEntryLabel());
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
     InvokeRuntimeCallingConvention calling_convention;
-    x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
-    x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
+    codegen->EmitParallelMoves(
+        index_location_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+        length_location_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
     __ gs()->call(Address::Absolute(
         QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
     codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
@@ -155,6 +207,145 @@
   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
 };
 
+class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+  LoadClassSlowPathX86_64(HLoadClass* cls,
+                          HInstruction* at,
+                          uint32_t dex_pc,
+                          bool do_clinit)
+      : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
+  }
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = at_->GetLocations();
+    CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
+    __ Bind(GetEntryLabel());
+
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
+    x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
+    __ gs()->call(Address::Absolute((do_clinit_
+          ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
+          : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
+    codegen->RecordPcInfo(at_, dex_pc_);
+
+    Location out = locations->Out();
+    // Move the class to the desired location.
+    if (out.IsValid()) {
+      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+      x64_codegen->Move(out, Location::RegisterLocation(RAX));
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  // The class this slow path will load.
+  HLoadClass* const cls_;
+
+  // The instruction where this slow path is happening.
+  // (Might be the load class or an initialization check).
+  HInstruction* const at_;
+
+  // The dex PC of `at_`.
+  const uint32_t dex_pc_;
+
+  // Whether to initialize the class.
+  const bool do_clinit_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
+};
+
+class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+  explicit LoadStringSlowPathX86_64(HLoadString* instruction) : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+    CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    InvokeRuntimeCallingConvention calling_convention;
+    x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
+    __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
+            Immediate(instruction_->GetStringIndex()));
+    __ gs()->call(Address::Absolute(
+        QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pResolveString), true));
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
+    codegen->RestoreLiveRegisters(locations);
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  HLoadString* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
+};
+
+class TypeCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+  TypeCheckSlowPathX86_64(HInstruction* instruction,
+                          Location class_to_check,
+                          Location object_class,
+                          uint32_t dex_pc)
+      : instruction_(instruction),
+        class_to_check_(class_to_check),
+        object_class_(object_class),
+        dex_pc_(dex_pc) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    LocationSummary* locations = instruction_->GetLocations();
+    DCHECK(instruction_->IsCheckCast()
+           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+    CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
+    __ Bind(GetEntryLabel());
+    codegen->SaveLiveRegisters(locations);
+
+    // We're moving two locations to locations that could overlap, so we need a parallel
+    // move resolver.
+    InvokeRuntimeCallingConvention calling_convention;
+    codegen->EmitParallelMoves(
+        class_to_check_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+        object_class_,
+        Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+
+    if (instruction_->IsInstanceOf()) {
+      __ gs()->call(
+          Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInstanceofNonTrivial), true));
+    } else {
+      DCHECK(instruction_->IsCheckCast());
+      __ gs()->call(
+          Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pCheckCast), true));
+    }
+    codegen->RecordPcInfo(instruction_, dex_pc_);
+
+    if (instruction_->IsInstanceOf()) {
+      x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
+    }
+
+    codegen->RestoreLiveRegisters(locations);
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  HInstruction* const instruction_;
+  const Location class_to_check_;
+  const Location object_class_;
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86_64);
+};
+
 #undef __
 #define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
 
@@ -172,6 +363,31 @@
   return kEqual;
 }
 
+void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
+                                                     CpuRegister temp) {
+  // All registers are assumed to be correctly set up.
+
+  // 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;
+  LoadCurrentMethod(temp);
+  // temp = temp->dex_cache_resolved_methods_;
+  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
+  // temp = temp[index_in_cache]
+  __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
+  // (temp + offset_of_quick_compiled_code)()
+  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kX86_64WordSize).SizeValue()));
+
+  DCHECK(!IsLeafMethod());
+  RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
   stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
 }
@@ -180,16 +396,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;
 }
 
-CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
-      : CodeGenerator(graph, kNumberOfRegIds),
+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, const CompilerOptions& compiler_options)
+      : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfFloatRegisters, 0, compiler_options),
+        block_labels_(graph->GetArena(), 0),
         location_builder_(graph, this),
         instruction_visitor_(graph, this),
         move_resolver_(graph->GetArena(), this) {}
@@ -204,8 +433,7 @@
         assembler_(codegen->GetAssembler()),
         codegen_(codegen) {}
 
-ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
-                                                          bool* blocked_registers) const {
+Location CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type) const {
   switch (type) {
     case Primitive::kPrimLong:
     case Primitive::kPrimByte:
@@ -214,35 +442,42 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
-      return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
+      size_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters);
+      return Location::RegisterLocation(reg);
     }
 
     case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << type;
+    case Primitive::kPrimDouble: {
+      size_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfFloatRegisters);
+      return Location::FpuRegisterLocation(reg);
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << type;
   }
 
-  return ManagedRegister::NoRegister();
+  return Location();
 }
 
-void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
+void CodeGeneratorX86_64::SetupBlockedRegisters() const {
   // Stack register is always reserved.
-  blocked_registers[RSP] = true;
+  blocked_core_registers_[RSP] = true;
 
   // Block the register used as TMP.
-  blocked_registers[TMP] = true;
+  blocked_core_registers_[TMP] = true;
 
   // TODO: We currently don't use Quick's callee saved registers.
-  blocked_registers[RBX] = true;
-  blocked_registers[RBP] = true;
-  blocked_registers[R12] = true;
-  blocked_registers[R13] = true;
-  blocked_registers[R14] = true;
-  blocked_registers[R15] = true;
+  blocked_core_registers_[RBX] = true;
+  blocked_core_registers_[RBP] = true;
+  blocked_core_registers_[R12] = true;
+  blocked_core_registers_[R13] = true;
+  blocked_core_registers_[R14] = true;
+  blocked_core_registers_[R15] = true;
+
+  blocked_fpu_registers_[XMM12] = true;
+  blocked_fpu_registers_[XMM13] = true;
+  blocked_fpu_registers_[XMM14] = true;
+  blocked_fpu_registers_[XMM15] = true;
 }
 
 void CodeGeneratorX86_64::GenerateFrameEntry() {
@@ -252,8 +487,9 @@
 
   bool skip_overflow_check = IsLeafMethod()
       && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
+  bool implicitStackOverflowChecks = GetCompilerOptions().GetImplicitStackOverflowChecks();
 
-  if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
+  if (!skip_overflow_check && implicitStackOverflowChecks) {
     __ testq(CpuRegister(RAX), Address(
         CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
     RecordPcInfo(nullptr, 0);
@@ -263,8 +499,8 @@
   __ subq(CpuRegister(RSP),
           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
 
-  if (!skip_overflow_check && kExplicitStackOverflowCheck) {
-    SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
+  if (!skip_overflow_check && !implicitStackOverflowChecks) {
+    SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
     AddSlowPath(slow_path);
 
     __ gs()->cmpq(CpuRegister(RSP),
@@ -280,27 +516,25 @@
           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) {
+void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
   __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
 }
 
 Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
   switch (load->GetType()) {
     case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
       break;
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
-      return Location::StackSlot(GetStackSlot(load->GetLocal()));
-
     case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented type " << load->GetType();
+      return Location::StackSlot(GetStackSlot(load->GetLocal()));
 
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
@@ -320,25 +554,71 @@
   }
   if (destination.IsRegister()) {
     if (source.IsRegister()) {
-      __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
+      __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
+    } else if (source.IsFpuRegister()) {
+      __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
     } else if (source.IsStackSlot()) {
-      __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
+      __ movl(destination.AsRegister<CpuRegister>(),
+              Address(CpuRegister(RSP), source.GetStackIndex()));
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
+      __ movq(destination.AsRegister<CpuRegister>(),
+              Address(CpuRegister(RSP), source.GetStackIndex()));
+    }
+  } else if (destination.IsFpuRegister()) {
+    if (source.IsRegister()) {
+      __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
+    } else if (source.IsFpuRegister()) {
+      __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
+    } else if (source.IsStackSlot()) {
+      __ movss(destination.AsFpuRegister<XmmRegister>(),
+              Address(CpuRegister(RSP), source.GetStackIndex()));
+    } else {
+      DCHECK(source.IsDoubleStackSlot());
+      __ movsd(destination.AsFpuRegister<XmmRegister>(),
+               Address(CpuRegister(RSP), source.GetStackIndex()));
     }
   } else if (destination.IsStackSlot()) {
     if (source.IsRegister()) {
-      __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
+      __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
+              source.AsRegister<CpuRegister>());
+    } else if (source.IsFpuRegister()) {
+      __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
+               source.AsFpuRegister<XmmRegister>());
+    } else if (source.IsConstant()) {
+      HConstant* constant = source.GetConstant();
+      int32_t value;
+      if (constant->IsFloatConstant()) {
+        value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
+      } else {
+        DCHECK(constant->IsIntConstant());
+        value = constant->AsIntConstant()->GetValue();
+      }
+      __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
     } else {
-      DCHECK(source.IsStackSlot());
+      DCHECK(source.IsStackSlot()) << source;
       __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
     }
   } else {
     DCHECK(destination.IsDoubleStackSlot());
     if (source.IsRegister()) {
-      __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
+      __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
+              source.AsRegister<CpuRegister>());
+    } else if (source.IsFpuRegister()) {
+      __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
+               source.AsFpuRegister<XmmRegister>());
+    } else if (source.IsConstant()) {
+      HConstant* constant = source.GetConstant();
+      int64_t value = constant->AsLongConstant()->GetValue();
+      if (constant->IsDoubleConstant()) {
+        value = bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue());
+      } else {
+        DCHECK(constant->IsLongConstant());
+        value = constant->AsLongConstant()->GetValue();
+      }
+      __ movq(CpuRegister(TMP), Immediate(value));
+      __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
     } else {
       DCHECK(source.IsDoubleStackSlot());
       __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
@@ -350,22 +630,36 @@
 void CodeGeneratorX86_64::Move(HInstruction* instruction,
                                Location location,
                                HInstruction* move_for) {
-  if (instruction->AsIntConstant() != nullptr) {
-    Immediate imm(instruction->AsIntConstant()->GetValue());
-    if (location.IsRegister()) {
-      __ movl(location.AsX86_64().AsCpuRegister(), imm);
-    } else {
-      __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
+  LocationSummary* locations = instruction->GetLocations();
+  if (locations != nullptr && locations->Out().Equals(location)) {
+    return;
+  }
+
+  if (locations != nullptr && locations->Out().IsConstant()) {
+    HConstant* const_to_move = locations->Out().GetConstant();
+    if (const_to_move->IsIntConstant()) {
+      Immediate imm(const_to_move->AsIntConstant()->GetValue());
+      if (location.IsRegister()) {
+        __ movl(location.AsRegister<CpuRegister>(), imm);
+      } else if (location.IsStackSlot()) {
+        __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
+      } else {
+        DCHECK(location.IsConstant());
+        DCHECK_EQ(location.GetConstant(), const_to_move);
+      }
+    } else if (const_to_move->IsLongConstant()) {
+      int64_t value = const_to_move->AsLongConstant()->GetValue();
+      if (location.IsRegister()) {
+        __ movq(location.AsRegister<CpuRegister>(), Immediate(value));
+      } 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(), const_to_move);
+      }
     }
-  } else if (instruction->AsLongConstant() != nullptr) {
-    int64_t value = instruction->AsLongConstant()->GetValue();
-    if (location.IsRegister()) {
-      __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
-    } else {
-      __ movq(CpuRegister(TMP), Immediate(value));
-      __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
-    }
-  } else if (instruction->AsLoadLocal() != nullptr) {
+  } else if (instruction->IsLoadLocal()) {
     switch (instruction->GetType()) {
       case Primitive::kPrimBoolean:
       case Primitive::kPrimByte:
@@ -373,16 +667,22 @@
       case Primitive::kPrimShort:
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
+      case Primitive::kPrimFloat:
         Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
         break;
 
       case Primitive::kPrimLong:
-        Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
+      case Primitive::kPrimDouble:
+        Move(location,
+             Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
+        LOG(FATAL) << "Unexpected local type " << instruction->GetType();
     }
+  } else if (instruction->IsTemporary()) {
+    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
+    Move(location, temp_location);
   } else {
     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
     switch (instruction->GetType()) {
@@ -393,11 +693,13 @@
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
       case Primitive::kPrimLong:
-        Move(location, instruction->GetLocations()->Out());
+      case Primitive::kPrimFloat:
+      case Primitive::kPrimDouble:
+        Move(location, locations->Out());
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented type " << instruction->GetType();
+        LOG(FATAL) << "Unexpected type " << instruction->GetType();
     }
   }
 }
@@ -433,6 +735,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
+  UNUSED(exit);
   if (kIsDebugBuild) {
     __ Comment("Unreachable");
     __ int3();
@@ -443,45 +746,66 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
   HInstruction* cond = if_instr->InputAt(0);
-  DCHECK(cond->IsCondition());
-  HCondition* condition = cond->AsCondition();
-  if (condition->NeedsMaterialization()) {
+  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
     locations->SetInAt(0, Location::Any());
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
   HInstruction* cond = if_instr->InputAt(0);
-  DCHECK(cond->IsCondition());
-  HCondition* condition = cond->AsCondition();
-  if (condition->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.
-    if (!condition->IsBeforeWhenDisregardMoves(if_instr)) {
-      // Materialized condition, compare against 0.
-      Location lhs = if_instr->GetLocations()->InAt(0);
-      if (lhs.IsRegister()) {
-        __ cmpl(lhs.AsX86_64().AsCpuRegister(), 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()));
-  } else {
-    Location lhs = condition->GetLocations()->InAt(0);
-    Location rhs = condition->GetLocations()->InAt(1);
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
-    } else if (rhs.IsConstant()) {
-      __ cmpl(lhs.AsX86_64().AsCpuRegister(),
-              Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
+      return;
     } else {
-      __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      DCHECK_EQ(cond_value, 0);
     }
-    __ j(X86_64Condition(condition->GetCondition()),
-         codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+  } 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.AsRegister<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.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
+      } else if (rhs.IsConstant()) {
+        __ cmpl(lhs.AsRegister<CpuRegister>(),
+                Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
+      } else {
+        __ cmpl(lhs.AsRegister<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()));
   }
 }
@@ -500,6 +824,7 @@
 
 void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
   // Nothing to do, this is driven by the code generator.
+  UNUSED(load);
 }
 
 void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
@@ -512,19 +837,22 @@
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
+    case Primitive::kPrimFloat:
       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
       break;
 
     case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
       break;
 
     default:
-      LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
+      LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
+  UNUSED(store);
 }
 
 void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
@@ -540,17 +868,17 @@
 void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
   if (comp->NeedsMaterialization()) {
     LocationSummary* locations = comp->GetLocations();
-    CpuRegister reg = locations->Out().AsX86_64().AsCpuRegister();
+    CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
     // Clear register: setcc only sets the low byte.
     __ xorq(reg, reg);
     if (locations->InAt(1).IsRegister()) {
-      __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
-              locations->InAt(1).AsX86_64().AsCpuRegister());
+      __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
+              locations->InAt(1).AsRegister<CpuRegister>());
     } else if (locations->InAt(1).IsConstant()) {
-      __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
+      __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
               Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
     } else {
-      __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
+      __ cmpl(locations->InAt(0).AsRegister<CpuRegister>(),
               Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
     }
     __ setcc(X86_64Condition(comp->GetCondition()), reg);
@@ -608,32 +936,61 @@
 void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  switch (compare->InputAt(0)->GetType()) {
+    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::RequiresRegister());
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
+  }
 }
 
 void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
-  Label greater, done;
   LocationSummary* locations = compare->GetLocations();
-  switch (compare->InputAt(0)->GetType()) {
-    case Primitive::kPrimLong:
-      __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
-              locations->InAt(1).AsX86_64().AsCpuRegister());
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  Label less, greater, done;
+  Primitive::Type type = compare->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong: {
+      __ cmpq(left.AsRegister<CpuRegister>(), right.AsRegister<CpuRegister>());
       break;
+    }
+    case Primitive::kPrimFloat: {
+      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      break;
+    }
     default:
-      LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
+      LOG(FATAL) << "Unexpected compare type " << type;
   }
-
-  __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
+  __ movl(out, Immediate(0));
   __ j(kEqual, &done);
-  __ j(kGreater, &greater);
-
-  __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
-  __ jmp(&done);
+  __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less);  //  ucomis{s,d} sets CF (kBelow)
 
   __ Bind(&greater);
-  __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
+  __ movl(out, Immediate(1));
+  __ jmp(&done);
+
+  __ Bind(&less);
+  __ movl(out, Immediate(-1));
 
   __ Bind(&done);
 }
@@ -645,6 +1002,8 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
+  UNUSED(constant);
 }
 
 void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
@@ -654,6 +1013,30 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
+  // Will be generated at use site.
+  UNUSED(constant);
+}
+
+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.
+  UNUSED(constant);
+}
+
+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.
+  UNUSED(constant);
 }
 
 void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
@@ -661,6 +1044,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
+  UNUSED(ret);
   codegen_->GenerateFrameExit();
   __ ret();
 }
@@ -676,11 +1060,17 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
     case Primitive::kPrimLong:
-      locations->SetInAt(0, X86_64CpuLocation(RAX));
+      locations->SetInAt(0, Location::RegisterLocation(RAX));
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0,
+          Location::FpuRegisterLocation(XMM0));
       break;
 
     default:
-      LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+      LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
   }
 }
 
@@ -694,11 +1084,17 @@
       case Primitive::kPrimInt:
       case Primitive::kPrimNot:
       case Primitive::kPrimLong:
-        DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
+        break;
+
+      case Primitive::kPrimFloat:
+      case Primitive::kPrimDouble:
+        DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>().AsFloatRegister(),
+                  XMM0);
         break;
 
       default:
-        LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
+        LOG(FATAL) << "Unexpected return type " << ret->InputAt(0)->GetType();
     }
   }
   codegen_->GenerateFrameExit();
@@ -716,7 +1112,7 @@
       uint32_t index = gp_index_++;
       stack_index_++;
       if (index < calling_convention.GetNumberOfRegisters()) {
-        return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
+        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
       } else {
         return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
       }
@@ -727,17 +1123,32 @@
       stack_index_ += 2;
       if (index < calling_convention.GetNumberOfRegisters()) {
         gp_index_ += 1;
-        return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
+        return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
       } else {
         gp_index_ += 2;
         return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
       }
     }
 
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
-      LOG(FATAL) << "Unimplemented parameter type " << type;
-      break;
+    case Primitive::kPrimFloat: {
+      uint32_t index = fp_index_++;
+      stack_index_++;
+      if (index < calling_convention.GetNumberOfFpuRegisters()) {
+        return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
+      } else {
+        return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
+      }
+    }
+
+    case Primitive::kPrimDouble: {
+      uint32_t index = fp_index_++;
+      stack_index_ += 2;
+      if (index < calling_convention.GetNumberOfFpuRegisters()) {
+        return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
+      } else {
+        return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
+      }
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unexpected parameter type " << type;
@@ -746,44 +1157,38 @@
   return Location();
 }
 
-void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
+void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
+  IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
+  if (intrinsic.TryDispatch(invoke)) {
+    return;
+  }
+
   HandleInvoke(invoke);
 }
 
-void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
-  CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
-  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
-  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
-      invoke->GetIndexInDexCache() * heap_reference_size;
-
-  // 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;
-  LoadCurrentMethod(temp);
-  // temp = temp->dex_cache_resolved_methods_;
-  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
-  // temp = temp[index_in_cache]
-  __ movl(temp, Address(temp, index_in_cache));
-  // (temp + offset_of_quick_compiled_code)()
-  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
-
-  DCHECK(!codegen_->IsLeafMethod());
-  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86_64* codegen) {
+  if (invoke->GetLocations()->Intrinsified()) {
+    IntrinsicCodeGeneratorX86_64 intrinsic(codegen);
+    intrinsic.Dispatch(invoke);
+    return true;
+  }
+  return false;
 }
 
-void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  HandleInvoke(invoke);
+void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
+  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
+    return;
+  }
+
+  codegen_->GenerateStaticOrDirectCall(
+      invoke,
+      invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
 }
 
 void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(X86_64CpuLocation(RDI));
+  locations->AddTemp(Location::RegisterLocation(RDI));
 
   InvokeDexCallingConventionVisitor calling_convention_visitor;
   for (size_t i = 0; i < invoke->InputCount(); i++) {
@@ -799,7 +1204,7 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
     case Primitive::kPrimLong:
-      locations->SetOut(X86_64CpuLocation(RAX));
+      locations->SetOut(Location::RegisterLocation(RAX));
       break;
 
     case Primitive::kPrimVoid:
@@ -807,13 +1212,26 @@
 
     case Primitive::kPrimDouble:
     case Primitive::kPrimFloat:
-      LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
+      locations->SetOut(Location::FpuRegisterLocation(XMM0));
       break;
   }
 }
 
+void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  IntrinsicLocationsBuilderX86_64 intrinsic(GetGraph()->GetArena());
+  if (intrinsic.TryDispatch(invoke)) {
+    return;
+  }
+
+  HandleInvoke(invoke);
+}
+
 void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
+  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
+    return;
+  }
+
+  CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
   size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
           invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
   LocationSummary* locations = invoke->GetLocations();
@@ -821,20 +1239,589 @@
   size_t class_offset = mirror::Object::ClassOffset().SizeValue();
   // temp = object->GetClass();
   if (receiver.IsStackSlot()) {
-    __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
-    __ movq(temp, Address(temp, class_offset));
+    __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
+    __ movl(temp, Address(temp, class_offset));
   } else {
-    __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
+    __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
   }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
   // temp = temp->GetMethodAt(method_offset);
   __ movl(temp, Address(temp, method_offset));
   // call temp->GetEntryPoint();
-  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
+  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kX86_64WordSize).SizeValue()));
 
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
+  HandleInvoke(invoke);
+  // Add the hidden argument.
+  invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX));
+}
+
+void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
+  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
+  CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
+  uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+          (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  size_t class_offset = mirror::Object::ClassOffset().SizeValue();
+
+  // Set the hidden argument.
+  __ movq(invoke->GetLocations()->GetTemp(1).AsRegister<CpuRegister>(),
+          Immediate(invoke->GetDexMethodIndex()));
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
+    __ movl(temp, Address(temp, class_offset));
+  } else {
+    __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
+  }
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
+  // temp = temp->GetImtEntryAt(method_offset);
+  __ movl(temp, Address(temp, method_offset));
+  // call temp->GetEntryPoint();
+  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kX86_64WordSize).SizeValue()));
+
+  DCHECK(!codegen_->IsLeafMethod());
+  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:
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresFpuRegister());
+      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());
+      DCHECK(in.Equals(out));
+      __ negl(out.AsRegister<CpuRegister>());
+      break;
+
+    case Primitive::kPrimLong:
+      DCHECK(in.IsRegister());
+      DCHECK(in.Equals(out));
+      __ negq(out.AsRegister<CpuRegister>());
+      break;
+
+    case Primitive::kPrimFloat: {
+      DCHECK(in.Equals(out));
+      CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
+      XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+      // Implement float negation with an exclusive or with value
+      // 0x80000000 (mask for bit 31, representing the sign of a
+      // single-precision floating-point number).
+      __ movq(constant, Immediate(INT64_C(0x80000000)));
+      __ movd(mask, constant);
+      __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      DCHECK(in.Equals(out));
+      CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
+      XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+      // Implement double negation with an exclusive or with value
+      // 0x8000000000000000 (mask for bit 63, representing the sign of
+      // a double-precision floating-point number).
+      __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
+      __ movd(mask, constant);
+      __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  DCHECK_NE(result_type, input_type);
+  switch (result_type) {
+    case Primitive::kPrimByte:
+      switch (input_type) {
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-byte' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimShort:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-short' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-int' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-int' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-int' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-long' instruction.
+          // TODO: We would benefit from a (to-be-implemented)
+          // Location::RegisterOrStackSlot requirement for this input.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister());
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-long' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-long' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimChar:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // Processing a Dex `int-to-char' instruction.
+          locations->SetInAt(0, Location::Any());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    case Primitive::kPrimDouble:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresFpuRegister());
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations = conversion->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  DCHECK_NE(result_type, input_type);
+  switch (result_type) {
+    case Primitive::kPrimByte:
+      switch (input_type) {
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-byte' instruction.
+          if (in.IsRegister()) {
+            __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
+          } else if (in.IsStackSlot()) {
+            __ movsxb(out.AsRegister<CpuRegister>(),
+                      Address(CpuRegister(RSP), in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsIntConstant());
+            __ movl(out.AsRegister<CpuRegister>(),
+                    Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+          }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimShort:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-short' instruction.
+          if (in.IsRegister()) {
+            __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
+          } else if (in.IsStackSlot()) {
+            __ movsxw(out.AsRegister<CpuRegister>(),
+                      Address(CpuRegister(RSP), in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsIntConstant());
+            __ movl(out.AsRegister<CpuRegister>(),
+                    Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+          }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+      switch (input_type) {
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-int' instruction.
+          if (in.IsRegister()) {
+            __ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ movl(out.AsRegister<CpuRegister>(),
+                    Address(CpuRegister(RSP), in.GetStackIndex()));
+          } else {
+            DCHECK(in.IsConstant());
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
+          }
+          break;
+
+        case Primitive::kPrimFloat: {
+          // Processing a Dex `float-to-int' instruction.
+          XmmRegister input = in.AsFpuRegister<XmmRegister>();
+          CpuRegister output = out.AsRegister<CpuRegister>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          Label done, nan;
+
+          __ movl(output, Immediate(kPrimIntMax));
+          // temp = int-to-float(output)
+          __ cvtsi2ss(temp, output, false);
+          // if input >= temp goto done
+          __ comiss(input, temp);
+          __ j(kAboveEqual, &done);
+          // if input == NaN goto nan
+          __ j(kUnordered, &nan);
+          // output = float-to-int-truncate(input)
+          __ cvttss2si(output, input, false);
+          __ jmp(&done);
+          __ Bind(&nan);
+          //  output = 0
+          __ xorl(output, output);
+          __ Bind(&done);
+          break;
+        }
+
+        case Primitive::kPrimDouble: {
+          // Processing a Dex `double-to-int' instruction.
+          XmmRegister input = in.AsFpuRegister<XmmRegister>();
+          CpuRegister output = out.AsRegister<CpuRegister>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          Label done, nan;
+
+          __ movl(output, Immediate(kPrimIntMax));
+          // temp = int-to-double(output)
+          __ cvtsi2sd(temp, output);
+          // if input >= temp goto done
+          __ comisd(input, temp);
+          __ j(kAboveEqual, &done);
+          // if input == NaN goto nan
+          __ j(kUnordered, &nan);
+          // output = double-to-int-truncate(input)
+          __ cvttsd2si(output, input);
+          __ jmp(&done);
+          __ Bind(&nan);
+          //  output = 0
+          __ xorl(output, output);
+          __ Bind(&done);
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        DCHECK(out.IsRegister());
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-long' instruction.
+          DCHECK(in.IsRegister());
+          __ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
+          break;
+
+        case Primitive::kPrimFloat: {
+          // Processing a Dex `float-to-long' instruction.
+          XmmRegister input = in.AsFpuRegister<XmmRegister>();
+          CpuRegister output = out.AsRegister<CpuRegister>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          Label done, nan;
+
+          __ movq(output, Immediate(kPrimLongMax));
+          // temp = long-to-float(output)
+          __ cvtsi2ss(temp, output, true);
+          // if input >= temp goto done
+          __ comiss(input, temp);
+          __ j(kAboveEqual, &done);
+          // if input == NaN goto nan
+          __ j(kUnordered, &nan);
+          // output = float-to-long-truncate(input)
+          __ cvttss2si(output, input, true);
+          __ jmp(&done);
+          __ Bind(&nan);
+          //  output = 0
+          __ xorq(output, output);
+          __ Bind(&done);
+          break;
+        }
+
+        case Primitive::kPrimDouble: {
+          // Processing a Dex `double-to-long' instruction.
+          XmmRegister input = in.AsFpuRegister<XmmRegister>();
+          CpuRegister output = out.AsRegister<CpuRegister>();
+          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+          Label done, nan;
+
+          __ movq(output, Immediate(kPrimLongMax));
+          // temp = long-to-double(output)
+          __ cvtsi2sd(temp, output, true);
+          // if input >= temp goto done
+          __ comisd(input, temp);
+          __ j(kAboveEqual, &done);
+          // if input == NaN goto nan
+          __ j(kUnordered, &nan);
+          // output = double-to-long-truncate(input)
+          __ cvttsd2si(output, input, true);
+          __ jmp(&done);
+          __ Bind(&nan);
+          //  output = 0
+          __ xorq(output, output);
+          __ Bind(&done);
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimChar:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // Processing a Dex `int-to-char' instruction.
+          if (in.IsRegister()) {
+            __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
+          } else if (in.IsStackSlot()) {
+            __ movzxw(out.AsRegister<CpuRegister>(),
+                      Address(CpuRegister(RSP), in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsIntConstant());
+            __ movl(out.AsRegister<CpuRegister>(),
+                    Immediate(static_cast<uint16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+          }
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-float' instruction.
+          __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-float' instruction.
+          __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
+          break;
+
+        case Primitive::kPrimDouble:
+          // Processing a Dex `double-to-float' instruction.
+          __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    case Primitive::kPrimDouble:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+        case Primitive::kPrimChar:
+          // Processing a Dex `int-to-double' instruction.
+          __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
+          break;
+
+        case Primitive::kPrimLong:
+          // Processing a Dex `long-to-double' instruction.
+          __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
+          break;
+
+        case Primitive::kPrimFloat:
+          // Processing a Dex `float-to-double' instruction.
+          __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      };
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
 void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -845,6 +1832,7 @@
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
+
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
@@ -852,52 +1840,55 @@
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+    case Primitive::kPrimDouble:
+    case Primitive::kPrimFloat: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
       break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
   LocationSummary* locations = add->GetLocations();
-  DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
-            locations->Out().AsX86_64().AsCpuRegister().AsRegister());
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
   switch (add->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (locations->InAt(1).IsRegister()) {
-        __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
-                locations->InAt(1).AsX86_64().AsCpuRegister());
-      } else if (locations->InAt(1).IsConstant()) {
-        HConstant* instruction = locations->InAt(1).GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
+      if (second.IsRegister()) {
+        __ addl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ addl(first.AsRegister<CpuRegister>(), imm);
       } else {
-        __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
-                Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
+        __ addl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
       }
       break;
     }
+
     case Primitive::kPrimLong: {
-      __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
-              locations->InAt(1).AsX86_64().AsCpuRegister());
+      __ addq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
+      LOG(FATAL) << "Unexpected add type " << add->GetResultType();
   }
 }
 
@@ -917,65 +1908,508 @@
       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).AsX86_64().AsCpuRegister().AsRegister(),
-            locations->Out().AsX86_64().AsCpuRegister().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).AsX86_64().AsCpuRegister(),
-                locations->InAt(1).AsX86_64().AsCpuRegister());
-      } else if (locations->InAt(1).IsConstant()) {
-        HConstant* instruction = locations->InAt(1).GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
+      if (second.IsRegister()) {
+        __ subl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ subl(first.AsRegister<CpuRegister>(), imm);
       } else {
-        __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
-                Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
+        __ subl(first.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
       }
       break;
     }
     case Primitive::kPrimLong: {
-      __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
-              locations->InAt(1).AsX86_64().AsCpuRegister());
+      __ subq(first.AsRegister<CpuRegister>(), second.AsRegister<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.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<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.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ imull(first.AsRegister<CpuRegister>(), imm);
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ imull(first.AsRegister<CpuRegister>(),
+                 Address(CpuRegister(RSP), second.GetStackIndex()));
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      __ imulq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86_64::PushOntoFPStack(Location source, uint32_t temp_offset,
+                                                     uint32_t stack_adjustment, bool is_float) {
+  if (source.IsStackSlot()) {
+    DCHECK(is_float);
+    __ flds(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
+  } else if (source.IsDoubleStackSlot()) {
+    DCHECK(!is_float);
+    __ fldl(Address(CpuRegister(RSP), source.GetStackIndex() + stack_adjustment));
+  } else {
+    // Write the value to the temporary location on the stack and load to FP stack.
+    if (is_float) {
+      Location stack_temp = Location::StackSlot(temp_offset);
+      codegen_->Move(stack_temp, source);
+      __ flds(Address(CpuRegister(RSP), temp_offset));
+    } else {
+      Location stack_temp = Location::DoubleStackSlot(temp_offset);
+      codegen_->Move(stack_temp, source);
+      __ fldl(Address(CpuRegister(RSP), temp_offset));
+    }
+  }
+}
+
+void InstructionCodeGeneratorX86_64::GenerateRemFP(HRem *rem) {
+  Primitive::Type type = rem->GetResultType();
+  bool is_float = type == Primitive::kPrimFloat;
+  size_t elem_size = Primitive::ComponentSize(type);
+  LocationSummary* locations = rem->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  Location out = locations->Out();
+
+  // Create stack space for 2 elements.
+  // TODO: enhance register allocator to ask for stack temporaries.
+  __ subq(CpuRegister(RSP), Immediate(2 * elem_size));
+
+  // Load the values to the FP stack in reverse order, using temporaries if needed.
+  PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
+  PushOntoFPStack(first, 0, 2 * elem_size, is_float);
+
+  // Loop doing FPREM until we stabilize.
+  Label retry;
+  __ Bind(&retry);
+  __ fprem();
+
+  // Move FP status to AX.
+  __ fstsw();
+
+  // And see if the argument reduction is complete. This is signaled by the
+  // C2 FPU flag bit set to 0.
+  __ andl(CpuRegister(RAX), Immediate(kC2ConditionMask));
+  __ j(kNotEqual, &retry);
+
+  // We have settled on the final value. Retrieve it into an XMM register.
+  // Store FP top of stack to real stack.
+  if (is_float) {
+    __ fsts(Address(CpuRegister(RSP), 0));
+  } else {
+    __ fstl(Address(CpuRegister(RSP), 0));
+  }
+
+  // Pop the 2 items from the FP stack.
+  __ fucompp();
+
+  // Load the value from the stack into an XMM register.
+  DCHECK(out.IsFpuRegister()) << out;
+  if (is_float) {
+    __ movss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
+  } else {
+    __ movsd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), 0));
+  }
+
+  // And remove the temporary stack space we allocated.
+  __ addq(CpuRegister(RSP), Immediate(2 * elem_size));
+}
+
+void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  Primitive::Type type = instruction->GetResultType();
+  DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
+
+  bool is_div = instruction->IsDiv();
+  LocationSummary* locations = instruction->GetLocations();
+
+  CpuRegister out_reg = locations->Out().AsRegister<CpuRegister>();
+  CpuRegister second_reg = locations->InAt(1).AsRegister<CpuRegister>();
+
+  DCHECK_EQ(RAX, locations->InAt(0).AsRegister<CpuRegister>().AsRegister());
+  DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister());
+
+  SlowPathCodeX86_64* slow_path =
+      new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64(
+          out_reg.AsRegister(), type, is_div);
+  codegen_->AddSlowPath(slow_path);
+
+  // 0x80000000(00000000)/-1 triggers an arithmetic exception!
+  // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
+  // so it's safe to just use negl instead of more complex comparisons.
+  if (type == Primitive::kPrimInt) {
+    __ cmpl(second_reg, Immediate(-1));
+    __ j(kEqual, slow_path->GetEntryLabel());
+    // edx:eax <- sign-extended of eax
+    __ cdq();
+    // eax = quotient, edx = remainder
+    __ idivl(second_reg);
+  } else {
+    __ cmpq(second_reg, Immediate(-1));
+    __ j(kEqual, slow_path->GetEntryLabel());
+    // rdx:rax <- sign-extended of rax
+    __ cqo();
+    // rax = quotient, rdx = remainder
+    __ idivq(second_reg);
+  }
+
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
+  switch (div->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RegisterLocation(RAX));
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      // Intel uses edx:eax as the dividend.
+      locations->AddTemp(Location::RegisterLocation(RDX));
+      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 div type " << div->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
+  LocationSummary* locations = div->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  Primitive::Type type = div->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      GenerateDivRemIntegral(div);
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
+  }
+}
+
+void LocationsBuilderX86_64::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+  LocationSummary* locations =
+    new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
+
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RegisterLocation(RAX));
+      locations->SetInAt(1, Location::RequiresRegister());
+      // Intel uses rdx:rax as the dividend and puts the remainder in rdx
+      locations->SetOut(Location::RegisterLocation(RDX));
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::Any());
+      locations->SetInAt(1, Location::Any());
+      locations->SetOut(Location::RequiresFpuRegister());
+      locations->AddTemp(Location::RegisterLocation(RAX));
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected rem type " << type;
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) {
+  Primitive::Type type = rem->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      GenerateDivRemIntegral(rem);
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      GenerateRemFP(rem);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
+  }
+}
+
+void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::Any());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+  SlowPathCodeX86_64* slow_path =
+      new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
+  codegen_->AddSlowPath(slow_path);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location value = locations->InAt(0);
+
+  switch (instruction->GetType()) {
+    case Primitive::kPrimInt: {
+      if (value.IsRegister()) {
+        __ testl(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else if (value.IsStackSlot()) {
+        __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else {
+        DCHECK(value.IsConstant()) << value;
+        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+        __ jmp(slow_path->GetEntryLabel());
+        }
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      if (value.IsRegister()) {
+        __ testq(value.AsRegister<CpuRegister>(), value.AsRegister<CpuRegister>());
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else if (value.IsDoubleStackSlot()) {
+        __ cmpq(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
+        __ j(kEqual, slow_path->GetEntryLabel());
+      } else {
+        DCHECK(value.IsConstant()) << value;
+        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
+        __ jmp(slow_path->GetEntryLabel());
+        }
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
+  }
+}
+
+void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) {
+  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
+
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
+
+  switch (op->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      // The shift count needs to be in CL.
+      locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1)));
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) {
+  DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
+
+  LocationSummary* locations = op->GetLocations();
+  CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
+  Location second = locations->InAt(1);
+
+  switch (op->GetResultType()) {
+    case Primitive::kPrimInt: {
+      if (second.IsRegister()) {
+        CpuRegister second_reg = second.AsRegister<CpuRegister>();
+        if (op->IsShl()) {
+          __ shll(first_reg, second_reg);
+        } else if (op->IsShr()) {
+          __ sarl(first_reg, second_reg);
+        } else {
+          __ shrl(first_reg, second_reg);
+        }
+      } else {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
+        if (op->IsShl()) {
+          __ shll(first_reg, imm);
+        } else if (op->IsShr()) {
+          __ sarl(first_reg, imm);
+        } else {
+          __ shrl(first_reg, imm);
+        }
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      if (second.IsRegister()) {
+        CpuRegister second_reg = second.AsRegister<CpuRegister>();
+        if (op->IsShl()) {
+          __ shlq(first_reg, second_reg);
+        } else if (op->IsShr()) {
+          __ sarq(first_reg, second_reg);
+        } else {
+          __ shrq(first_reg, second_reg);
+        }
+      } else {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
+        if (op->IsShl()) {
+          __ shlq(first_reg, imm);
+        } else if (op->IsShr()) {
+          __ sarq(first_reg, imm);
+        } else {
+          __ shrq(first_reg, imm);
+        }
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
+  }
+}
+
+void LocationsBuilderX86_64::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) {
+  HandleShift(shl);
+}
+
+void LocationsBuilderX86_64::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) {
+  HandleShift(shr);
+}
+
+void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
+void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) {
+  HandleShift(ushr);
+}
+
 void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
-  locations->SetOut(X86_64CpuLocation(RAX));
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(Location::RegisterLocation(RAX));
 }
 
 void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
+  codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
   __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
 
   __ gs()->call(Address::Absolute(
@@ -985,6 +2419,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(2)));
+  locations->SetOut(Location::RegisterLocation(RAX));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
+  __ 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);
@@ -999,20 +2455,33 @@
 
 void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
   // Nothing to do, the parameter is already at its location.
+  UNUSED(instruction);
 }
 
-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();
-  DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
-            locations->Out().AsX86_64().AsCpuRegister().AsRegister());
-  __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
+void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
+  DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
+            locations->Out().AsRegister<CpuRegister>().AsRegister());
+  Location out = locations->Out();
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt:
+      __ notl(out.AsRegister<CpuRegister>());
+      break;
+
+    case Primitive::kPrimLong:
+      __ notq(out.AsRegister<CpuRegister>());
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
@@ -1025,203 +2494,333 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
+  UNUSED(instruction);
   LOG(FATAL) << "Unimplemented";
 }
 
-void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+void InstructionCodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
+  /*
+   * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
+   * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
+   * For those cases, all we need to ensure is that there is a scheduling barrier in place.
+   */
+  switch (kind) {
+    case MemBarrierKind::kAnyAny: {
+      __ mfence();
+      break;
+    }
+    case MemBarrierKind::kAnyStore:
+    case MemBarrierKind::kLoadAny:
+    case MemBarrierKind::kStoreStore: {
+      // nop
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected memory barier " << kind;
+  }
+}
+
+void LocationsBuilderX86_64::HandleFieldGet(HInstruction* instruction) {
+  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
+
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
+                                                    const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
+
+  LocationSummary* locations = instruction->GetLocations();
+  CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
+  Location out = locations->Out();
+  bool is_volatile = field_info.IsVolatile();
+  Primitive::Type field_type = field_info.GetFieldType();
+  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+  switch (field_type) {
+    case Primitive::kPrimBoolean: {
+      __ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimByte: {
+      __ movsxb(out.AsRegister<CpuRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimShort: {
+      __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimChar: {
+      __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      __ movl(out.AsRegister<CpuRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      __ movq(out.AsRegister<CpuRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
+      break;
+    }
+
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << field_type;
+      UNREACHABLE();
+  }
+
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
+  }
+}
+
+void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
+                                            const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
+
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  // Temporary registers for the write barrier.
-  if (instruction->GetFieldType() == Primitive::kPrimNot) {
+  if (needs_write_barrier) {
+    // Temporary registers for the write barrier.
     locations->AddTemp(Location::RequiresRegister());
     locations->AddTemp(Location::RequiresRegister());
   }
 }
 
-void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
+                                                    const FieldInfo& field_info) {
+  DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
+
   LocationSummary* locations = instruction->GetLocations();
-  CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
-  CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
-  size_t offset = instruction->GetFieldOffset().SizeValue();
-  Primitive::Type field_type = instruction->GetFieldType();
+  CpuRegister base = locations->InAt(0).AsRegister<CpuRegister>();
+  Location value = locations->InAt(1);
+  bool is_volatile = field_info.IsVolatile();
+  Primitive::Type field_type = field_info.GetFieldType();
+  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+  }
 
   switch (field_type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte: {
-      __ movb(Address(obj, offset), value);
+      __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
       break;
     }
 
     case Primitive::kPrimShort:
     case Primitive::kPrimChar: {
-      __ movw(Address(obj, offset), value);
+      __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
       break;
     }
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      __ movl(Address(obj, offset), value);
-      if (field_type == Primitive::kPrimNot) {
-        CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
-        CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
-        codegen_->MarkGCCard(temp, card, obj, value);
-      }
+      __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
       break;
     }
 
     case Primitive::kPrimLong: {
-      __ movq(Address(obj, offset), value);
+      __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << field_type;
+    case Primitive::kPrimFloat: {
+      __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
+      break;
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << field_type;
+      UNREACHABLE();
   }
+
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+    CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+    CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
+  }
+
+  if (is_volatile) {
+    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+  }
+}
+
+void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
+
+void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
 }
 
 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  HandleFieldGet(instruction);
 }
 
 void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
-  CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
-  size_t offset = instruction->GetFieldOffset().SizeValue();
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
 
-  switch (instruction->GetType()) {
-    case Primitive::kPrimBoolean: {
-      __ movzxb(out, Address(obj, offset));
-      break;
-    }
+void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  HandleFieldGet(instruction);
+}
 
-    case Primitive::kPrimByte: {
-      __ movsxb(out, Address(obj, offset));
-      break;
-    }
+void InstructionCodeGeneratorX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
+  HandleFieldGet(instruction, instruction->GetFieldInfo());
+}
 
-    case Primitive::kPrimShort: {
-      __ movsxw(out, Address(obj, offset));
-      break;
-    }
+void LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
+}
 
-    case Primitive::kPrimChar: {
-      __ movzxw(out, Address(obj, offset));
-      break;
-    }
-
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot: {
-      __ movl(out, Address(obj, offset));
-      break;
-    }
-
-    case Primitive::kPrimLong: {
-      __ movq(out, Address(obj, offset));
-      break;
-    }
-
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
-
-    case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
-  }
+void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  HandleFieldSet(instruction, instruction->GetFieldInfo());
 }
 
 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::Any());
-  // TODO: Have a normalization phase that makes this instruction never used.
-  locations->SetOut(Location::SameAsFirstInput());
+  Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
+      ? Location::RequiresRegister()
+      : Location::Any();
+  locations->SetInAt(0, loc);
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
 }
 
-void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
+void InstructionCodeGeneratorX86_64::GenerateImplicitNullCheck(HNullCheck* instruction) {
+  if (codegen_->CanMoveNullCheckToUser(instruction)) {
+    return;
+  }
+  LocationSummary* locations = instruction->GetLocations();
+  Location obj = locations->InAt(0);
+
+  __ testl(CpuRegister(RAX), Address(obj.AsRegister<CpuRegister>(), 0));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void InstructionCodeGeneratorX86_64::GenerateExplicitNullCheck(HNullCheck* instruction) {
+  SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
   codegen_->AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
-  DCHECK(obj.Equals(locations->Out()));
 
   if (obj.IsRegister()) {
-    __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
-  } else {
-    DCHECK(locations->InAt(0).IsStackSlot());
+    __ cmpl(obj.AsRegister<CpuRegister>(), Immediate(0));
+  } else if (obj.IsStackSlot()) {
     __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
+  } else {
+    DCHECK(obj.IsConstant()) << obj;
+    DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
+    __ jmp(slow_path->GetEntryLabel());
+    return;
   }
   __ j(kEqual, slow_path->GetEntryLabel());
 }
 
+void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
+  if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+    GenerateImplicitNullCheck(instruction);
+  } else {
+    GenerateExplicitNullCheck(instruction);
+  }
+}
+
 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* 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());
+  locations->SetInAt(
+      1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
+  CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
   Location index = locations->InAt(1);
 
   switch (instruction->GetType()) {
     case Primitive::kPrimBoolean: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
-      CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+      CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
         __ movzxb(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
       } else {
-        __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
+        __ movzxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimByte: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
-      CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+      CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
         __ movsxb(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
       } else {
-        __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
+        __ movsxb(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimShort: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
-      CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+      CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
         __ movsxw(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
       } else {
-        __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
+        __ movsxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimChar: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
-      CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+      CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
         __ movzxw(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
       } else {
-        __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
+        __ movzxw(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset));
       }
       break;
     }
@@ -1230,124 +2829,246 @@
     case Primitive::kPrimNot: {
       DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+      CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
         __ movl(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
       } else {
-        __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
+        __ movl(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
       }
       break;
     }
 
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
-      CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+      CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
         __ movq(out, Address(obj,
             (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
       } else {
-        __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
+        __ movq(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
       }
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+    case Primitive::kPrimFloat: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+      XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
+      if (index.IsConstant()) {
+        __ movss(out, Address(obj,
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
+      } else {
+        __ movss(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset));
+      }
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+      XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
+      if (index.IsConstant()) {
+        __ movsd(out, Address(obj,
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
+      } else {
+        __ movsd(out, Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset));
+      }
+      break;
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      UNREACHABLE();
   }
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
   Primitive::Type value_type = instruction->GetComponentType();
-  bool is_object = value_type == Primitive::kPrimNot;
+
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+  bool needs_runtime_call = instruction->NeedsTypeCheck();
+
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
-      instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
-  if (is_object) {
+      instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+  if (needs_runtime_call) {
     InvokeRuntimeCallingConvention calling_convention;
-    locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
-    locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
-    locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
+    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+    locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+    locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   } else {
     locations->SetInAt(0, Location::RequiresRegister());
-    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+    locations->SetInAt(
+        1, Location::RegisterOrConstant(instruction->InputAt(1)));
     locations->SetInAt(2, Location::RequiresRegister());
+    if (value_type == Primitive::kPrimLong) {
+      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)));
+    }
+
+    if (needs_write_barrier) {
+      // Temporary registers for the write barrier.
+      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());
+    }
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
+  CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
   Location index = locations->InAt(1);
+  Location value = locations->InAt(2);
   Primitive::Type value_type = instruction->GetComponentType();
+  bool needs_runtime_call = locations->WillCall();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
 
   switch (value_type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
-      CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
-        __ movb(Address(obj, offset), value);
+        if (value.IsRegister()) {
+          __ movb(Address(obj, offset), value.AsRegister<CpuRegister>());
+        } else {
+          __ movb(Address(obj, offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       } else {
-        __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
+        if (value.IsRegister()) {
+          __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
+                  value.AsRegister<CpuRegister>());
+        } else {
+          __ movb(Address(obj, index.AsRegister<CpuRegister>(), TIMES_1, data_offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
       break;
     }
 
     case Primitive::kPrimShort:
     case Primitive::kPrimChar: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
-      CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
-        __ movw(Address(obj, offset), value);
+        if (value.IsRegister()) {
+          __ movw(Address(obj, offset), value.AsRegister<CpuRegister>());
+        } else {
+          DCHECK(value.IsConstant()) << value;
+          __ movw(Address(obj, offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       } else {
-        __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
+        DCHECK(index.IsRegister()) << index;
+        if (value.IsRegister()) {
+          __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
+                  value.AsRegister<CpuRegister>());
+        } else {
+          DCHECK(value.IsConstant()) << value;
+          __ movw(Address(obj, index.AsRegister<CpuRegister>(), TIMES_2, data_offset),
+                  Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+        }
       }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
       break;
     }
 
-    case Primitive::kPrimInt: {
-      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
-      CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
-      if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-        __ movl(Address(obj, offset), value);
-      } else {
-        __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
-      }
-      break;
-    }
-
+    case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
-      DCHECK(!codegen_->IsLeafMethod());
-      codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+      if (!needs_runtime_call) {
+        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+        if (index.IsConstant()) {
+          size_t offset =
+              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        } else {
+          DCHECK(index.IsRegister()) << index;
+          if (value.IsRegister()) {
+            __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
+                    value.AsRegister<CpuRegister>());
+          } else {
+            DCHECK(value.IsConstant()) << value;
+            __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
+                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+          }
+        }
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (needs_write_barrier) {
+          DCHECK_EQ(value_type, Primitive::kPrimNot);
+          CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+          CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
+          codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
+        }
+      } else {
+        DCHECK_EQ(value_type, Primitive::kPrimNot);
+        __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
+                                        true));
+        DCHECK(!codegen_->IsLeafMethod());
+        codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+      }
       break;
     }
 
     case Primitive::kPrimLong: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
-      CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
       if (index.IsConstant()) {
         size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
-        __ movq(Address(obj, offset), value);
+        DCHECK(value.IsRegister());
+        __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
       } else {
-        __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
+        DCHECK(value.IsRegister());
+        __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
+                value.AsRegister<CpuRegister>());
       }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+    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.AsFpuRegister<XmmRegister>());
+      } else {
+        DCHECK(value.IsFpuRegister());
+        __ movss(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
+                value.AsFpuRegister<XmmRegister>());
+      }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+      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.AsFpuRegister<XmmRegister>());
+      } else {
+        DCHECK(value.IsFpuRegister());
+        __ movsd(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
+                value.AsFpuRegister<XmmRegister>());
+      }
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+      break;
+    }
 
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      UNREACHABLE();
   }
 }
 
@@ -1355,15 +3076,16 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations = instruction->GetLocations();
   uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
-  CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
-  CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+  CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
   __ movl(out, Address(obj, offset));
+  codegen_->MaybeRecordImplicitNullCheck(instruction);
 }
 
 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -1371,18 +3093,19 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
-  // TODO: Have a normalization phase that makes this instruction never used.
-  locations->SetOut(Location::SameAsFirstInput());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
 }
 
 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);
 
-  CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
-  CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
+  CpuRegister index = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister length = locations->InAt(1).AsRegister<CpuRegister>();
 
   __ cmpl(index, length);
   __ j(kAboveEqual, slow_path->GetEntryLabel());
@@ -1409,9 +3132,11 @@
 
 void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
   // Nothing to do, this is driven by the code generator.
+  UNUSED(temp);
 }
 
 void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
+  UNUSED(instruction);
   LOG(FATAL) << "Unimplemented";
 }
 
@@ -1464,18 +3189,21 @@
 
   if (source.IsRegister()) {
     if (destination.IsRegister()) {
-      __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
+      __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
     } else if (destination.IsStackSlot()) {
       __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
-              source.AsX86_64().AsCpuRegister());
+              source.AsRegister<CpuRegister>());
     } else {
       DCHECK(destination.IsDoubleStackSlot());
       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
-              source.AsX86_64().AsCpuRegister());
+              source.AsRegister<CpuRegister>());
     }
   } else if (source.IsStackSlot()) {
     if (destination.IsRegister()) {
-      __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
+      __ movl(destination.AsRegister<CpuRegister>(),
+              Address(CpuRegister(RSP), source.GetStackIndex()));
+    } else if (destination.IsFpuRegister()) {
+      __ movss(destination.AsFpuRegister<XmmRegister>(),
               Address(CpuRegister(RSP), source.GetStackIndex()));
     } else {
       DCHECK(destination.IsStackSlot());
@@ -1484,10 +3212,13 @@
     }
   } else if (source.IsDoubleStackSlot()) {
     if (destination.IsRegister()) {
-      __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
+      __ movq(destination.AsRegister<CpuRegister>(),
               Address(CpuRegister(RSP), source.GetStackIndex()));
+    } else if (destination.IsFpuRegister()) {
+      __ movsd(destination.AsFpuRegister<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));
     }
@@ -1496,23 +3227,52 @@
     if (constant->IsIntConstant()) {
       Immediate imm(constant->AsIntConstant()->GetValue());
       if (destination.IsRegister()) {
-        __ movl(destination.AsX86_64().AsCpuRegister(), imm);
+        __ movl(destination.AsRegister<CpuRegister>(), imm);
       } else {
+        DCHECK(destination.IsStackSlot()) << destination;
         __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
       }
     } else if (constant->IsLongConstant()) {
       int64_t value = constant->AsLongConstant()->GetValue();
       if (destination.IsRegister()) {
-        __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
+        __ movq(destination.AsRegister<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.AsFpuRegister<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.AsFpuRegister<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.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
+    } else if (destination.IsStackSlot()) {
+      __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
+               source.AsFpuRegister<XmmRegister>());
+    } else {
+      DCHECK(destination.IsDoubleStackSlot()) << destination;
+      __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
+               source.AsFpuRegister<XmmRegister>());
+    }
   }
 }
 
@@ -1554,27 +3314,51 @@
           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();
   Location destination = move->GetDestination();
 
   if (source.IsRegister() && destination.IsRegister()) {
-    __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
+    __ xchgq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
   } else if (source.IsRegister() && destination.IsStackSlot()) {
-    Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
+    Exchange32(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
   } else if (source.IsStackSlot() && destination.IsRegister()) {
-    Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
+    Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
   } else if (source.IsStackSlot() && destination.IsStackSlot()) {
     Exchange32(destination.GetStackIndex(), source.GetStackIndex());
   } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
-    Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
+    Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
   } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
-    Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
+    Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
     Exchange64(destination.GetStackIndex(), source.GetStackIndex());
+  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
+    __ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
+    __ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
+    __ movd(destination.AsFpuRegister<XmmRegister>(), CpuRegister(TMP));
+  } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
+    Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
+  } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
+    Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
+  } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
+    Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
+  } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
+    Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
   } else {
-    LOG(FATAL) << "Unimplemented";
+    LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
   }
 }
 
@@ -1588,5 +3372,296 @@
   __ popq(CpuRegister(reg));
 }
 
+void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
+    SlowPathCodeX86_64* slow_path, CpuRegister class_reg) {
+  __ cmpl(Address(class_reg,  mirror::Class::StatusOffset().Int32Value()),
+          Immediate(mirror::Class::kStatusInitialized));
+  __ j(kLess, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+  // No need for memory fence, thanks to the X86_64 memory model.
+}
+
+void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
+  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
+      ? LocationSummary::kCallOnSlowPath
+      : LocationSummary::kNoCall;
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
+  CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
+  if (cls->IsReferrersClass()) {
+    DCHECK(!cls->CanCallRuntime());
+    DCHECK(!cls->MustGenerateClinitCheck());
+    codegen_->LoadCurrentMethod(out);
+    __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
+  } else {
+    DCHECK(cls->CanCallRuntime());
+    codegen_->LoadCurrentMethod(out);
+    __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
+    __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+    SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+    codegen_->AddSlowPath(slow_path);
+    __ testl(out, out);
+    __ j(kEqual, slow_path->GetEntryLabel());
+    if (cls->MustGenerateClinitCheck()) {
+      GenerateClassInitializationCheck(slow_path, out);
+    } else {
+      __ Bind(slow_path->GetExitLabel());
+    }
+  }
+}
+
+void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (check->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
+  // We assume the class to not be null.
+  SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
+      check->GetLoadClass(), check, check->GetDexPc(), true);
+  codegen_->AddSlowPath(slow_path);
+  GenerateClassInitializationCheck(slow_path,
+                                   check->GetLocations()->InAt(0).AsRegister<CpuRegister>());
+}
+
+void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
+  SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
+  codegen_->AddSlowPath(slow_path);
+
+  CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
+  codegen_->LoadCurrentMethod(CpuRegister(out));
+  __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
+  __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
+  __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  __ testl(out, out);
+  __ j(kEqual, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
+  Address address = Address::Absolute(
+      Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
+  __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
+  __ gs()->movl(address, Immediate(0));
+}
+
+void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
+  __ gs()->call(
+        Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary::CallKind call_kind = instruction->IsClassFinal()
+      ? LocationSummary::kNoCall
+      : LocationSummary::kCallOnSlowPath;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
+  Location cls = locations->InAt(1);
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  Label done, zero;
+  SlowPathCodeX86_64* slow_path = nullptr;
+
+  // Return 0 if `obj` is null.
+  // TODO: avoid this check if we know obj is not null.
+  __ testl(obj, obj);
+  __ j(kEqual, &zero);
+  // Compare the class of `obj` with `cls`.
+  __ movl(out, Address(obj, class_offset));
+  if (cls.IsRegister()) {
+    __ cmpl(out, cls.AsRegister<CpuRegister>());
+  } else {
+    DCHECK(cls.IsStackSlot()) << cls;
+    __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex()));
+  }
+  if (instruction->IsClassFinal()) {
+    // Classes must be equal for the instanceof to succeed.
+    __ j(kNotEqual, &zero);
+    __ movl(out, Immediate(1));
+    __ jmp(&done);
+  } else {
+    // If the classes are not equal, we go into a slow path.
+    DCHECK(locations->OnlyCallsOnSlowPath());
+    slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
+        instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
+    codegen_->AddSlowPath(slow_path);
+    __ j(kNotEqual, slow_path->GetEntryLabel());
+    __ movl(out, Immediate(1));
+    __ jmp(&done);
+  }
+  __ Bind(&zero);
+  __ movl(out, Immediate(0));
+  if (slow_path != nullptr) {
+    __ Bind(slow_path->GetExitLabel());
+  }
+  __ Bind(&done);
+}
+
+void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
+      instruction, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
+  Location cls = locations->InAt(1);
+  CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86_64(
+      instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
+  codegen_->AddSlowPath(slow_path);
+
+  // TODO: avoid this check if we know obj is not null.
+  __ testl(obj, obj);
+  __ j(kEqual, slow_path->GetExitLabel());
+  // Compare the class of `obj` with `cls`.
+  __ movl(temp, Address(obj, class_offset));
+  if (cls.IsRegister()) {
+    __ cmpl(temp, cls.AsRegister<CpuRegister>());
+  } else {
+    DCHECK(cls.IsStackSlot()) << cls;
+    __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
+  }
+  // Classes must be equal for the checkcast to succeed.
+  __ j(kNotEqual, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetExitLabel());
+}
+
+void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
+  __ gs()->call(Address::Absolute(instruction->IsEnter()
+        ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pLockObject)
+        : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pUnlockObject),
+      true));
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
+void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+
+void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (instruction->GetType() == Primitive::kPrimInt) {
+    locations->SetInAt(1, Location::Any());
+  } else {
+    // Request a register to avoid loading a 64bits constant.
+    locations->SetInAt(1, Location::RequiresRegister());
+  }
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    if (second.IsRegister()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+      }
+    } else if (second.IsConstant()) {
+      Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegister<CpuRegister>(), imm);
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegister<CpuRegister>(), imm);
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegister<CpuRegister>(), imm);
+      }
+    } else {
+      Address address(CpuRegister(RSP), second.GetStackIndex());
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegister<CpuRegister>(), address);
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegister<CpuRegister>(), address);
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegister<CpuRegister>(), address);
+      }
+    }
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    if (instruction->IsAnd()) {
+      __ andq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+    } else if (instruction->IsOr()) {
+      __ orq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+    } else {
+      DCHECK(instruction->IsXor());
+      __ xorq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+    }
+  }
+}
+
 }  // namespace x86_64
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index a299cf6..ead771a 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -18,6 +18,8 @@
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_
 
 #include "code_generator.h"
+#include "dex/compiler_enums.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "parallel_move_resolver.h"
 #include "utils/x86_64/assembler_x86_64.h"
@@ -25,16 +27,25 @@
 namespace art {
 namespace x86_64 {
 
-static constexpr size_t kX86_64WordSize = 8;
+// Use a local definition to prevent copying mistakes.
+static constexpr size_t kX86_64WordSize = kX86_64PointerSize;
 
 static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 };
+static constexpr FloatRegister kParameterFloatRegisters[] =
+    { XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7 };
 
 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+static constexpr size_t kParameterFloatRegistersLength = arraysize(kParameterFloatRegisters);
 
-class InvokeDexCallingConvention : public CallingConvention<Register> {
+static constexpr bool kCoalescedImplicitNullCheck = false;
+
+class InvokeDexCallingConvention : public CallingConvention<Register, FloatRegister> {
  public:
-  InvokeDexCallingConvention()
-      : CallingConvention(kParameterCoreRegisters, kParameterCoreRegistersLength) {}
+  InvokeDexCallingConvention() : CallingConvention(
+      kParameterCoreRegisters,
+      kParameterCoreRegistersLength,
+      kParameterFloatRegisters,
+      kParameterFloatRegistersLength) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
@@ -42,13 +53,17 @@
 
 class InvokeDexCallingConventionVisitor {
  public:
-  InvokeDexCallingConventionVisitor() : gp_index_(0), stack_index_(0) {}
+  InvokeDexCallingConventionVisitor() : gp_index_(0), fp_index_(0), stack_index_(0) {}
 
   Location GetNextLocation(Primitive::Type type);
 
  private:
   InvokeDexCallingConvention calling_convention;
+  // The current index for cpu registers.
   uint32_t gp_index_;
+  // The current index for fpu registers.
+  uint32_t fp_index_;
+  // The current stack index.
   uint32_t stack_index_;
 
   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor);
@@ -56,22 +71,38 @@
 
 class CodeGeneratorX86_64;
 
+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 ParallelMoveResolverX86_64 : public ParallelMoveResolver {
  public:
   ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen)
       : ParallelMoveResolver(allocator), codegen_(codegen) {}
 
-  virtual void EmitMove(size_t index) OVERRIDE;
-  virtual void EmitSwap(size_t index) OVERRIDE;
-  virtual void SpillScratch(int reg) OVERRIDE;
-  virtual void RestoreScratch(int reg) OVERRIDE;
+  void EmitMove(size_t index) OVERRIDE;
+  void EmitSwap(size_t index) OVERRIDE;
+  void SpillScratch(int reg) OVERRIDE;
+  void RestoreScratch(int reg) OVERRIDE;
 
   X86_64Assembler* GetAssembler() const;
 
  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_;
@@ -84,16 +115,20 @@
   LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen)
       : HGraphVisitor(graph), codegen_(codegen) {}
 
-#define DECLARE_VISIT_INSTRUCTION(name)     \
-  virtual void Visit##name(H##name* instr);
+#define DECLARE_VISIT_INSTRUCTION(name, super)     \
+  void Visit##name(H##name* instr) OVERRIDE;
 
   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void HandleInvoke(HInvoke* invoke);
-
  private:
+  void HandleInvoke(HInvoke* invoke);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
+  void HandleShift(HBinaryOperation* operation);
+  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldGet(HInstruction* instruction);
+
   CodeGeneratorX86_64* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
 
@@ -104,15 +139,13 @@
  public:
   InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen);
 
-#define DECLARE_VISIT_INSTRUCTION(name)     \
-  virtual void Visit##name(H##name* instr);
+#define DECLARE_VISIT_INSTRUCTION(name, super)     \
+  void Visit##name(H##name* instr) OVERRIDE;
 
   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void LoadCurrentMethod(CpuRegister reg);
-
   X86_64Assembler* GetAssembler() const { return assembler_; }
 
  private:
@@ -120,6 +153,18 @@
   // is the block to branch to if the suspend check is not needed, and after
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
+  void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
+  void GenerateRemFP(HRem *rem);
+  void GenerateDivRemIntegral(HBinaryOperation* instruction);
+  void HandleShift(HBinaryOperation* operation);
+  void GenerateMemoryBarrier(MemBarrierKind kind);
+  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
+  void GenerateImplicitNullCheck(HNullCheck* instruction);
+  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void PushOntoFPStack(Location source, uint32_t temp_offset,
+                       uint32_t stack_adjustment, bool is_float);
 
   X86_64Assembler* const assembler_;
   CodeGeneratorX86_64* const codegen_;
@@ -129,59 +174,56 @@
 
 class CodeGeneratorX86_64 : public CodeGenerator {
  public:
-  explicit CodeGeneratorX86_64(HGraph* graph);
+  CodeGeneratorX86_64(HGraph* graph, const CompilerOptions& compiler_options);
   virtual ~CodeGeneratorX86_64() {}
 
-  virtual void GenerateFrameEntry() OVERRIDE;
-  virtual void GenerateFrameExit() OVERRIDE;
-  virtual void Bind(Label* label) 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;
+  void GenerateFrameEntry() OVERRIDE;
+  void GenerateFrameExit() OVERRIDE;
+  void Bind(HBasicBlock* block) OVERRIDE;
+  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
-  virtual size_t GetWordSize() const OVERRIDE {
+  size_t GetWordSize() const OVERRIDE {
     return kX86_64WordSize;
   }
 
-  virtual size_t FrameEntrySpillSize() const OVERRIDE;
+  size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
+    return kX86_64WordSize;
+  }
 
-  virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+  size_t FrameEntrySpillSize() const OVERRIDE;
+
+  HGraphVisitor* GetLocationBuilder() OVERRIDE {
     return &location_builder_;
   }
 
-  virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+  HGraphVisitor* GetInstructionVisitor() OVERRIDE {
     return &instruction_visitor_;
   }
 
-  virtual X86_64Assembler* GetAssembler() OVERRIDE {
+  X86_64Assembler* GetAssembler() OVERRIDE {
     return &assembler_;
   }
 
-  ParallelMoveResolverX86_64* GetMoveResolver() {
+  ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE {
     return &move_resolver_;
   }
 
-  virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
-
-  virtual size_t GetNumberOfRegisters() const OVERRIDE {
-    return kNumberOfRegIds;
+  uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+    return GetLabelOf(block)->Position();
   }
 
-  virtual size_t GetNumberOfCoreRegisters() const OVERRIDE {
-    return kNumberOfCpuRegisters;
-  }
+  Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
 
-  virtual size_t GetNumberOfFloatingPointRegisters() const OVERRIDE {
-    return kNumberOfFloatRegisters;
-  }
+  void SetupBlockedRegisters() const OVERRIDE;
+  Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+  void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+  void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
 
-  virtual void SetupBlockedRegisters(bool* blocked_registers) const OVERRIDE;
-  virtual ManagedRegister AllocateFreeRegister(
-      Primitive::Type type, bool* blocked_registers) const OVERRIDE;
-  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 {
+  InstructionSet GetInstructionSet() const OVERRIDE {
     return InstructionSet::kX86_64;
   }
 
@@ -191,7 +233,25 @@
   // Helper method to move a value between two locations.
   void Move(Location destination, Location source);
 
+  void LoadCurrentMethod(CpuRegister reg);
+
+  Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_.GetRawStorage() + block->GetBlockId();
+  }
+
+  void Initialize() OVERRIDE {
+    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
+  }
+
+  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
+    return false;
+  }
+
+  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, CpuRegister temp);
+
  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 7161eed..aa4fc8f 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -14,16 +14,26 @@
  * limitations under the License.
  */
 
+#include <functional>
+
+#include "arch/instruction_set.h"
+#include "arch/arm/instruction_set_features_arm.h"
+#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"
 #include "dex_file.h"
 #include "dex_instruction.h"
-#include "instruction_set.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
+#include "prepare_for_register_allocation.h"
+#include "register_allocator.h"
+#include "ssa_liveness_analysis.h"
+#include "utils.h"
 
 #include "gtest/gtest.h"
 
@@ -31,7 +41,7 @@
 
 class InternalCodeAllocator : public CodeAllocator {
  public:
-  InternalCodeAllocator() { }
+  InternalCodeAllocator() : size_(0) { }
 
   virtual uint8_t* Allocate(size_t size) {
     size_ = size;
@@ -49,20 +59,96 @@
   DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
 };
 
+template <typename Expected>
 static void Run(const InternalCodeAllocator& allocator,
                 const CodeGenerator& codegen,
                 bool has_result,
-                int32_t expected) {
-  typedef int32_t (*fptr)();
+                Expected expected) {
+  typedef Expected (*fptr)();
   CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
   fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
   if (codegen.GetInstructionSet() == kThumb2) {
     // For thumb we need the bottom bit set.
     f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
   }
-  int32_t result = f();
+  Expected result = f();
   if (has_result) {
-    CHECK_EQ(result, expected);
+    ASSERT_EQ(result, expected);
+  }
+}
+
+template <typename Expected>
+static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) {
+  InternalCodeAllocator allocator;
+
+  CompilerOptions compiler_options;
+  x86::CodeGeneratorX86 codegenX86(graph, compiler_options);
+  // We avoid doing a stack overflow check that requires the runtime being setup,
+  // by making sure the compiler knows the methods we are running are leaf methods.
+  codegenX86.CompileBaseline(&allocator, true);
+  if (kRuntimeISA == kX86) {
+    Run(allocator, codegenX86, has_result, expected);
+  }
+
+  std::unique_ptr<const ArmInstructionSetFeatures> features(
+      ArmInstructionSetFeatures::FromCppDefines());
+  arm::CodeGeneratorARM codegenARM(graph, *features.get(), compiler_options);
+  codegenARM.CompileBaseline(&allocator, true);
+  if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) {
+    Run(allocator, codegenARM, has_result, expected);
+  }
+
+  x86_64::CodeGeneratorX86_64 codegenX86_64(graph, compiler_options);
+  codegenX86_64.CompileBaseline(&allocator, true);
+  if (kRuntimeISA == kX86_64) {
+    Run(allocator, codegenX86_64, has_result, expected);
+  }
+
+  arm64::CodeGeneratorARM64 codegenARM64(graph, compiler_options);
+  codegenARM64.CompileBaseline(&allocator, true);
+  if (kRuntimeISA == kArm64) {
+    Run(allocator, codegenARM64, has_result, expected);
+  }
+}
+
+template <typename Expected>
+static void RunCodeOptimized(CodeGenerator* codegen,
+                             HGraph* graph,
+                             std::function<void(HGraph*)> hook_before_codegen,
+                             bool has_result,
+                             Expected expected) {
+  SsaLivenessAnalysis liveness(*graph, codegen);
+  liveness.Analyze();
+
+  RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
+  register_allocator.AllocateRegisters();
+  hook_before_codegen(graph);
+
+  InternalCodeAllocator allocator;
+  codegen->CompileOptimized(&allocator);
+  Run(allocator, *codegen, has_result, expected);
+}
+
+template <typename Expected>
+static void RunCodeOptimized(HGraph* graph,
+                             std::function<void(HGraph*)> hook_before_codegen,
+                             bool has_result,
+                             Expected expected) {
+  CompilerOptions compiler_options;
+  if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) {
+    arm::CodeGeneratorARM codegenARM(graph,
+                                     *ArmInstructionSetFeatures::FromCppDefines(),
+                                     compiler_options);
+    RunCodeOptimized(&codegenARM, graph, hook_before_codegen, has_result, expected);
+  } else if (kRuntimeISA == kArm64) {
+    arm64::CodeGeneratorARM64 codegenARM64(graph, compiler_options);
+    RunCodeOptimized(&codegenARM64, graph, hook_before_codegen, has_result, expected);
+  } else if (kRuntimeISA == kX86) {
+    x86::CodeGeneratorX86 codegenX86(graph, compiler_options);
+    RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected);
+  } else if (kRuntimeISA == kX86_64) {
+    x86_64::CodeGeneratorX86_64 codegenX86_64(graph, compiler_options);
+    RunCodeOptimized(&codegenX86_64, graph, hook_before_codegen, has_result, expected);
   }
 }
 
@@ -72,30 +158,22 @@
   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);
+  RunCodeBaseline(graph, has_result, expected);
+}
+
+static void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) {
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  HGraphBuilder builder(&arena, Primitive::kPrimLong);
+  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
+  HGraph* graph = builder.BuildGraph(*item);
   ASSERT_NE(graph, nullptr);
-  InternalCodeAllocator allocator;
-
-  x86::CodeGeneratorX86 codegenX86(graph);
-  // We avoid doing a stack overflow check that requires the runtime being setup,
-  // by making sure the compiler knows the methods we are running are leaf methods.
-  codegenX86.CompileBaseline(&allocator, true);
-  if (kRuntimeISA == kX86) {
-    Run(allocator, codegenX86, has_result, expected);
-  }
-
-  arm::CodeGeneratorARM codegenARM(graph);
-  codegenARM.CompileBaseline(&allocator, true);
-  if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) {
-    Run(allocator, codegenARM, has_result, expected);
-  }
-
-  x86_64::CodeGeneratorX86_64 codegenX86_64(graph);
-  codegenX86_64.CompileBaseline(&allocator, true);
-  if (kRuntimeISA == kX86_64) {
-    Run(allocator, codegenX86_64, has_result, expected);
-  }
+  // Remove suspend checks, they cannot be executed in this context.
+  RemoveSuspendChecks(graph);
+  RunCodeBaseline(graph, has_result, expected);
 }
 
 TEST(CodegenTest, ReturnVoid) {
@@ -218,6 +296,100 @@
   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 = Low16Bits(input);           \
+  const uint16_t input_hi = High16Bits(input);          \
+  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(ReturnNotIntINT32_MIN, -2147483648, 2147483647)  // (2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646)  // (2^31) - 2
+NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647)  // -(2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648)  // -(2^31)
+
+#undef NOT_INT_TEST
+
+// Exercise bit-wise (one's complement) not-long instruction.
+#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT)                 \
+TEST(CodegenTest, TEST_NAME) {                                           \
+  const int64_t input = INPUT;                                           \
+  const uint16_t word0 = Low16Bits(Low32Bits(input));   /* LSW. */       \
+  const uint16_t word1 = High16Bits(Low32Bits(input));                   \
+  const uint16_t word2 = Low16Bits(High32Bits(input));                   \
+  const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */       \
+  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(                      \
+      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,      \
+      Instruction::NOT_LONG | 2 << 8 | 0 << 12,                          \
+      Instruction::RETURN_WIDE | 2 << 8);                                \
+                                                                         \
+  TestCodeLong(data, true, EXPECTED_OUTPUT);                             \
+}
+
+NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
+NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
+NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
+NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
+
+NOT_LONG_TEST(ReturnNotLongINT32_MIN,
+              INT64_C(-2147483648),
+              INT64_C(2147483647))  // (2^31) - 1
+NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
+              INT64_C(-2147483647),
+              INT64_C(2147483646))  // (2^31) - 2
+NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
+              INT64_C(2147483646),
+              INT64_C(-2147483647))  // -(2^31) - 1
+NOT_LONG_TEST(ReturnNotLongINT32_MAX,
+              INT64_C(2147483647),
+              INT64_C(-2147483648))  // -(2^31)
+
+// Note that the C++ compiler won't accept
+// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
+// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
+NOT_LONG_TEST(ReturnNotINT64_MIN,
+              INT64_C(-9223372036854775807)-1,
+              INT64_C(9223372036854775807));  // (2^63) - 1
+NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
+              INT64_C(-9223372036854775807),
+              INT64_C(9223372036854775806));  // (2^63) - 2
+NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
+              INT64_C(9223372036854775806),
+              INT64_C(-9223372036854775807));  // -(2^63) - 1
+NOT_LONG_TEST(ReturnNotLongINT64_MAX,
+              INT64_C(9223372036854775807),
+              INT64_C(-9223372036854775807)-1);  // -(2^63)
+
+#undef NOT_LONG_TEST
+
+TEST(CodegenTest, IntToLongOfLongToInt) {
+  const int64_t input = INT64_C(4294967296);             // 2^32
+  const uint16_t word0 = Low16Bits(Low32Bits(input));    // LSW.
+  const uint16_t word1 = High16Bits(Low32Bits(input));
+  const uint16_t word2 = Low16Bits(High32Bits(input));
+  const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
+  const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
+      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
+      Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
+      Instruction::ADD_LONG | 0, 0 << 8 | 2,             // v0 <- 2^32 + 1
+      Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
+      Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
+      Instruction::RETURN_WIDE | 2 << 8);
+
+  TestCodeLong(data, true, 1);
+}
+
 TEST(CodegenTest, ReturnAdd1) {
   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
@@ -256,4 +428,233 @@
   TestCode(data, true, 7);
 }
 
+TEST(CodegenTest, NonMaterializedCondition) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  entry->AddInstruction(new (&allocator) HGoto());
+
+  HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(first_block);
+  entry->AddSuccessor(first_block);
+  HIntConstant* constant0 = new (&allocator) HIntConstant(0);
+  entry->AddInstruction(constant0);
+  HIntConstant* constant1 = new (&allocator) HIntConstant(1);
+  entry->AddInstruction(constant1);
+  HEqual* equal = new (&allocator) HEqual(constant0, constant0);
+  first_block->AddInstruction(equal);
+  first_block->AddInstruction(new (&allocator) HIf(equal));
+
+  HBasicBlock* then = new (&allocator) HBasicBlock(graph);
+  HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
+  HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
+
+  graph->AddBlock(then);
+  graph->AddBlock(else_);
+  graph->AddBlock(exit);
+  first_block->AddSuccessor(then);
+  first_block->AddSuccessor(else_);
+  then->AddSuccessor(exit);
+  else_->AddSuccessor(exit);
+
+  exit->AddInstruction(new (&allocator) HExit());
+  then->AddInstruction(new (&allocator) HReturn(constant0));
+  else_->AddInstruction(new (&allocator) HReturn(constant1));
+
+  ASSERT_TRUE(equal->NeedsMaterialization());
+  graph->BuildDominatorTree();
+  PrepareForRegisterAllocation(graph).Run();
+  ASSERT_FALSE(equal->NeedsMaterialization());
+
+  auto hook_before_codegen = [](HGraph* graph_in) {
+    HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0);
+    HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
+    block->InsertInstructionBefore(move, block->GetLastInstruction());
+  };
+
+  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);                         \
+  }
+
+MUL_TEST(INT, MulInt);
+MUL_TEST(LONG, MulLong);
+
+TEST(CodegenTest, ReturnMulIntLit8) {
+  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);
+}
+
+TEST(CodegenTest, ReturnMulIntLit16) {
+  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_in) {
+      HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0);
+      HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->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_in) {
+      HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors().Get(0);
+      HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
+      block->InsertInstructionBefore(move, block->GetLastInstruction());
+    };
+
+    RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+  }
+}
+
+TEST(CodegenTest, ReturnDivIntLit8) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 4 << 12 | 0 << 8,
+    Instruction::DIV_INT_LIT8, 3 << 8 | 0,
+    Instruction::RETURN);
+
+  TestCode(data, true, 1);
+}
+
+TEST(CodegenTest, ReturnDivInt2Addr) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 4 << 12 | 0,
+    Instruction::CONST_4 | 2 << 12 | 1 << 8,
+    Instruction::DIV_INT_2ADDR | 1 << 12,
+    Instruction::RETURN);
+
+  TestCode(data, true, 2);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
new file mode 100644
index 0000000..fca9933
--- /dev/null
+++ b/compiler/optimizing/constant_folding.cc
@@ -0,0 +1,55 @@
+/*
+ * 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 "constant_folding.h"
+
+namespace art {
+
+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
+  // instruction into a constant as well.
+  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    // Traverse this block's instructions in (forward) order and
+    // replace the ones that can be statically evaluated by a
+    // compile-time counterpart.
+    for (HInstructionIterator inst_it(block->GetInstructions());
+         !inst_it.Done(); inst_it.Advance()) {
+      HInstruction* inst = inst_it.Current();
+      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();
+        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);
+        }
+      }
+    }
+  }
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h
new file mode 100644
index 0000000..ac00824
--- /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:
+  explicit HConstantFolding(HGraph* graph)
+      : HOptimization(graph, true, kConstantFoldingPassName) {}
+
+  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_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
new file mode 100644
index 0000000..6ceccfb
--- /dev/null
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -0,0 +1,643 @@
+/*
+ * 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 <functional>
+
+#include "code_generator_x86.h"
+#include "constant_folding.h"
+#include "dead_code_elimination.h"
+#include "driver/compiler_options.h"
+#include "graph_checker.h"
+#include "optimizing_unit_test.h"
+#include "pretty_printer.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+static void TestCode(const uint16_t* data,
+                     const std::string& expected_before,
+                     const std::string& expected_after_cf,
+                     const std::string& expected_after_dce,
+                     std::function<void(HGraph*)> check_after_cf,
+                     Primitive::Type return_type = Primitive::kPrimInt) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HGraph* graph = CreateCFG(&allocator, data, return_type);
+  ASSERT_NE(graph, nullptr);
+
+  graph->TryBuildingSsa();
+
+  StringPrettyPrinter printer_before(graph);
+  printer_before.VisitInsertionOrder();
+  std::string actual_before = printer_before.str();
+  ASSERT_EQ(expected_before, actual_before);
+
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+  HConstantFolding(graph).Run();
+  SSAChecker ssa_checker_cf(&allocator, graph);
+  ssa_checker_cf.Run();
+  ASSERT_TRUE(ssa_checker_cf.IsValid());
+
+  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_cf(graph);
+
+  HDeadCodeElimination(graph).Run();
+  SSAChecker ssa_checker_dce(&allocator, graph);
+  ssa_checker_dce.Run();
+  ASSERT_TRUE(ssa_checker_dce.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);
+}
+
+
+/**
+ * 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
+ *                              offset
+ *                              ------
+ *     v0 <- 1                  0.      const/4 v0, #+1
+ *     v1 <- 2                  1.      const/4 v1, #+2
+ *     v2 <- v0 + v1            2.      add-int v2, v0, v1
+ *     return v2                4.      return v2
+ */
+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,
+    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
+    Instruction::RETURN | 2 << 8);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  3: IntConstant [9]\n"
+    "  5: IntConstant [9]\n"
+    "  14: SuspendCheck\n"
+    "  15: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  9: Add(3, 5) [12]\n"
+    "  12: Return(9)\n"
+    "BasicBlock 2, pred: 1\n"
+    "  13: Exit\n";
+
+  // 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_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(), 3);
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  3: IntConstant\n", removed },
+    { "  5: 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);
+}
+
+/**
+ * Small three-register program exercising int constant folding on addition.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     v0 <- 1                  0.      const/4 v0, #+1
+ *     v1 <- 2                  1.      const/4 v1, #+2
+ *     v0 <- v0 + v1            2.      add-int/2addr v0, v1
+ *     v1 <- 3                  3.      const/4 v1, #+3
+ *     v2 <- 4                  4.      const/4 v2, #+4
+ *     v1 <- v1 + v2            5.      add-int/2addr v1, v2
+ *     v2 <- v0 + v1            6.      add-int v2, v0, v1
+ *     return v2                8.      return v2
+ */
+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,
+    Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
+    Instruction::CONST_4 | 1 << 8 | 3 << 12,
+    Instruction::CONST_4 | 2 << 8 | 4 << 12,
+    Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
+    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
+    Instruction::RETURN | 2 << 8);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  3: IntConstant [9]\n"
+    "  5: IntConstant [9]\n"
+    "  11: IntConstant [17]\n"
+    "  13: IntConstant [17]\n"
+    "  26: SuspendCheck\n"
+    "  27: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  9: Add(3, 5) [21]\n"
+    "  17: Add(11, 13) [21]\n"
+    "  21: Add(9, 17) [24]\n"
+    "  24: Return(21)\n"
+    "BasicBlock 2, pred: 1\n"
+    "  25: Exit\n";
+
+  // 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" },
+    { "  13: IntConstant [17]\n", "  13: IntConstant\n" },
+    { "  9: Add(3, 5) [21]\n",    "  28: IntConstant\n" },
+    { "  17: Add(11, 13) [21]\n", "  29: IntConstant\n" },
+    { "  21: Add(9, 17) [24]\n",  "  30: IntConstant [24]\n" },
+    { "  24: Return(21)\n",       "  24: Return(30)\n" }
+  };
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
+
+  // Check the values of the computed constants.
+  auto check_after_cf = [](HGraph* graph) {
+    HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
+    ASSERT_TRUE(inst1->IsIntConstant());
+    ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
+    HInstruction* inst2 = inst1->GetNext();
+    ASSERT_TRUE(inst2->IsIntConstant());
+    ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
+    HInstruction* inst3 = inst2->GetNext();
+    ASSERT_TRUE(inst3->IsIntConstant());
+    ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  3: IntConstant\n",  removed },
+    { "  5: IntConstant\n",  removed },
+    { "  11: IntConstant\n", removed },
+    { "  13: IntConstant\n", removed },
+    { "  28: IntConstant\n", removed },
+    { "  29: 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 subtraction.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     v0 <- 3                  0.      const/4 v0, #+3
+ *     v1 <- 2                  1.      const/4 v1, #+2
+ *     v2 <- v0 - v1            2.      sub-int v2, v0, v1
+ *     return v2                4.      return v2
+ */
+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,
+    Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
+    Instruction::RETURN | 2 << 8);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  3: IntConstant [9]\n"
+    "  5: IntConstant [9]\n"
+    "  14: SuspendCheck\n"
+    "  15: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  9: Sub(3, 5) [12]\n"
+    "  12: Return(9)\n"
+    "BasicBlock 2, pred: 1\n"
+    "  13: Exit\n";
+
+  // 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_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 = {
+    { "  3: IntConstant\n", removed },
+    { "  5: 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-pair program exercising long constant folding
+ * on addition.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     (v0, v1) <- 1            0.      const-wide/16 v0, #+1
+ *     (v2, v3) <- 2            2.      const-wide/16 v2, #+2
+ *     (v4, v5) <-
+ *       (v0, v1) + (v1, v2)    4.      add-long v4, v0, v2
+ *     return (v4, v5)          6.      return-wide v4
+ */
+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,
+    Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
+    Instruction::RETURN_WIDE | 4 << 8);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  6: LongConstant [12]\n"
+    "  8: LongConstant [12]\n"
+    "  17: SuspendCheck\n"
+    "  18: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  12: Add(6, 8) [15]\n"
+    "  15: Return(12)\n"
+    "BasicBlock 2, pred: 1\n"
+    "  16: Exit\n";
+
+  // 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_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->IsLongConstant());
+    ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  6: LongConstant\n", removed },
+    { "  8: LongConstant\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,
+           Primitive::kPrimLong);
+}
+
+/**
+ * Tiny three-register-pair program exercising long constant folding
+ * on subtraction.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     (v0, v1) <- 3            0.      const-wide/16 v0, #+3
+ *     (v2, v3) <- 2            2.      const-wide/16 v2, #+2
+ *     (v4, v5) <-
+ *       (v0, v1) - (v1, v2)    4.      sub-long v4, v0, v2
+ *     return (v4, v5)          6.      return-wide v4
+ */
+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,
+    Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
+    Instruction::RETURN_WIDE | 4 << 8);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  6: LongConstant [12]\n"
+    "  8: LongConstant [12]\n"
+    "  17: SuspendCheck\n"
+    "  18: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 2\n"
+    "  12: Sub(6, 8) [15]\n"
+    "  15: Return(12)\n"
+    "BasicBlock 2, pred: 1\n"
+    "  16: Exit\n";
+
+  // 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_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->IsLongConstant());
+    ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  6: LongConstant\n", removed },
+    { "  8: LongConstant\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,
+           Primitive::kPrimLong);
+}
+
+/**
+ * Three-register program with jumps leading to the creation of many
+ * blocks.
+ *
+ * The intent of this test is to ensure that all constant expressions
+ * are actually evaluated at compile-time, thanks to the reverse
+ * (forward) post-order traversal of the the dominator tree.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     v0 <- 0                   0.     const/4 v0, #+0
+ *     v1 <- 1                   1.     const/4 v1, #+1
+ *     v2 <- v0 + v1             2.     add-int v2, v0, v1
+ *     goto L2                   4.     goto +4
+ * L1: v1 <- v0 + 3              5.     add-int/lit16 v1, v0, #+3
+ *     goto L3                   7.     goto +4
+ * L2: v0 <- v2 + 2              8.     add-int/lit16 v0, v2, #+2
+ *     goto L1                  10.     goto +(-5)
+ * L3: v2 <- v1 + 4             11.     add-int/lit16 v2, v1, #+4
+ *     return v2                13.     return v2
+ */
+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,
+    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
+    Instruction::GOTO | 4 << 8,
+    Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
+    Instruction::GOTO | 4 << 8,
+    Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
+    static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
+    Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
+    Instruction::RETURN | 2 << 8);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  3: IntConstant [9]\n"            // v0 <- 0
+    "  5: IntConstant [9]\n"            // v1 <- 1
+    "  13: IntConstant [14]\n"          // const 3
+    "  18: IntConstant [19]\n"          // const 2
+    "  24: IntConstant [25]\n"          // const 4
+    "  30: SuspendCheck\n"
+    "  31: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 3\n"
+    "  9: Add(3, 5) [19]\n"             // v2 <- v0 + v1 = 0 + 1 = 1
+    "  11: Goto 3\n"                    // goto L2
+    "BasicBlock 2, pred: 3, succ: 4\n"  // L1:
+    "  14: Add(19, 13) [25]\n"          // v1 <- v0 + 3 = 3 + 3 = 6
+    "  16: Goto 4\n"                    // goto L3
+    "BasicBlock 3, pred: 1, succ: 2\n"  // L2:
+    "  19: Add(9, 18) [14]\n"           // v0 <- v2 + 2 = 1 + 2 = 3
+    "  21: SuspendCheck\n"
+    "  22: Goto 2\n"                    // goto L1
+    "BasicBlock 4, pred: 2, succ: 5\n"  // L3:
+    "  25: Add(14, 24) [28]\n"          // v2 <- v1 + 4 = 6 + 4 = 10
+    "  28: Return(25)\n"                // return v2
+    "BasicBlock 5, pred: 4\n"
+    "  29: Exit\n";
+
+  // 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" },
+    { "  18: IntConstant [19]\n", "  18: IntConstant\n" },
+    { "  24: IntConstant [25]\n", "  24: IntConstant\n" },
+    { "  9: Add(3, 5) [19]\n",    "  32: IntConstant []\n" },
+    { "  14: Add(19, 13) [25]\n", "  34: IntConstant\n" },
+    { "  19: Add(9, 18) [14]\n",  "  33: IntConstant []\n" },
+    { "  25: Add(14, 24) [28]\n", "  35: IntConstant [28]\n" },
+    { "  28: Return(25)\n",       "  28: Return(35)\n"}
+  };
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
+
+  // Check the values of the computed constants.
+  auto check_after_cf = [](HGraph* graph) {
+    HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
+    ASSERT_TRUE(inst1->IsIntConstant());
+    ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
+    HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
+    ASSERT_TRUE(inst2->IsIntConstant());
+    ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
+    HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
+    ASSERT_TRUE(inst3->IsIntConstant());
+    ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
+    HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
+    ASSERT_TRUE(inst4->IsIntConstant());
+    ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  3: IntConstant\n",     removed },
+    { "  13: IntConstant\n",    removed },
+    { "  18: IntConstant\n",    removed },
+    { "  24: IntConstant\n",    removed },
+    { "  34: 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);
+}
+
+
+/**
+ * Three-register program with a constant (static) condition.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     v1 <- 1                  0.      const/4 v1, #+1
+ *     v0 <- 0                  1.      const/4 v0, #+0
+ *     if v1 >= 0 goto L1       2.      if-gez v1, +3
+ *     v0 <- v1                 4.      move v0, v1
+ * L1: v2 <- v0 + v1            5.      add-int v2, v0, v1
+ *     return-void              7.      return
+ */
+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,
+    Instruction::IF_GEZ | 1 << 8, 3,
+    Instruction::MOVE | 0 << 8 | 1 << 12,
+    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
+    Instruction::RETURN_VOID);
+
+  std::string expected_before =
+    "BasicBlock 0, succ: 1\n"
+    "  3: IntConstant [15, 22, 8]\n"
+    "  5: IntConstant [22, 8]\n"
+    "  19: SuspendCheck\n"
+    "  20: Goto 1\n"
+    "BasicBlock 1, pred: 0, succ: 5, 2\n"
+    "  8: GreaterThanOrEqual(3, 5) [9]\n"
+    "  9: If(8)\n"
+    "BasicBlock 2, pred: 1, succ: 3\n"
+    "  12: Goto 3\n"
+    "BasicBlock 3, pred: 2, 5, succ: 4\n"
+    "  22: Phi(3, 5) [15]\n"
+    "  15: Add(22, 3)\n"
+    "  17: ReturnVoid\n"
+    "BasicBlock 4, pred: 3\n"
+    "  18: Exit\n"
+    "BasicBlock 5, pred: 1, succ: 3\n"
+    "  21: Goto 3\n";
+
+  // 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_cf = Patch(expected_before, expected_cf_diff);
+
+  // Check the values of the computed constants.
+  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 = {
+    { "  3: IntConstant [15, 22]\n", "  3: IntConstant [22]\n" },
+    { "  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_cf, expected_dce_diff);
+
+  TestCode(data,
+           expected_before,
+           expected_after_cf,
+           expected_after_dce,
+           check_after_cf);
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/constant_propagation.cc b/compiler/optimizing/constant_propagation.cc
deleted file mode 100644
index d675164..0000000
--- a/compiler/optimizing/constant_propagation.cc
+++ /dev/null
@@ -1,47 +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.
- */
-
-#include "constant_propagation.h"
-
-namespace art {
-
-void ConstantPropagation::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
-  // instruction into a constant as well.
-  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
-    HBasicBlock* block = it.Current();
-    // Traverse this block's instructions in (forward) order and
-    // replace the ones that can be statically evaluated by a
-    // compile-time counterpart.
-    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()) {
-        HConstant* constant =
-          inst->AsBinaryOperation()->TryStaticEvaluation(graph_->GetArena());
-        if (constant != nullptr) {
-          inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
-        }
-      }
-    }
-  }
-}
-
-}  // 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/constant_propagation_test.cc b/compiler/optimizing/constant_propagation_test.cc
deleted file mode 100644
index 5c8c709..0000000
--- a/compiler/optimizing/constant_propagation_test.cc
+++ /dev/null
@@ -1,487 +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.
- */
-
-#include "constant_propagation.h"
-#include "dead_code_elimination.h"
-#include "pretty_printer.h"
-#include "graph_checker.h"
-#include "optimizing_unit_test.h"
-
-#include "gtest/gtest.h"
-
-namespace art {
-
-static void TestCode(const uint16_t* data,
-                     const std::string& expected_before,
-                     const std::string& expected_after_cp,
-                     const std::string& expected_after_dce) {
-  ArenaPool pool;
-  ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateCFG(&allocator, data);
-  ASSERT_NE(graph, nullptr);
-
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-
-  StringPrettyPrinter printer_before(graph);
-  printer_before.VisitInsertionOrder();
-  std::string actual_before = printer_before.str();
-  ASSERT_EQ(expected_before, actual_before);
-
-  ConstantPropagation(graph).Run();
-
-  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);
-
-  DeadCodeElimination(graph).Run();
-
-  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 addition.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     v0 <- 1                  0.      const/4 v0, #+1
- *     v1 <- 2                  1.      const/4 v1, #+2
- *     v2 <- v0 + v1            2.      add-int v2, v0, v1
- *     return v2                4.      return v2
- */
-TEST(ConstantPropagation, IntConstantFoldingOnAddition1) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
-    Instruction::CONST_4 | 0 << 8 | 1 << 12,
-    Instruction::CONST_4 | 1 << 8 | 2 << 12,
-    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
-    Instruction::RETURN | 2 << 8);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  3: IntConstant [9]\n"
-    "  5: IntConstant [9]\n"
-    "  14: SuspendCheck\n"
-    "  15: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 2\n"
-    "  9: Add(3, 5) [12]\n"
-    "  12: Return(9)\n"
-    "BasicBlock 2, pred: 1\n"
-    "  13: Exit\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  3: IntConstant\n", removed },
-    { "  5: IntConstant\n", removed }
-  };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-/**
- * Small three-register program exercising int constant folding on addition.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     v0 <- 1                  0.      const/4 v0, #+1
- *     v1 <- 2                  1.      const/4 v1, #+2
- *     v0 <- v0 + v1            2.      add-int/2addr v0, v1
- *     v1 <- 3                  3.      const/4 v1, #+3
- *     v2 <- 4                  4.      const/4 v2, #+4
- *     v1 <- v1 + v2            5.      add-int/2addr v1, v2
- *     v2 <- v0 + v1            6.      add-int v2, v0, v1
- *     return v2                8.      return v2
- */
-TEST(ConstantPropagation, IntConstantFoldingOnAddition2) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
-    Instruction::CONST_4 | 0 << 8 | 1 << 12,
-    Instruction::CONST_4 | 1 << 8 | 2 << 12,
-    Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
-    Instruction::CONST_4 | 1 << 8 | 3 << 12,
-    Instruction::CONST_4 | 2 << 8 | 4 << 12,
-    Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
-    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
-    Instruction::RETURN | 2 << 8);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  3: IntConstant [9]\n"
-    "  5: IntConstant [9]\n"
-    "  11: IntConstant [17]\n"
-    "  13: IntConstant [17]\n"
-    "  26: SuspendCheck\n"
-    "  27: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 2\n"
-    "  9: Add(3, 5) [21]\n"
-    "  17: Add(11, 13) [21]\n"
-    "  21: Add(9, 17) [24]\n"
-    "  24: Return(21)\n"
-    "BasicBlock 2, pred: 1\n"
-    "  25: Exit\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
-    { "  3: IntConstant [9]\n",   "  3: IntConstant\n" },
-    { "  5: IntConstant [9]\n",   "  5: IntConstant\n" },
-    { "  11: IntConstant [17]\n", "  11: IntConstant\n" },
-    { "  13: IntConstant [17]\n", "  13: IntConstant\n" },
-    { "  9: Add(3, 5) [21]\n",    "  28: IntConstant\n" },
-    { "  17: Add(11, 13) [21]\n", "  29: IntConstant\n" },
-    { "  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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  3: IntConstant\n",  removed },
-    { "  5: IntConstant\n",  removed },
-    { "  11: IntConstant\n", removed },
-    { "  13: IntConstant\n", removed },
-    { "  28: IntConstant\n", removed },
-    { "  29: IntConstant\n", removed }
-  };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-/**
- * Tiny three-register program exercising int constant folding on subtraction.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     v0 <- 3                  0.      const/4 v0, #+3
- *     v1 <- 2                  1.      const/4 v1, #+2
- *     v2 <- v0 - v1            2.      sub-int v2, v0, v1
- *     return v2                4.      return v2
- */
-TEST(ConstantPropagation, IntConstantFoldingOnSubtraction) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
-    Instruction::CONST_4 | 0 << 8 | 3 << 12,
-    Instruction::CONST_4 | 1 << 8 | 2 << 12,
-    Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
-    Instruction::RETURN | 2 << 8);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  3: IntConstant [9]\n"
-    "  5: IntConstant [9]\n"
-    "  14: SuspendCheck\n"
-    "  15: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 2\n"
-    "  9: Sub(3, 5) [12]\n"
-    "  12: Return(9)\n"
-    "BasicBlock 2, pred: 1\n"
-    "  13: Exit\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  3: IntConstant\n", removed },
-    { "  5: IntConstant\n", removed }
-  };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-#define SIX_REGISTERS_CODE_ITEM(...)                                     \
-    { 6, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
-
-/**
- * Tiny three-register-pair program exercising long constant folding
- * on addition.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     (v0, v1) <- 1            0.      const-wide/16 v0, #+1
- *     (v2, v3) <- 2            2.      const-wide/16 v2, #+2
- *     (v4, v5) <-
- *       (v0, v1) + (v1, v2)    4.      add-long v4, v0, v2
- *     return (v4, v5)          6.      return-wide v4
- */
-TEST(ConstantPropagation, LongConstantFoldingOnAddition) {
-  const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
-    Instruction::CONST_WIDE_16 | 0 << 8, 1,
-    Instruction::CONST_WIDE_16 | 2 << 8, 2,
-    Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
-    Instruction::RETURN_WIDE | 4 << 8);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  6: LongConstant [12]\n"
-    "  8: LongConstant [12]\n"
-    "  17: SuspendCheck\n"
-    "  18: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 2\n"
-    "  12: Add(6, 8) [15]\n"
-    "  15: Return(12)\n"
-    "BasicBlock 2, pred: 1\n"
-    "  16: Exit\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  6: LongConstant\n", removed },
-    { "  8: LongConstant\n", removed }
-  };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-/**
- * Tiny three-register-pair program exercising long constant folding
- * on subtraction.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     (v0, v1) <- 3            0.      const-wide/16 v0, #+3
- *     (v2, v3) <- 2            2.      const-wide/16 v2, #+2
- *     (v4, v5) <-
- *       (v0, v1) - (v1, v2)    4.      sub-long v4, v0, v2
- *     return (v4, v5)          6.      return-wide v4
- */
-TEST(ConstantPropagation, LongConstantFoldingOnSubtraction) {
-  const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
-    Instruction::CONST_WIDE_16 | 0 << 8, 3,
-    Instruction::CONST_WIDE_16 | 2 << 8, 2,
-    Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
-    Instruction::RETURN_WIDE | 4 << 8);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  6: LongConstant [12]\n"
-    "  8: LongConstant [12]\n"
-    "  17: SuspendCheck\n"
-    "  18: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 2\n"
-    "  12: Sub(6, 8) [15]\n"
-    "  15: Return(12)\n"
-    "BasicBlock 2, pred: 1\n"
-    "  16: Exit\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  6: LongConstant\n", removed },
-    { "  8: LongConstant\n", removed }
-  };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-/**
- * Three-register program with jumps leading to the creation of many
- * blocks.
- *
- * The intent of this test is to ensure that all constant expressions
- * are actually evaluated at compile-time, thanks to the reverse
- * (forward) post-order traversal of the the dominator tree.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     v0 <- 0                   0.     const/4 v0, #+0
- *     v1 <- 1                   1.     const/4 v1, #+1
- *     v2 <- v0 + v1             2.     add-int v2, v0, v1
- *     goto L2                   4.     goto +4
- * L1: v1 <- v0 + 3              5.     add-int/lit16 v1, v0, #+3
- *     goto L3                   7.     goto +4
- * L2: v0 <- v2 + 2              8.     add-int/lit16 v0, v2, #+2
- *     goto L1                  10.     goto +(-5)
- * L3: v2 <- v1 + 4             11.     add-int/lit16 v2, v1, #+4
- *     return v2                13.     return v2
- */
-TEST(ConstantPropagation, IntConstantFoldingAndJumps) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
-    Instruction::CONST_4 | 0 << 8 | 0 << 12,
-    Instruction::CONST_4 | 1 << 8 | 1 << 12,
-    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
-    Instruction::GOTO | 4 << 8,
-    Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
-    Instruction::GOTO | 4 << 8,
-    Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
-    static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
-    Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
-    Instruction::RETURN | 2 << 8);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  3: IntConstant [9]\n"
-    "  5: IntConstant [9]\n"
-    "  13: IntConstant [14]\n"
-    "  18: IntConstant [19]\n"
-    "  24: IntConstant [25]\n"
-    "  30: SuspendCheck\n"
-    "  31: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 3\n"
-    "  9: Add(3, 5) [19]\n"
-    "  11: Goto 3\n"
-    "BasicBlock 2, pred: 3, succ: 4\n"
-    "  14: Add(19, 13) [25]\n"
-    "  16: Goto 4\n"
-    "BasicBlock 3, pred: 1, succ: 2\n"
-    "  19: Add(9, 18) [14]\n"
-    "  21: SuspendCheck\n"
-    "  22: Goto 2\n"
-    "BasicBlock 4, pred: 2, succ: 5\n"
-    "  25: Add(14, 24) [28]\n"
-    "  28: Return(25)\n"
-    "BasicBlock 5, pred: 4\n"
-    "  29: Exit\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
-    { "  3: IntConstant [9]\n",   "  3: IntConstant\n" },
-    { "  5: IntConstant [9]\n",   "  5: IntConstant []\n" },
-    { "  13: IntConstant [14]\n", "  13: IntConstant\n" },
-    { "  18: IntConstant [19]\n", "  18: IntConstant\n" },
-    { "  24: IntConstant [25]\n", "  24: IntConstant\n" },
-    { "  9: Add(3, 5) [19]\n",    "  32: IntConstant []\n" },
-    { "  14: Add(19, 13) [25]\n", "  34: IntConstant\n" },
-    { "  19: Add(9, 18) [14]\n",  "  33: IntConstant []\n" },
-    { "  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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  3: IntConstant\n",     removed },
-    { "  13: IntConstant\n",    removed },
-    { "  18: IntConstant\n",    removed },
-    { "  24: IntConstant\n",    removed },
-    { "  34: IntConstant\n",    removed },
-  };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-
-/**
- * Three-register program with a constant (static) condition.
- *
- *                              16-bit
- *                              offset
- *                              ------
- *     v1 <- 1                  0.      const/4 v1, #+1
- *     v0 <- 0                  1.      const/4 v0, #+0
- *     if v1 >= 0 goto L1       2.      if-gez v1, +3
- *     v0 <- v1                 4.      move v0, v1
- * L1: v2 <- v0 + v1            5.      add-int v2, v0, v1
- *     return-void              7.      return
- */
-TEST(ConstantPropagation, ConstantCondition) {
-  const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
-    Instruction::CONST_4 | 1 << 8 | 1 << 12,
-    Instruction::CONST_4 | 0 << 8 | 0 << 12,
-    Instruction::IF_GEZ | 1 << 8, 3,
-    Instruction::MOVE | 0 << 8 | 1 << 12,
-    Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
-    Instruction::RETURN_VOID);
-
-  std::string expected_before =
-    "BasicBlock 0, succ: 1\n"
-    "  3: IntConstant [15, 22, 8]\n"
-    "  5: IntConstant [22, 8]\n"
-    "  19: SuspendCheck\n"
-    "  20: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 5, 2\n"
-    "  8: GreaterThanOrEqual(3, 5) [9]\n"
-    "  9: If(8)\n"
-    "BasicBlock 2, pred: 1, succ: 3\n"
-    "  12: Goto 3\n"
-    "BasicBlock 3, pred: 2, 5, succ: 4\n"
-    "  22: Phi(3, 5) [15]\n"
-    "  15: Add(22, 3)\n"
-    "  17: ReturnVoid\n"
-    "BasicBlock 4, pred: 3\n"
-    "  18: Exit\n"
-    "BasicBlock 5, pred: 1, succ: 3\n"
-    "  21: Goto 3\n";
-
-  // Expected difference after constant propagation.
-  diff_t expected_cp_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);
-
-  // Expected difference after dead code elimination.
-  diff_t expected_dce_diff = {
-    { "  3: IntConstant [15, 22]\n", "  3: IntConstant [22]\n" },
-    { "  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);
-
-  TestCode(data, expected_before, expected_after_cp, expected_after_dce);
-}
-
-}  // namespace art
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..3db2c3f 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) {}
+  explicit HDeadCodeElimination(HGraph* graph)
+      : HOptimization(graph, true, kDeadCodeEliminationPassName) {}
 
-  void Run();
+  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..a644719 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
+#include "code_generator_x86.h"
 #include "dead_code_elimination.h"
-#include "pretty_printer.h"
+#include "driver/compiler_options.h"
 #include "graph_checker.h"
 #include "optimizing_unit_test.h"
+#include "pretty_printer.h"
 
 #include "gtest/gtest.h"
 
@@ -31,24 +33,23 @@
   HGraph* graph = CreateCFG(&allocator, data);
   ASSERT_NE(graph, nullptr);
 
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
+  graph->TryBuildingSsa();
 
   StringPrettyPrinter printer_before(graph);
   printer_before.VisitInsertionOrder();
   std::string actual_before = printer_before.str();
   ASSERT_EQ(actual_before, expected_before);
 
-  DeadCodeElimination(graph).Run();
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+  HDeadCodeElimination(graph).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 +95,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 +166,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/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index c36b143..82fe03c 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -32,7 +32,7 @@
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
   graph->BuildDominatorTree();
-  graph->FindNaturalLoops();
+  graph->AnalyzeNaturalLoops();
   return graph;
 }
 
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 589b44a..291b14c 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -16,9 +16,9 @@
 
 #include "graph_checker.h"
 
-#include <string>
 #include <map>
 #include <sstream>
+#include <string>
 
 #include "base/bit_vector-inl.h"
 
@@ -53,7 +53,7 @@
             << " lists " << block_count_in_p_successors
             << " occurrences of block " << block->GetBlockId()
             << " in its successors.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
   }
 
@@ -83,7 +83,7 @@
             << " lists " << block_count_in_s_predecessors
             << " occurrences of block " << block->GetBlockId()
             << " in its predecessors.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
   }
 
@@ -93,7 +93,7 @@
     std::stringstream error;
     error  << "Block " << block->GetBlockId()
            << " does not end with a branch instruction.";
-    errors_.Insert(error.str());
+    errors_.push_back(error.str());
   }
 
   // Visit this block's list of phis.
@@ -103,7 +103,7 @@
       std::stringstream error;
       error << "Block " << current_block_->GetBlockId()
             << " has a non-phi in its phi list.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
     it.Current()->Accept(this);
   }
@@ -116,13 +116,21 @@
       std::stringstream error;
       error << "Block " << current_block_->GetBlockId()
             << " has a phi in its non-phi list.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
     it.Current()->Accept(this);
   }
 }
 
 void GraphChecker::VisitInstruction(HInstruction* instruction) {
+  if (seen_ids_.IsBitSet(instruction->GetId())) {
+    std::stringstream error;
+    error << "Duplicate id in graph " << instruction->GetId() << ".";
+    errors_.push_back(error.str());
+  } else {
+    seen_ids_.SetBit(instruction->GetId());
+  }
+
   // Ensure `instruction` is associated with `current_block_`.
   if (instruction->GetBlock() != current_block_) {
     std::stringstream error;
@@ -139,7 +147,7 @@
     } else {
       error << " not associated with any block.";
     }
-    errors_.Insert(error.str());
+    errors_.push_back(error.str());
   }
 
   // Ensure the inputs of `instruction` are defined in a block of the graph.
@@ -154,7 +162,7 @@
       error << "Input " << input->GetId()
             << " of instruction " << instruction->GetId()
             << " is not defined in a basic block of the control-flow graph.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
   }
 
@@ -170,7 +178,7 @@
       error << "User " << use->GetId()
             << " of instruction " << instruction->GetId()
             << " is not defined in a basic block of the control-flow graph.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
   }
 }
@@ -188,7 +196,7 @@
         std::stringstream error;
         error << "Critical edge between blocks " << block->GetBlockId()
               << " and "  << successor->GetBlockId() << ".";
-        errors_.Insert(error.str());
+        errors_.push_back(error.str());
       }
     }
   }
@@ -207,7 +215,7 @@
     std::stringstream error;
     error << "Loop pre-header is not the first predecessor of the loop header "
           << id << ".";
-    errors_.Insert(error.str());
+    errors_.push_back(error.str());
   }
 
   // Ensure the loop header has only two predecessors and that only the
@@ -215,25 +223,25 @@
   if (loop_header->GetPredecessors().Size() < 2) {
     std::stringstream error;
     error << "Loop header " << id << " has less than two predecessors.";
-    errors_.Insert(error.str());
+    errors_.push_back(error.str());
   } else if (loop_header->GetPredecessors().Size() > 2) {
     std::stringstream error;
     error << "Loop header " << id << " has more than two predecessors.";
-    errors_.Insert(error.str());
+    errors_.push_back(error.str());
   } else {
     HLoopInformation* loop_information = loop_header->GetLoopInformation();
     HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
     if (loop_information->IsBackEdge(first_predecessor)) {
       std::stringstream error;
       error << "First predecessor of loop header " << id << " is a back edge.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
     HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1);
     if (!loop_information->IsBackEdge(second_predecessor)) {
       std::stringstream error;
       error << "Second predecessor of loop header " << id
             << " is not a back edge.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
   }
 
@@ -244,7 +252,7 @@
       std::stringstream error;
       error << "Loop defined by header " << id << " has "
             << num_back_edges << " back edge(s).";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
   }
 
   // Ensure all blocks in the loop are dominated by the loop header.
@@ -256,7 +264,7 @@
       std::stringstream error;
       error << "Loop block " << loop_block->GetBlockId()
             << " not dominated by loop header " << id;
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
     }
   }
 }
@@ -264,19 +272,36 @@
 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() << ".";
-      errors_.Insert(error.str());
+      error << "Instruction " << instruction->GetId()
+            << " in block " << current_block_->GetBlockId()
+            << " does not dominate use " << use->GetId()
+            << " in block " << use->GetBlock()->GetBlockId() << ".";
+      errors_.push_back(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_.push_back(error.str());
+      }
     }
   }
 }
@@ -290,7 +315,7 @@
       error << "Loop phi " << phi->GetId()
             << " in block " << phi->GetBlock()->GetBlockId()
             << " is its own first input.";
-      errors_.Insert(error.str());
+      errors_.push_back(error.str());
   }
 
   // Ensure the number of phi inputs is the same as the number of
@@ -304,7 +329,7 @@
           << " has " << phi->InputCount() << " inputs, but block "
           << phi->GetBlock()->GetBlockId() << " has "
           << predecessors.Size() << " predecessors.";
-    errors_.Insert(error.str());
+    errors_.push_back(error.str());
   } else {
     // Ensure phi input at index I either comes from the Ith
     // predecessor or from a block that dominates this predecessor.
@@ -319,10 +344,138 @@
               << " from block " << phi->GetBlock()->GetBlockId()
               << " is not defined in predecessor number " << i
               << " nor in a block dominating it.";
-        errors_.Insert(error.str());
+        errors_.push_back(error.str());
       }
     }
   }
 }
 
+static Primitive::Type PrimitiveKind(Primitive::Type type) {
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimInt:
+      return Primitive::kPrimInt;
+    default:
+      return type;
+  }
+}
+
+void SSAChecker::VisitIf(HIf* instruction) {
+  VisitInstruction(instruction);
+  HInstruction* input = instruction->InputAt(0);
+  if (input->IsIntConstant()) {
+    int value = input->AsIntConstant()->GetValue();
+    if (value != 0 && value != 1) {
+      std::stringstream error;
+      error << "If instruction " << instruction->GetId()
+            << " has a non-boolean constant input whose value is: "
+            << value << ".";
+      errors_.push_back(error.str());
+    }
+  } else if (instruction->InputAt(0)->GetType() != Primitive::kPrimBoolean) {
+    std::stringstream error;
+    error << "If instruction " << instruction->GetId()
+          << " has a non-boolean input type: "
+          << instruction->InputAt(0)->GetType() << ".";
+    errors_.push_back(error.str());
+  }
+}
+
+void SSAChecker::VisitCondition(HCondition* op) {
+  VisitInstruction(op);
+  if (op->GetType() != Primitive::kPrimBoolean) {
+    std::stringstream error;
+    error << "Condition " << op->DebugName() << " " << op->GetId()
+          << " has a non-boolean result type: "
+          << op->GetType() << ".";
+    errors_.push_back(error.str());
+  }
+  HInstruction* lhs = op->InputAt(0);
+  HInstruction* rhs = op->InputAt(1);
+  if (lhs->GetType() == Primitive::kPrimNot) {
+    if (!op->IsEqual() && !op->IsNotEqual()) {
+      std::stringstream error;
+      error << "Condition " << op->DebugName() << " " << op->GetId()
+            << " uses an object as left-hand side input.";
+      errors_.push_back(error.str());
+    }
+    if (rhs->IsIntConstant() && rhs->AsIntConstant()->GetValue() != 0) {
+      std::stringstream error;
+      error << "Condition " << op->DebugName() << " " << op->GetId()
+            << " compares an object with a non-0 integer: "
+            << rhs->AsIntConstant()->GetValue()
+            << ".";
+      errors_.push_back(error.str());
+    }
+  } else if (rhs->GetType() == Primitive::kPrimNot) {
+    if (!op->IsEqual() && !op->IsNotEqual()) {
+      std::stringstream error;
+      error << "Condition " << op->DebugName() << " " << op->GetId()
+            << " uses an object as right-hand side input.";
+      errors_.push_back(error.str());
+    }
+    if (lhs->IsIntConstant() && lhs->AsIntConstant()->GetValue() != 0) {
+      std::stringstream error;
+      error << "Condition " << op->DebugName() << " " << op->GetId()
+            << " compares a non-0 integer with an object: "
+            << lhs->AsIntConstant()->GetValue()
+            << ".";
+      errors_.push_back(error.str());
+    }
+  } else if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) {
+    std::stringstream error;
+    error << "Condition " << op->DebugName() << " " << op->GetId()
+          << " has inputs of different type: "
+          << lhs->GetType() << ", and " << rhs->GetType()
+          << ".";
+    errors_.push_back(error.str());
+  }
+}
+
+void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) {
+  VisitInstruction(op);
+  if (op->IsUShr() || op->IsShr() || op->IsShl()) {
+    if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
+      std::stringstream error;
+      error << "Shift operation " << op->DebugName() << " " << op->GetId()
+            << " has a non-int kind second input: "
+            << op->InputAt(1)->DebugName() << " of type " << op->InputAt(1)->GetType()
+            << ".";
+      errors_.push_back(error.str());
+    }
+  } else {
+    if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
+      std::stringstream error;
+      error << "Binary operation " << op->DebugName() << " " << op->GetId()
+            << " has inputs of different type: "
+            << op->InputAt(0)->GetType() << ", and " << op->InputAt(1)->GetType()
+            << ".";
+      errors_.push_back(error.str());
+    }
+  }
+
+  if (op->IsCompare()) {
+    if (op->GetType() != Primitive::kPrimInt) {
+      std::stringstream error;
+      error << "Compare operation " << op->GetId()
+            << " has a non-int result type: "
+            << op->GetType() << ".";
+      errors_.push_back(error.str());
+    }
+  } else {
+    // Use the first input, so that we can also make this check for shift operations.
+    if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
+      std::stringstream error;
+      error << "Binary operation " << op->DebugName() << " " << op->GetId()
+            << " has a result type different than its input type: "
+            << op->GetType() << ", and " << op->InputAt(1)->GetType()
+            << ".";
+      errors_.push_back(error.str());
+    }
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 34a770b..ae1557b 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -19,40 +19,58 @@
 
 #include "nodes.h"
 
+#include <ostream>
+
 namespace art {
 
 // A control-flow graph visitor performing various checks.
-class GraphChecker : public HGraphVisitor {
+class GraphChecker : public HGraphDelegateVisitor {
  public:
-  GraphChecker(ArenaAllocator* allocator, HGraph* graph)
-    : HGraphVisitor(graph),
+  GraphChecker(ArenaAllocator* allocator, HGraph* graph,
+               const char* dump_prefix = "art::GraphChecker: ")
+    : HGraphDelegateVisitor(graph),
       allocator_(allocator),
-      errors_(allocator, 0) {}
+      dump_prefix_(dump_prefix),
+      seen_ids_(allocator, graph->GetCurrentInstructionId(), false) {}
+
+  // Check the whole graph (in insertion order).
+  virtual void Run() { VisitInsertionOrder(); }
 
   // Check `block`.
-  virtual void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
+  void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
 
   // Check `instruction`.
-  virtual void VisitInstruction(HInstruction* instruction) OVERRIDE;
+  void VisitInstruction(HInstruction* instruction) OVERRIDE;
 
   // Was the last visit of the graph valid?
   bool IsValid() const {
-    return errors_.IsEmpty();
+    return errors_.empty();
   }
 
   // Get the list of detected errors.
-  const GrowableArray<std::string>& GetErrors() const {
+  const std::vector<std::string>& GetErrors() const {
     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_[i] << std::endl;
+    }
+  }
+
  protected:
   ArenaAllocator* const allocator_;
   // The block currently visited.
   HBasicBlock* current_block_ = nullptr;
   // Errors encountered while checking the graph.
-  GrowableArray<std::string> errors_;
+  std::vector<std::string> errors_;
 
  private:
+  // String displayed before dumped errors.
+  const char* const dump_prefix_;
+  ArenaBitVector seen_ids_;
+
   DISALLOW_COPY_AND_ASSIGN(GraphChecker);
 };
 
@@ -63,16 +81,27 @@
   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).
+  void Run() OVERRIDE {
+    // 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;
+  void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
   // Loop-related checks from block `loop_header`.
   void CheckLoop(HBasicBlock* loop_header);
 
   // Perform SSA form checks on instructions.
-  virtual void VisitInstruction(HInstruction* instruction) OVERRIDE;
-  virtual void VisitPhi(HPhi* phi) OVERRIDE;
+  void VisitInstruction(HInstruction* instruction) OVERRIDE;
+  void VisitPhi(HPhi* phi) OVERRIDE;
+  void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
+  void VisitCondition(HCondition* op) OVERRIDE;
+  void VisitIf(HIf* instruction) OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SSAChecker);
diff --git a/compiler/optimizing/graph_checker_test.cc b/compiler/optimizing/graph_checker_test.cc
index ea06920..923468f 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());
 }
 
@@ -62,10 +62,10 @@
   ASSERT_NE(graph, nullptr);
 
   graph->BuildDominatorTree();
-  graph->TransformToSSA();
+  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 0fb4737..d7dcb4c 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -17,7 +17,6 @@
 #include "graph_visualizer.h"
 
 #include "code_generator.h"
-#include "driver/dex_compilation_unit.h"
 #include "nodes.h"
 #include "ssa_liveness_analysis.h"
 
@@ -31,10 +30,12 @@
   HGraphVisualizerPrinter(HGraph* graph,
                           std::ostream& output,
                           const char* pass_name,
+                          bool is_after_pass,
                           const CodeGenerator& codegen)
       : HGraphVisitor(graph),
         output_(output),
         pass_name_(pass_name),
+        is_after_pass_(is_after_pass),
         codegen_(codegen),
         indent_(0) {}
 
@@ -67,7 +68,7 @@
 
   void PrintTime(const char* name) {
     AddIndent();
-    output_ << name << " " << time(NULL) << std::endl;
+    output_ << name << " " << time(nullptr) << std::endl;
   }
 
   void PrintInt(const char* name, int value) {
@@ -120,13 +121,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().RegId());
-      } else {
-        codegen_.DumpCoreRegister(output_, location.reg().RegId());
-      }
+      codegen_.DumpCoreRegister(output_, location.reg());
+    } else if (location.IsFpuRegister()) {
+      codegen_.DumpFloatingPointRegister(output_, location.reg());
     } else if (location.IsConstant()) {
       output_ << "constant";
       HConstant* constant = location.GetConstant();
@@ -139,29 +138,54 @@
       output_ << "invalid";
     } else if (location.IsStackSlot()) {
       output_ << location.GetStackIndex() << "(sp)";
+    } else if (location.IsFpuRegisterPair()) {
+      codegen_.DumpFloatingPointRegister(output_, location.low());
+      output_ << " and ";
+      codegen_.DumpFloatingPointRegister(output_, location.high());
+    } else if (location.IsRegisterPair()) {
+      codegen_.DumpCoreRegister(output_, location.low());
+      output_ << " and ";
+      codegen_.DumpCoreRegister(output_, location.high());
     } else {
       DCHECK(location.IsDoubleStackSlot());
       output_ << "2x" << location.GetStackIndex() << "(sp)";
     }
   }
 
-  void VisitParallelMove(HParallelMove* instruction) {
-    output_ << instruction->DebugName();
+  void VisitParallelMove(HParallelMove* instruction) OVERRIDE {
     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_ << ", ";
       }
     }
     output_ << ")";
+    output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
   }
 
-  void VisitInstruction(HInstruction* instruction) {
+  void VisitIntConstant(HIntConstant* instruction) OVERRIDE {
+    output_ << " " << instruction->GetValue();
+  }
+
+  void VisitLongConstant(HLongConstant* instruction) OVERRIDE {
+    output_ << " " << instruction->GetValue();
+  }
+
+  void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE {
+    output_ << " " << instruction->GetValue();
+  }
+
+  void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE {
+    output_ << " " << instruction->GetValue();
+  }
+
+  void PrintInstruction(HInstruction* instruction) {
     output_ << instruction->DebugName();
+    instruction->Accept(this);
     if (instruction->InputCount() > 0) {
       output_ << " [ ";
       for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
@@ -182,15 +206,16 @@
       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() << ")";
     }
   }
 
@@ -202,19 +227,20 @@
       int bci = 0;
       output_ << bci << " " << instruction->NumberOfUses()
               << " " << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
-      instruction->Accept(this);
+      PrintInstruction(instruction);
       output_ << kEndInstructionMarker << std::endl;
     }
   }
 
   void Run() {
     StartTag("cfg");
-    PrintProperty("name", pass_name_);
+    std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
+    PrintProperty("name", pass_desc.c_str());
     VisitInsertionOrder();
     EndTag("cfg");
   }
 
-  void VisitBasicBlock(HBasicBlock* block) {
+  void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
     StartTag("block");
     PrintProperty("name", "B", block->GetBlockId());
     if (block->GetLifetimeStart() != kNoLifetime) {
@@ -260,6 +286,7 @@
  private:
   std::ostream& output_;
   const char* pass_name_;
+  const bool is_after_pass_;
   const CodeGenerator& codegen_;
   size_t indent_;
 
@@ -270,49 +297,29 @@
                                    HGraph* graph,
                                    const char* string_filter,
                                    const CodeGenerator& codegen,
-                                   const DexCompilationUnit& cu)
-    : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
+                                   const char* method_name)
+  : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
   if (output == nullptr) {
     return;
   }
-  std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
-  if (pretty_name.find(string_filter) == std::string::npos) {
+  if (strstr(method_name, string_filter) == nullptr) {
     return;
   }
 
   is_enabled_ = true;
-  HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
+  HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
   printer.StartTag("compilation");
-  printer.PrintProperty("name", pretty_name.c_str());
-  printer.PrintProperty("method", pretty_name.c_str());
+  printer.PrintProperty("name", method_name);
+  printer.PrintProperty("method", method_name);
   printer.PrintTime("date");
   printer.EndTag("compilation");
 }
 
-HGraphVisualizer::HGraphVisualizer(std::ostream* output,
-                                   HGraph* graph,
-                                   const CodeGenerator& codegen,
-                                   const char* name)
-    : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
-  if (output == nullptr) {
-    return;
+void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
+  if (is_enabled_) {
+    HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
+    printer.Run();
   }
-
-  is_enabled_ = true;
-  HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
-  printer.StartTag("compilation");
-  printer.PrintProperty("name", name);
-  printer.PrintProperty("method", name);
-  printer.PrintTime("date");
-  printer.EndTag("compilation");
-}
-
-void HGraphVisualizer::DumpGraph(const char* pass_name) {
-  if (!is_enabled_) {
-    return;
-  }
-  HGraphVisualizerPrinter printer(graph_, *output_, pass_name, codegen_);
-  printer.Run();
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 6e2c6fd..b90d15e 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -17,7 +17,9 @@
 #ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
 #define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
 
-#include "utils/allocation.h"
+#include <ostream>
+
+#include "base/value_object.h"
 
 namespace art {
 
@@ -28,40 +30,20 @@
 // TODO: Create an analysis/optimization abstraction.
 static const char* kLivenessPassName = "liveness";
 static const char* kRegisterAllocatorPassName = "register";
-static const char* kGVNPassName = "gvn";
 
 /**
- * If enabled, emits compilation information suitable for the c1visualizer tool
- * and IRHydra.
- * Currently only works if the compiler is single threaded.
+ * This class outputs the HGraph in the C1visualizer format.
+ * Note: Currently only works if the compiler is single threaded.
  */
 class HGraphVisualizer : public ValueObject {
  public:
-  /**
-   * If output is not null, and the method name of the dex compilation
-   * unit contains `string_filter`, the compilation information will be
-   * emitted.
-   */
   HGraphVisualizer(std::ostream* output,
                    HGraph* graph,
                    const char* string_filter,
                    const CodeGenerator& codegen,
-                   const DexCompilationUnit& cu);
+                   const char* method_name);
 
-  /**
-   * Version of `HGraphVisualizer` for unit testing, that is when a
-   * `DexCompilationUnit` is not available.
-   */
-  HGraphVisualizer(std::ostream* output,
-                   HGraph* graph,
-                   const CodeGenerator& codegen,
-                   const char* name);
-
-  /**
-   * If this visualizer is enabled, emit the compilation information
-   * in `output_`.
-   */
-  void DumpGraph(const char* pass_name);
+  void DumpGraph(const char* pass_name, bool is_after_pass = true) const;
 
  private:
   std::ostream* const output_;
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index 027b3d4..6e5f1bd 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -54,8 +54,9 @@
 
     SideEffects effects = SideEffects::None();
     // Update `effects` with the side effects of all instructions in this block.
-    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-      HInstruction* instruction = it.Current();
+    for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
+         inst_it.Advance()) {
+      HInstruction* instruction = inst_it.Current();
       effects = effects.Union(instruction->GetSideEffects());
       if (effects.HasAllSideEffects()) {
         break;
@@ -90,29 +91,38 @@
   return block_effects_.Get(block->GetBlockId());
 }
 
-static bool IsLoopExit(HBasicBlock* block, HBasicBlock* successor) {
-  HLoopInformation* block_info = block->GetLoopInformation();
-  HLoopInformation* other_info = successor->GetLoopInformation();
-  return block_info != other_info && (other_info == nullptr || block_info->IsIn(*other_info));
-}
-
 void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) {
-  if (kIsDebugBuild) {
-    // Check that all non back-edge processors have been visited.
-    for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
-      HBasicBlock* predecessor = block->GetPredecessors().Get(i);
-      DCHECK(visited_.Get(predecessor->GetBlockId())
-             || (block->GetLoopInformation() != nullptr
-                 && (block->GetLoopInformation()->GetBackEdges().Get(0) == predecessor)));
+  ValueSet* set = nullptr;
+  const GrowableArray<HBasicBlock*>& predecessors = block->GetPredecessors();
+  if (predecessors.Size() == 0 || predecessors.Get(0)->IsEntryBlock()) {
+    // The entry block should only accumulate constant instructions, and
+    // the builder puts constants only in the entry block.
+    // Therefore, there is no need to propagate the value set to the next block.
+    set = new (allocator_) ValueSet(allocator_);
+  } else {
+    HBasicBlock* dominator = block->GetDominator();
+    set = sets_.Get(dominator->GetBlockId())->Copy();
+    if (dominator->GetSuccessors().Size() != 1 || dominator->GetSuccessors().Get(0) != block) {
+      // We have to copy if the dominator has other successors, or `block` is not a successor
+      // of the dominator.
+      set = set->Copy();
     }
-    visited_.Put(block->GetBlockId(), true);
+    if (!set->IsEmpty()) {
+      if (block->IsLoopHeader()) {
+        DCHECK_EQ(block->GetDominator(), block->GetLoopInformation()->GetPreHeader());
+        set->Kill(GetLoopEffects(block));
+      } else if (predecessors.Size() > 1) {
+        for (size_t i = 0, e = predecessors.Size(); i < e; ++i) {
+          set->IntersectionWith(sets_.Get(predecessors.Get(i)->GetBlockId()));
+          if (set->IsEmpty()) {
+            break;
+          }
+        }
+      }
+    }
   }
 
-  ValueSet* set = sets_.Get(block->GetBlockId());
-
-  if (block->IsLoopHeader()) {
-    set->Kill(GetLoopEffects(block));
-  }
+  sets_.Put(block->GetBlockId(), set);
 
   HInstruction* current = block->GetFirstInstruction();
   while (current != nullptr) {
@@ -130,57 +140,6 @@
     }
     current = next;
   }
-
-  if (block == graph_->GetEntryBlock()) {
-    // The entry block should only accumulate constant instructions, and
-    // the builder puts constants only in the entry block.
-    // Therefore, there is no need to propagate the value set to the next block.
-    DCHECK_EQ(block->GetDominatedBlocks().Size(), 1u);
-    HBasicBlock* dominated = block->GetDominatedBlocks().Get(0);
-    sets_.Put(dominated->GetBlockId(), new (allocator_) ValueSet(allocator_));
-    return;
-  }
-
-  // Copy the value set to dominated blocks. We can re-use
-  // the current set for the last dominated block because we are done visiting
-  // this block.
-  for (size_t i = 0, e = block->GetDominatedBlocks().Size(); i < e; ++i) {
-    HBasicBlock* dominated = block->GetDominatedBlocks().Get(i);
-    sets_.Put(dominated->GetBlockId(), i == e - 1 ? set : set->Copy());
-  }
-
-  // Kill instructions in the value set of each successor. If the successor
-  // is a loop exit, then we use the side effects of the loop. If not, we use
-  // the side effects of this block.
-  for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
-    HBasicBlock* successor = block->GetSuccessors().Get(i);
-    if (successor->IsLoopHeader()
-        && successor->GetLoopInformation()->GetBackEdges().Get(0) == block) {
-      // In case of a back edge, we already have visited the loop header.
-      // We should not update its value set, because the last dominated block
-      // of the loop header uses the same value set.
-      DCHECK(visited_.Get(successor->GetBlockId()));
-      continue;
-    }
-    DCHECK(!visited_.Get(successor->GetBlockId()));
-    ValueSet* successor_set = sets_.Get(successor->GetBlockId());
-    // The dominator sets the set, and we are guaranteed to have visited it already.
-    DCHECK(successor_set != nullptr);
-
-    // If this block dominates this successor there is nothing to do.
-    // Also if the set is empty, there is nothing to kill.
-    if (successor->GetDominator() != block && !successor_set->IsEmpty()) {
-      if (block->IsInLoop() && IsLoopExit(block, successor)) {
-        // All instructions killed in the loop must be killed for a loop exit.
-        SideEffects effects = GetLoopEffects(block->GetLoopInformation()->GetHeader());
-        sets_.Get(successor->GetBlockId())->Kill(effects);
-      } else {
-        // Following block (that might be in the same loop).
-        // Just kill instructions based on this block's side effects.
-        sets_.Get(successor->GetBlockId())->Kill(GetBlockEffects(block));
-      }
-    }
-  }
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index 41b3ceb..81f2c3f 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -17,8 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_GVN_H_
 #define ART_COMPILER_OPTIMIZING_GVN_H_
 
-#include <gtest/gtest.h>
 #include "nodes.h"
+#include "optimization.h"
 
 namespace art {
 
@@ -26,7 +26,7 @@
  * A node in the collision list of a ValueSet. Encodes the instruction,
  * the hash code, and the next node in the collision list.
  */
-class ValueSetNode : public ArenaObject {
+class ValueSetNode : public ArenaObject<kArenaAllocMisc> {
  public:
   ValueSetNode(HInstruction* instruction, size_t hash_code, ValueSetNode* next)
       : instruction_(instruction), hash_code_(hash_code), next_(next) {}
@@ -53,7 +53,7 @@
  * if there is one in the set. In GVN, we would say those instructions have the
  * same "number".
  */
-class ValueSet : public ArenaObject {
+class ValueSet : public ArenaObject<kArenaAllocMisc> {
  public:
   explicit ValueSet(ArenaAllocator* allocator)
       : allocator_(allocator), number_of_entries_(0), collisions_(nullptr) {
@@ -96,6 +96,26 @@
     return nullptr;
   }
 
+  // Returns whether `instruction` is in the set.
+  HInstruction* IdentityLookup(HInstruction* instruction) const {
+    size_t hash_code = instruction->ComputeHashCode();
+    size_t index = hash_code % kDefaultNumberOfEntries;
+    HInstruction* existing = table_[index];
+    if (existing != nullptr && existing == instruction) {
+      return existing;
+    }
+
+    for (ValueSetNode* node = collisions_; node != nullptr; node = node->GetNext()) {
+      if (node->GetHashCode() == hash_code) {
+        existing = node->GetInstruction();
+        if (existing == instruction) {
+          return existing;
+        }
+      }
+    }
+    return nullptr;
+  }
+
   // Removes all instructions in the set that are affected by the given side effects.
   void Kill(SideEffects side_effects) {
     for (size_t i = 0; i < kDefaultNumberOfEntries; ++i) {
@@ -106,9 +126,9 @@
       }
     }
 
-    ValueSetNode* current = collisions_;
-    ValueSetNode* previous = nullptr;
-    while (current != nullptr) {
+    for (ValueSetNode* current = collisions_, *previous = nullptr;
+         current != nullptr;
+         current = current->GetNext()) {
       HInstruction* instruction = current->GetInstruction();
       if (instruction->GetSideEffects().DependsOn(side_effects)) {
         if (previous == nullptr) {
@@ -120,7 +140,6 @@
       } else {
         previous = current;
       }
-      current = current->GetNext();
     }
   }
 
@@ -143,6 +162,44 @@
     return copy;
   }
 
+  void Clear() {
+    number_of_entries_ = 0;
+    collisions_ = nullptr;
+    for (size_t i = 0; i < kDefaultNumberOfEntries; ++i) {
+      table_[i] = nullptr;
+    }
+  }
+
+  // Update this `ValueSet` by intersecting with instructions in `other`.
+  void IntersectionWith(ValueSet* other) {
+    if (IsEmpty()) {
+      return;
+    } else if (other->IsEmpty()) {
+      Clear();
+    } else {
+      for (size_t i = 0; i < kDefaultNumberOfEntries; ++i) {
+        if (table_[i] != nullptr && other->IdentityLookup(table_[i]) == nullptr) {
+          --number_of_entries_;
+          table_[i] = nullptr;
+        }
+      }
+      for (ValueSetNode* current = collisions_, *previous = nullptr;
+           current != nullptr;
+           current = current->GetNext()) {
+        if (other->IdentityLookup(current->GetInstruction()) == nullptr) {
+          if (previous == nullptr) {
+            collisions_ = current->GetNext();
+          } else {
+            previous->SetNext(current->GetNext());
+          }
+          --number_of_entries_;
+        } else {
+          previous = current;
+        }
+      }
+    }
+  }
+
   bool IsEmpty() const { return number_of_entries_ == 0; }
   size_t GetNumberOfEntries() const { return number_of_entries_; }
 
@@ -169,17 +226,15 @@
 class GlobalValueNumberer : public ValueObject {
  public:
   GlobalValueNumberer(ArenaAllocator* allocator, HGraph* graph)
-      : allocator_(allocator),
-        graph_(graph),
+      : graph_(graph),
+        allocator_(allocator),
         block_effects_(allocator, graph->GetBlocks().Size()),
         loop_effects_(allocator, graph->GetBlocks().Size()),
-        sets_(allocator, graph->GetBlocks().Size()),
-        visited_(allocator, graph->GetBlocks().Size()) {
+        sets_(allocator, graph->GetBlocks().Size()) {
     size_t number_of_blocks = graph->GetBlocks().Size();
     block_effects_.SetSize(number_of_blocks);
     loop_effects_.SetSize(number_of_blocks);
     sets_.SetSize(number_of_blocks);
-    visited_.SetSize(number_of_blocks);
 
     for (size_t i = 0; i < number_of_blocks; ++i) {
       block_effects_.Put(i, SideEffects::None());
@@ -202,8 +257,9 @@
   SideEffects GetLoopEffects(HBasicBlock* block) const;
   SideEffects GetBlockEffects(HBasicBlock* block) const;
 
+  HGraph* graph_;
+
   ArenaAllocator* const allocator_;
-  HGraph* const graph_;
 
   // Side effects of individual blocks, that is the union of the side effects
   // of the instructions in the block.
@@ -218,13 +274,23 @@
   // in the path from the dominator to the block.
   GrowableArray<ValueSet*> sets_;
 
-  // Mark visisted blocks. Only used for debugging.
-  GrowableArray<bool> visited_;
-
-  FRIEND_TEST(GVNTest, LoopSideEffects);
+  ART_FRIEND_TEST(GVNTest, LoopSideEffects);
   DISALLOW_COPY_AND_ASSIGN(GlobalValueNumberer);
 };
 
+class GVNOptimization : public HOptimization {
+ public:
+  explicit GVNOptimization(HGraph* graph) : HOptimization(graph, true, "GVN") {}
+
+  void Run() OVERRIDE {
+    GlobalValueNumberer gvn(graph_->GetArena(), graph_);
+    gvn.Run();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GVNOptimization);
+};
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_GVN_H_
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index ad6e338..48f1ea9 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -40,18 +40,22 @@
   entry->AddSuccessor(block);
 
   block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
+          MemberOffset(42), false));
   block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
+          MemberOffset(42), false));
   HInstruction* to_remove = block->GetLastInstruction();
   block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(43)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
+          MemberOffset(43), false));
   HInstruction* different_offset = block->GetLastInstruction();
   // Kill the value.
   block->AddInstruction(new (&allocator) HInstanceFieldSet(
-      parameter, parameter, Primitive::kPrimNot, MemberOffset(42)));
+      parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
   block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
+          MemberOffset(42), false));
   HInstruction* use_after_kill = block->GetLastInstruction();
   block->AddInstruction(new (&allocator) HExit());
 
@@ -59,8 +63,7 @@
   ASSERT_EQ(different_offset->GetBlock(), block);
   ASSERT_EQ(use_after_kill->GetBlock(), block);
 
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
+  graph->TryBuildingSsa();
   GlobalValueNumberer(&allocator, graph).Run();
 
   ASSERT_TRUE(to_remove->GetBlock() == nullptr);
@@ -83,7 +86,8 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
   block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
 
   block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
   HBasicBlock* then = new (&allocator) HBasicBlock(graph);
@@ -99,17 +103,19 @@
   else_->AddSuccessor(join);
 
   then->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   then->AddInstruction(new (&allocator) HGoto());
   else_->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   else_->AddInstruction(new (&allocator) HGoto());
   join->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   join->AddInstruction(new (&allocator) HExit());
 
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
+  graph->TryBuildingSsa();
   GlobalValueNumberer(&allocator, graph).Run();
 
   // Check that all field get instructions have been GVN'ed.
@@ -134,7 +140,8 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
   block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   block->AddInstruction(new (&allocator) HGoto());
 
   HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
@@ -150,22 +157,25 @@
   loop_body->AddSuccessor(loop_header);
 
   loop_header->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
   loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
 
   // Kill inside the loop body to prevent field gets inside the loop header
   // and the body to be GVN'ed.
   loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(
-      parameter, parameter, Primitive::kPrimNot, MemberOffset(42)));
+      parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
   HInstruction* field_set = loop_body->GetLastInstruction();
   loop_body->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
   loop_body->AddInstruction(new (&allocator) HGoto());
 
   exit->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, MemberOffset(42)));
+      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
+          MemberOffset(42), false));
   HInstruction* field_get_in_exit = exit->GetLastInstruction();
   exit->AddInstruction(new (&allocator) HExit());
 
@@ -173,9 +183,7 @@
   ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
   ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
 
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
+  graph->TryBuildingSsa();
   GlobalValueNumberer(&allocator, graph).Run();
 
   // Check that all field get instructions are still there.
@@ -237,9 +245,7 @@
   inner_loop_exit->AddInstruction(new (&allocator) HGoto());
   outer_loop_exit->AddInstruction(new (&allocator) HExit());
 
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
+  graph->TryBuildingSsa();
 
   ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
       *outer_loop_header->GetLoopInformation()));
@@ -248,7 +254,7 @@
   {
     // Make one block with a side effect.
     entry->AddInstruction(new (&allocator) HInstanceFieldSet(
-        parameter, parameter, Primitive::kPrimNot, MemberOffset(42)));
+        parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
 
     GlobalValueNumberer gvn(&allocator, graph);
     gvn.Run();
@@ -262,7 +268,7 @@
   {
     outer_loop_body->InsertInstructionBefore(
         new (&allocator) HInstanceFieldSet(
-            parameter, parameter, Primitive::kPrimNot, MemberOffset(42)),
+            parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
         outer_loop_body->GetLastInstruction());
 
     GlobalValueNumberer gvn(&allocator, graph);
@@ -279,7 +285,7 @@
     outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
     inner_loop_body->InsertInstructionBefore(
         new (&allocator) HInstanceFieldSet(
-            parameter, parameter, Primitive::kPrimNot, MemberOffset(42)),
+            parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
         inner_loop_body->GetLastInstruction());
 
     GlobalValueNumberer gvn(&allocator, graph);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
new file mode 100644
index 0000000..532167c
--- /dev/null
+++ b/compiler/optimizing/inliner.cc
@@ -0,0 +1,221 @@
+/*
+ * 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 "inliner.h"
+
+#include "builder.h"
+#include "class_linker.h"
+#include "constant_folding.h"
+#include "dead_code_elimination.h"
+#include "driver/compiler_driver-inl.h"
+#include "driver/dex_compilation_unit.h"
+#include "instruction_simplifier.h"
+#include "mirror/art_method-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/dex_cache.h"
+#include "nodes.h"
+#include "register_allocator.h"
+#include "ssa_phi_elimination.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+
+static constexpr int kMaxInlineCodeUnits = 100;
+static constexpr int kMaxInlineNumberOfBlocks = 3;
+
+void HInliner::Run() {
+  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
+    for (HInstructionIterator instr_it(it.Current()->GetInstructions());
+         !instr_it.Done();
+         instr_it.Advance()) {
+      HInvokeStaticOrDirect* current = instr_it.Current()->AsInvokeStaticOrDirect();
+      if (current != nullptr) {
+        if (!TryInline(current, current->GetDexMethodIndex(), current->GetInvokeType())) {
+          if (kIsDebugBuild) {
+            std::string callee_name =
+                PrettyMethod(current->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile());
+            bool should_inline = callee_name.find("$inline$") != std::string::npos;
+            CHECK(!should_inline) << "Could not inline " << callee_name;
+          }
+        }
+      }
+    }
+  }
+}
+
+bool HInliner::TryInline(HInvoke* invoke_instruction,
+                         uint32_t method_index,
+                         InvokeType invoke_type) const {
+  ScopedObjectAccess soa(Thread::Current());
+  const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
+  VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, outer_dex_file);
+
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(
+      hs.NewHandle(outer_compilation_unit_.GetClassLinker()->FindDexCache(outer_dex_file)));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(outer_compilation_unit_.GetClassLoader())));
+  Handle<mirror::ArtMethod> resolved_method(hs.NewHandle(
+      compiler_driver_->ResolveMethod(
+          soa, dex_cache, class_loader, &outer_compilation_unit_, method_index, invoke_type)));
+
+  if (resolved_method.Get() == nullptr) {
+    VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, outer_dex_file);
+    return false;
+  }
+
+  if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) {
+    VLOG(compiler) << "Did not inline "
+                   << PrettyMethod(method_index, outer_dex_file)
+                   << " because it is in a different dex file";
+    return false;
+  }
+
+  const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
+
+  if (code_item == nullptr) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " is not inlined because it is native";
+    return false;
+  }
+
+  if (code_item->insns_size_in_code_units_ > kMaxInlineCodeUnits) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " is too big to inline";
+    return false;
+  }
+
+  if (code_item->tries_size_ != 0) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " is not inlined because of try block";
+    return false;
+  }
+
+  if (!resolved_method->GetDeclaringClass()->IsVerified()) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " is not inlined because its class could not be verified";
+    return false;
+  }
+
+  DexCompilationUnit dex_compilation_unit(
+    nullptr,
+    outer_compilation_unit_.GetClassLoader(),
+    outer_compilation_unit_.GetClassLinker(),
+    outer_dex_file,
+    code_item,
+    resolved_method->GetDeclaringClass()->GetDexClassDefIndex(),
+    method_index,
+    resolved_method->GetAccessFlags(),
+    nullptr);
+
+  OptimizingCompilerStats inline_stats;
+  HGraphBuilder builder(graph_->GetArena(),
+                        &dex_compilation_unit,
+                        &outer_compilation_unit_,
+                        &outer_dex_file,
+                        compiler_driver_,
+                        &inline_stats);
+  HGraph* callee_graph = builder.BuildGraph(*code_item, graph_->GetCurrentInstructionId());
+
+  if (callee_graph == nullptr) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " could not be built, so cannot be inlined";
+    return false;
+  }
+
+  if (callee_graph->GetBlocks().Size() > kMaxInlineNumberOfBlocks) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " has too many blocks to be inlined: "
+                   << callee_graph->GetBlocks().Size();
+    return false;
+  }
+
+  if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph,
+                                                  compiler_driver_->GetInstructionSet())) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " cannot be inlined because of the register allocator";
+    return false;
+  }
+
+  if (!callee_graph->TryBuildingSsa()) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " could not be transformed to SSA";
+    return false;
+  }
+
+  HReversePostOrderIterator it(*callee_graph);
+  it.Advance();  // Past the entry block to avoid seeing the suspend check.
+  for (; !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    if (block->IsLoopHeader()) {
+      VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                     << " could not be inlined because it contains a loop";
+      return false;
+    }
+
+    for (HInstructionIterator instr_it(block->GetInstructions());
+         !instr_it.Done();
+         instr_it.Advance()) {
+      HInstruction* current = instr_it.Current();
+      if (current->CanThrow()) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                       << " could not be inlined because " << current->DebugName()
+                       << " can throw";
+        return false;
+      }
+
+      if (current->NeedsEnvironment()) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                       << " could not be inlined because " << current->DebugName()
+                       << " needs an environment";
+        return false;
+      }
+    }
+  }
+
+  // Run simple optimizations on the graph.
+  SsaRedundantPhiElimination redundant_phi(callee_graph);
+  SsaDeadPhiElimination dead_phi(callee_graph);
+  HDeadCodeElimination dce(callee_graph);
+  HConstantFolding fold(callee_graph);
+  InstructionSimplifier simplify(callee_graph);
+
+  HOptimization* optimizations[] = {
+    &redundant_phi,
+    &dead_phi,
+    &dce,
+    &fold,
+    &simplify,
+  };
+
+  for (size_t i = 0; i < arraysize(optimizations); ++i) {
+    HOptimization* optimization = optimizations[i];
+    optimization->Run();
+  }
+
+  callee_graph->InlineInto(graph_, invoke_instruction);
+
+  // Now that we have inlined the callee, we need to update the next
+  // instruction id of the caller, so that new instructions added
+  // after optimizations get a unique id.
+  graph_->SetCurrentInstructionId(callee_graph->GetNextInstructionId());
+  VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
+  outer_stats_->RecordStat(kInlinedInvoke);
+  return true;
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
new file mode 100644
index 0000000..370e33c
--- /dev/null
+++ b/compiler/optimizing/inliner.h
@@ -0,0 +1,56 @@
+/*
+ * 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_INLINER_H_
+#define ART_COMPILER_OPTIMIZING_INLINER_H_
+
+#include "invoke_type.h"
+#include "optimization.h"
+
+namespace art {
+
+class CompilerDriver;
+class DexCompilationUnit;
+class HGraph;
+class HInvoke;
+class OptimizingCompilerStats;
+
+class HInliner : public HOptimization {
+ public:
+  HInliner(HGraph* outer_graph,
+           const DexCompilationUnit& outer_compilation_unit,
+           CompilerDriver* compiler_driver,
+           OptimizingCompilerStats* stats)
+      : HOptimization(outer_graph, true, "inliner"),
+        outer_compilation_unit_(outer_compilation_unit),
+        compiler_driver_(compiler_driver),
+        outer_stats_(stats) {}
+
+  void Run() OVERRIDE;
+
+ private:
+  bool TryInline(HInvoke* invoke_instruction, uint32_t method_index, InvokeType invoke_type) const;
+
+  const DexCompilationUnit& outer_compilation_unit_;
+  CompilerDriver* const compiler_driver_;
+  OptimizingCompilerStats* const outer_stats_;
+
+  DISALLOW_COPY_AND_ASSIGN(HInliner);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_INLINER_H_
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index a0de73d..63bc4ae 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,11 +18,23 @@
 
 namespace art {
 
+class InstructionSimplifierVisitor : public HGraphVisitor {
+ public:
+  explicit InstructionSimplifierVisitor(HGraph* graph) : HGraphVisitor(graph) {}
+
+ private:
+  void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
+  void VisitEqual(HEqual* equal) OVERRIDE;
+  void VisitArraySet(HArraySet* equal) OVERRIDE;
+  void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
+};
+
 void InstructionSimplifier::Run() {
-  VisitInsertionOrder();
+  InstructionSimplifierVisitor visitor(graph_);
+  visitor.VisitInsertionOrder();
 }
 
-void InstructionSimplifier::VisitSuspendCheck(HSuspendCheck* check) {
+void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
   HBasicBlock* block = check->GetBlock();
   // Currently always keep the suspend check at entry.
   if (block->IsEntryBlock()) return;
@@ -38,4 +50,40 @@
   block->RemoveInstruction(check);
 }
 
+void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
+  HInstruction* input1 = equal->InputAt(0);
+  HInstruction* input2 = equal->InputAt(1);
+  if (input1->GetType() == Primitive::kPrimBoolean && input2->IsIntConstant()) {
+    if (input2->AsIntConstant()->GetValue() == 1) {
+      // Replace (bool_value == 1) with bool_value
+      equal->ReplaceWith(equal->InputAt(0));
+      equal->GetBlock()->RemoveInstruction(equal);
+    } else {
+      // We should replace (bool_value == 0) with !bool_value, but we unfortunately
+      // do not have such instruction.
+      DCHECK_EQ(input2->AsIntConstant()->GetValue(), 0);
+    }
+  }
+}
+
+void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
+  HInstruction* value = instruction->GetValue();
+  if (value->GetType() != Primitive::kPrimNot) return;
+
+  if (value->IsArrayGet()) {
+    if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
+      // If the code is just swapping elements in the array, no need for a type check.
+      instruction->ClearNeedsTypeCheck();
+    }
+  }
+}
+
+void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
+  if (instruction->GetResultType() == instruction->GetInputType()) {
+    // Remove the instruction if it's converting to the same type.
+    instruction->ReplaceWith(instruction->GetInput());
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index b2f3f52..7068c7f 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -18,20 +18,19 @@
 #define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_H_
 
 #include "nodes.h"
+#include "optimization.h"
 
 namespace art {
 
 /**
  * Implements optimizations specific to each instruction.
  */
-class InstructionSimplifier : public HGraphVisitor {
+class InstructionSimplifier : public HOptimization {
  public:
-  explicit InstructionSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
+  explicit InstructionSimplifier(HGraph* graph)
+    : HOptimization(graph, true, "instruction_simplifier") {}
 
-  void Run();
-
- private:
-  virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
+  void Run() OVERRIDE;
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
new file mode 100644
index 0000000..fe0e7f2
--- /dev/null
+++ b/compiler/optimizing/intrinsics.cc
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2015 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 "intrinsics.h"
+
+#include "dex/quick/dex_file_method_inliner.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "driver/compiler_driver.h"
+#include "invoke_type.h"
+#include "nodes.h"
+#include "quick/inline_method_analyser.h"
+
+namespace art {
+
+// Function that returns whether an intrinsic is static/direct or virtual.
+static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
+  switch (i) {
+    case Intrinsics::kNone:
+      return kInterface;  // Non-sensical for intrinsic.
+#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
+    case Intrinsics::k ## Name:               \
+      return IsStatic;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+  }
+  return kInterface;
+}
+
+
+
+static Primitive::Type GetType(uint64_t data, bool is_op_size) {
+  if (is_op_size) {
+    switch (static_cast<OpSize>(data)) {
+      case kSignedByte:
+        return Primitive::Type::kPrimByte;
+      case kSignedHalf:
+        return Primitive::Type::kPrimShort;
+      case k32:
+        return Primitive::Type::kPrimInt;
+      case k64:
+        return Primitive::Type::kPrimLong;
+      default:
+        LOG(FATAL) << "Unknown/unsupported op size " << data;
+        UNREACHABLE();
+    }
+  } else {
+    if ((data & kIntrinsicFlagIsLong) != 0) {
+      return Primitive::Type::kPrimLong;
+    }
+    if ((data & kIntrinsicFlagIsObject) != 0) {
+      return Primitive::Type::kPrimNot;
+    }
+    return Primitive::Type::kPrimInt;
+  }
+}
+
+static Intrinsics GetIntrinsic(InlineMethod method) {
+  switch (method.opcode) {
+    // Floating-point conversions.
+    case kIntrinsicDoubleCvt:
+      return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
+          Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
+    case kIntrinsicFloatCvt:
+      return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
+          Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
+
+    // Bit manipulations.
+    case kIntrinsicReverseBits:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::Type::kPrimInt:
+          return Intrinsics::kIntegerReverse;
+        case Primitive::Type::kPrimLong:
+          return Intrinsics::kLongReverse;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+    case kIntrinsicReverseBytes:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::Type::kPrimShort:
+          return Intrinsics::kShortReverseBytes;
+        case Primitive::Type::kPrimInt:
+          return Intrinsics::kIntegerReverseBytes;
+        case Primitive::Type::kPrimLong:
+          return Intrinsics::kLongReverseBytes;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+
+    // Abs.
+    case kIntrinsicAbsDouble:
+      return Intrinsics::kMathAbsDouble;
+    case kIntrinsicAbsFloat:
+      return Intrinsics::kMathAbsFloat;
+    case kIntrinsicAbsInt:
+      return Intrinsics::kMathAbsInt;
+    case kIntrinsicAbsLong:
+      return Intrinsics::kMathAbsLong;
+
+    // Min/max.
+    case kIntrinsicMinMaxDouble:
+      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
+          Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
+    case kIntrinsicMinMaxFloat:
+      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
+          Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
+    case kIntrinsicMinMaxInt:
+      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
+          Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
+    case kIntrinsicMinMaxLong:
+      return ((method.d.data & kIntrinsicFlagMin) == 0) ?
+          Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
+
+    // Misc math.
+    case kIntrinsicSqrt:
+      return Intrinsics::kMathSqrt;
+    case kIntrinsicCeil:
+      return Intrinsics::kMathCeil;
+    case kIntrinsicFloor:
+      return Intrinsics::kMathFloor;
+    case kIntrinsicRint:
+      return Intrinsics::kMathRint;
+    case kIntrinsicRoundDouble:
+      return Intrinsics::kMathRoundDouble;
+    case kIntrinsicRoundFloat:
+      return Intrinsics::kMathRoundFloat;
+
+    // System.arraycopy.
+    case kIntrinsicSystemArrayCopyCharArray:
+      return Intrinsics::kSystemArrayCopyChar;
+
+    // Thread.currentThread.
+    case kIntrinsicCurrentThread:
+      return  Intrinsics::kThreadCurrentThread;
+
+    // Memory.peek.
+    case kIntrinsicPeek:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::Type::kPrimByte:
+          return Intrinsics::kMemoryPeekByte;
+        case Primitive::Type::kPrimShort:
+          return Intrinsics::kMemoryPeekShortNative;
+        case Primitive::Type::kPrimInt:
+          return Intrinsics::kMemoryPeekIntNative;
+        case Primitive::Type::kPrimLong:
+          return Intrinsics::kMemoryPeekLongNative;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+
+    // Memory.poke.
+    case kIntrinsicPoke:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::Type::kPrimByte:
+          return Intrinsics::kMemoryPokeByte;
+        case Primitive::Type::kPrimShort:
+          return Intrinsics::kMemoryPokeShortNative;
+        case Primitive::Type::kPrimInt:
+          return Intrinsics::kMemoryPokeIntNative;
+        case Primitive::Type::kPrimLong:
+          return Intrinsics::kMemoryPokeLongNative;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+
+    // String.
+    case kIntrinsicCharAt:
+      return Intrinsics::kStringCharAt;
+    case kIntrinsicCompareTo:
+      return Intrinsics::kStringCompareTo;
+    case kIntrinsicIsEmptyOrLength:
+      return ((method.d.data & kIntrinsicFlagIsEmpty) == 0) ?
+          Intrinsics::kStringLength : Intrinsics::kStringIsEmpty;
+    case kIntrinsicIndexOf:
+      return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
+          Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
+
+    case kIntrinsicCas:
+      switch (GetType(method.d.data, false)) {
+        case Primitive::Type::kPrimNot:
+          return Intrinsics::kUnsafeCASObject;
+        case Primitive::Type::kPrimInt:
+          return Intrinsics::kUnsafeCASInt;
+        case Primitive::Type::kPrimLong:
+          return Intrinsics::kUnsafeCASLong;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+    case kIntrinsicUnsafeGet: {
+      const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
+      switch (GetType(method.d.data, false)) {
+        case Primitive::Type::kPrimInt:
+          return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
+        case Primitive::Type::kPrimLong:
+          return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+    }
+    case kIntrinsicUnsafePut: {
+      enum Sync { kNoSync, kVolatile, kOrdered };
+      const Sync sync =
+          ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
+          ((method.d.data & kIntrinsicFlagIsOrdered) != 0)  ? kOrdered :
+                                                              kNoSync;
+      switch (GetType(method.d.data, false)) {
+        case Primitive::Type::kPrimInt:
+          switch (sync) {
+            case kNoSync:
+              return Intrinsics::kUnsafePut;
+            case kVolatile:
+              return Intrinsics::kUnsafePutVolatile;
+            case kOrdered:
+              return Intrinsics::kUnsafePutOrdered;
+          }
+          break;
+        case Primitive::Type::kPrimLong:
+          switch (sync) {
+            case kNoSync:
+              return Intrinsics::kUnsafePutLong;
+            case kVolatile:
+              return Intrinsics::kUnsafePutLongVolatile;
+            case kOrdered:
+              return Intrinsics::kUnsafePutLongOrdered;
+          }
+          break;
+        case Primitive::Type::kPrimNot:
+          switch (sync) {
+            case kNoSync:
+              return Intrinsics::kUnsafePutObject;
+            case kVolatile:
+              return Intrinsics::kUnsafePutObjectVolatile;
+            case kOrdered:
+              return Intrinsics::kUnsafePutObjectOrdered;
+          }
+          break;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+      break;
+    }
+
+    // Virtual cases.
+
+    case kIntrinsicReferenceGetReferent:
+      return Intrinsics::kReferenceGetReferent;
+
+    // Quick inliner cases. Remove after refactoring. They are here so that we can use the
+    // compiler to warn on missing cases.
+
+    case kInlineOpNop:
+    case kInlineOpReturnArg:
+    case kInlineOpNonWideConst:
+    case kInlineOpIGet:
+    case kInlineOpIPut:
+      return Intrinsics::kNone;
+
+    // No default case to make the compiler warn on missing cases.
+  }
+  return Intrinsics::kNone;
+}
+
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
+  // The DexFileMethodInliner should have checked whether the methods are agreeing with
+  // what we expect, i.e., static methods are called as such. Add another check here for
+  // our expectations:
+  // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
+  // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
+  // functions that will perform a check inline. If the precise type is known, however,
+  // the instruction will be sharpened to an InvokeStaticOrDirect.
+  InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
+  InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
+      invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
+      invoke->IsInvokeVirtual() ? kVirtual : kSuper;
+  switch (intrinsic_type) {
+    case kStatic:
+      return (invoke_type == kStatic);
+    case kDirect:
+      return (invoke_type == kDirect);
+    case kVirtual:
+      // Call might be devirtualized.
+      return (invoke_type == kVirtual || invoke_type == kDirect);
+
+    default:
+      return false;
+  }
+}
+
+// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
+void IntrinsicsRecognizer::Run() {
+  DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(dex_file_);
+  DCHECK(inliner != nullptr);
+
+  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
+         inst_it.Advance()) {
+      HInstruction* inst = inst_it.Current();
+      if (inst->IsInvoke()) {
+        HInvoke* invoke = inst->AsInvoke();
+        InlineMethod method;
+        if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
+          Intrinsics intrinsic = GetIntrinsic(method);
+
+          if (intrinsic != Intrinsics::kNone) {
+            if (!CheckInvokeType(intrinsic, invoke)) {
+              LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
+                           << intrinsic << " for "
+                           << PrettyMethod(invoke->GetDexMethodIndex(), *dex_file_);
+            } else {
+              invoke->SetIntrinsic(intrinsic);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
+  switch (intrinsic) {
+    case Intrinsics::kNone:
+      os << "No intrinsic.";
+      break;
+#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
+    case Intrinsics::k ## Name: \
+      os << # Name; \
+      break;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef STATIC_INTRINSICS_LIST
+#undef VIRTUAL_INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+  }
+  return os;
+}
+
+}  // namespace art
+
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
new file mode 100644
index 0000000..29cc8ef
--- /dev/null
+++ b/compiler/optimizing/intrinsics.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 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_INTRINSICS_H_
+#define ART_COMPILER_OPTIMIZING_INTRINSICS_H_
+
+#include "nodes.h"
+#include "optimization.h"
+
+namespace art {
+
+class CompilerDriver;
+class DexFile;
+
+// Recognize intrinsics from HInvoke nodes.
+class IntrinsicsRecognizer : public HOptimization {
+ public:
+  IntrinsicsRecognizer(HGraph* graph, const DexFile* dex_file, CompilerDriver* driver)
+      : HOptimization(graph, true, "intrinsics_recognition"),
+        dex_file_(dex_file), driver_(driver) {}
+
+  void Run() OVERRIDE;
+
+ private:
+  const DexFile* dex_file_;
+  CompilerDriver* driver_;
+
+  DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
+};
+
+class IntrinsicVisitor : public ValueObject {
+ public:
+  virtual ~IntrinsicVisitor() {}
+
+  // Dispatch logic.
+
+  void Dispatch(HInvoke* invoke) {
+    switch (invoke->GetIntrinsic()) {
+      case Intrinsics::kNone:
+        return;
+#define OPTIMIZING_INTRINSICS(Name, IsStatic) \
+      case Intrinsics::k ## Name:             \
+        Visit ## Name(invoke);                \
+        return;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+
+      // Do not put a default case. That way the compiler will complain if we missed a case.
+    }
+  }
+
+  // Define visitor methods.
+
+#define OPTIMIZING_INTRINSICS(Name, IsStatic)                    \
+  virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
+  }
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+
+ protected:
+  IntrinsicVisitor() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_H_
diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h
new file mode 100644
index 0000000..29ca20c
--- /dev/null
+++ b/compiler/optimizing/intrinsics_list.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 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_INTRINSICS_LIST_H_
+#define ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
+
+// All intrinsics supported by the optimizing compiler. Format is name, then whether it is expected
+// to be a HInvokeStaticOrDirect node (compared to HInvokeVirtual).
+
+#define INTRINSICS_LIST(V) \
+  V(DoubleDoubleToRawLongBits, kStatic) \
+  V(DoubleLongBitsToDouble, kStatic) \
+  V(FloatFloatToRawIntBits, kStatic) \
+  V(FloatIntBitsToFloat, kStatic) \
+  V(IntegerReverse, kStatic) \
+  V(IntegerReverseBytes, kStatic) \
+  V(LongReverse, kStatic) \
+  V(LongReverseBytes, kStatic) \
+  V(ShortReverseBytes, kStatic) \
+  V(MathAbsDouble, kStatic) \
+  V(MathAbsFloat, kStatic) \
+  V(MathAbsLong, kStatic) \
+  V(MathAbsInt, kStatic) \
+  V(MathMinDoubleDouble, kStatic) \
+  V(MathMinFloatFloat, kStatic) \
+  V(MathMinLongLong, kStatic) \
+  V(MathMinIntInt, kStatic) \
+  V(MathMaxDoubleDouble, kStatic) \
+  V(MathMaxFloatFloat, kStatic) \
+  V(MathMaxLongLong, kStatic) \
+  V(MathMaxIntInt, kStatic) \
+  V(MathSqrt, kStatic) \
+  V(MathCeil, kStatic) \
+  V(MathFloor, kStatic) \
+  V(MathRint, kStatic) \
+  V(MathRoundDouble, kStatic) \
+  V(MathRoundFloat, kStatic) \
+  V(SystemArrayCopyChar, kStatic) \
+  V(ThreadCurrentThread, kStatic) \
+  V(MemoryPeekByte, kStatic) \
+  V(MemoryPeekIntNative, kStatic) \
+  V(MemoryPeekLongNative, kStatic) \
+  V(MemoryPeekShortNative, kStatic) \
+  V(MemoryPokeByte, kStatic) \
+  V(MemoryPokeIntNative, kStatic) \
+  V(MemoryPokeLongNative, kStatic) \
+  V(MemoryPokeShortNative, kStatic) \
+  V(StringCharAt, kDirect) \
+  V(StringCompareTo, kDirect) \
+  V(StringIsEmpty, kDirect) \
+  V(StringIndexOf, kDirect) \
+  V(StringIndexOfAfter, kDirect) \
+  V(StringLength, kDirect) \
+  V(UnsafeCASInt, kDirect) \
+  V(UnsafeCASLong, kDirect) \
+  V(UnsafeCASObject, kDirect) \
+  V(UnsafeGet, kDirect) \
+  V(UnsafeGetVolatile, kDirect) \
+  V(UnsafeGetLong, kDirect) \
+  V(UnsafeGetLongVolatile, kDirect) \
+  V(UnsafePut, kDirect) \
+  V(UnsafePutOrdered, kDirect) \
+  V(UnsafePutVolatile, kDirect) \
+  V(UnsafePutObject, kDirect) \
+  V(UnsafePutObjectOrdered, kDirect) \
+  V(UnsafePutObjectVolatile, kDirect) \
+  V(UnsafePutLong, kDirect) \
+  V(UnsafePutLongOrdered, kDirect) \
+  V(UnsafePutLongVolatile, kDirect) \
+  \
+  V(ReferenceGetReferent, kVirtual)
+
+#endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
+#undef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_   // #define is only for lint.
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
new file mode 100644
index 0000000..2c23945
--- /dev/null
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -0,0 +1,984 @@
+/*
+ * Copyright (C) 2015 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 "intrinsics_x86_64.h"
+
+#include "code_generator_x86_64.h"
+#include "entrypoints/quick/quick_entrypoints.h"
+#include "intrinsics.h"
+#include "mirror/array-inl.h"
+#include "mirror/art_method.h"
+#include "mirror/string.h"
+#include "thread.h"
+#include "utils/x86_64/assembler_x86_64.h"
+#include "utils/x86_64/constants_x86_64.h"
+
+namespace art {
+
+namespace x86_64 {
+
+static constexpr bool kIntrinsified = true;
+
+X86_64Assembler* IntrinsicCodeGeneratorX86_64::GetAssembler() {
+  return reinterpret_cast<X86_64Assembler*>(codegen_->GetAssembler());
+}
+
+ArenaAllocator* IntrinsicCodeGeneratorX86_64::GetArena() {
+  return codegen_->GetGraph()->GetArena();
+}
+
+bool IntrinsicLocationsBuilderX86_64::TryDispatch(HInvoke* invoke) {
+  Dispatch(invoke);
+  const LocationSummary* res = invoke->GetLocations();
+  return res != nullptr && res->Intrinsified();
+}
+
+#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
+
+// TODO: trg as memory.
+static void MoveFromReturnRegister(Location trg,
+                                   Primitive::Type type,
+                                   CodeGeneratorX86_64* codegen) {
+  if (!trg.IsValid()) {
+    DCHECK(type == Primitive::kPrimVoid);
+    return;
+  }
+
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      CpuRegister trg_reg = trg.AsRegister<CpuRegister>();
+      if (trg_reg.AsRegister() != RAX) {
+        __ movl(trg_reg, CpuRegister(RAX));
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      CpuRegister trg_reg = trg.AsRegister<CpuRegister>();
+      if (trg_reg.AsRegister() != RAX) {
+        __ movq(trg_reg, CpuRegister(RAX));
+      }
+      break;
+    }
+
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unexpected void type for valid location " << trg;
+      UNREACHABLE();
+
+    case Primitive::kPrimDouble: {
+      XmmRegister trg_reg = trg.AsFpuRegister<XmmRegister>();
+      if (trg_reg.AsFloatRegister() != XMM0) {
+        __ movsd(trg_reg, XmmRegister(XMM0));
+      }
+      break;
+    }
+    case Primitive::kPrimFloat: {
+      XmmRegister trg_reg = trg.AsFpuRegister<XmmRegister>();
+      if (trg_reg.AsFloatRegister() != XMM0) {
+        __ movss(trg_reg, XmmRegister(XMM0));
+      }
+      break;
+    }
+  }
+}
+
+static void MoveArguments(HInvoke* invoke, ArenaAllocator* arena, CodeGeneratorX86_64* codegen) {
+  if (invoke->InputCount() == 0) {
+    return;
+  }
+
+  LocationSummary* locations = invoke->GetLocations();
+  InvokeDexCallingConventionVisitor calling_convention_visitor;
+
+  // We're moving potentially two or more locations to locations that could overlap, so we need
+  // a parallel move resolver.
+  HParallelMove parallel_move(arena);
+
+  for (size_t i = 0; i < invoke->InputCount(); i++) {
+    HInstruction* input = invoke->InputAt(i);
+    Location cc_loc = calling_convention_visitor.GetNextLocation(input->GetType());
+    Location actual_loc = locations->InAt(i);
+
+    parallel_move.AddMove(actual_loc, cc_loc, nullptr);
+  }
+
+  codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
+}
+
+// Slow-path for fallback (calling the managed code to handle the intrinsic) in an intrinsified
+// call. This will copy the arguments into the positions for a regular call.
+//
+// Note: The actual parameters are required to be in the locations given by the invoke's location
+//       summary. If an intrinsic modifies those locations before a slowpath call, they must be
+//       restored!
+class IntrinsicSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+  explicit IntrinsicSlowPathX86_64(HInvoke* invoke) : invoke_(invoke) { }
+
+  void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
+    CodeGeneratorX86_64* codegen = down_cast<CodeGeneratorX86_64*>(codegen_in);
+    __ Bind(GetEntryLabel());
+
+    codegen->SaveLiveRegisters(invoke_->GetLocations());
+
+    MoveArguments(invoke_, codegen->GetGraph()->GetArena(), codegen);
+
+    if (invoke_->IsInvokeStaticOrDirect()) {
+      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), CpuRegister(RDI));
+    } else {
+      UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
+      UNREACHABLE();
+    }
+
+    // Copy the result back to the expected output.
+    Location out = invoke_->GetLocations()->Out();
+    if (out.IsValid()) {
+      DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
+      DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
+      MoveFromReturnRegister(out, invoke_->GetType(), codegen);
+    }
+
+    codegen->RestoreLiveRegisters(invoke_->GetLocations());
+    __ jmp(GetExitLabel());
+  }
+
+ private:
+  // The instruction where this slow path is happening.
+  HInvoke* const invoke_;
+
+  DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathX86_64);
+};
+
+#undef __
+#define __ assembler->
+
+static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresFpuRegister());
+}
+
+static void MoveFPToInt(LocationSummary* locations, bool is64bit, X86_64Assembler* assembler) {
+  Location input = locations->InAt(0);
+  Location output = locations->Out();
+  __ movd(output.AsRegister<CpuRegister>(), input.AsFpuRegister<XmmRegister>(), is64bit);
+}
+
+static void MoveIntToFP(LocationSummary* locations, bool is64bit, X86_64Assembler* assembler) {
+  Location input = locations->InAt(0);
+  Location output = locations->Out();
+  __ movd(output.AsFpuRegister<XmmRegister>(), input.AsRegister<CpuRegister>(), is64bit);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
+  CreateFPToIntLocations(arena_, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
+  CreateIntToFPLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
+  MoveFPToInt(invoke->GetLocations(), true, GetAssembler());
+}
+void IntrinsicCodeGeneratorX86_64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
+  MoveIntToFP(invoke->GetLocations(), true, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
+  CreateFPToIntLocations(arena_, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
+  CreateIntToFPLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
+  MoveFPToInt(invoke->GetLocations(), false, GetAssembler());
+}
+void IntrinsicCodeGeneratorX86_64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
+  MoveIntToFP(invoke->GetLocations(), false, GetAssembler());
+}
+
+static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+static void GenReverseBytes(LocationSummary* locations,
+                            Primitive::Type size,
+                            X86_64Assembler* assembler) {
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+
+  switch (size) {
+    case Primitive::kPrimShort:
+      // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
+      __ bswapl(out);
+      __ sarl(out, Immediate(16));
+      break;
+    case Primitive::kPrimInt:
+      __ bswapl(out);
+      break;
+    case Primitive::kPrimLong:
+      __ bswapq(out);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected size for reverse-bytes: " << size;
+      UNREACHABLE();
+  }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitIntegerReverseBytes(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitIntegerReverseBytes(HInvoke* invoke) {
+  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitLongReverseBytes(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitLongReverseBytes(HInvoke* invoke) {
+  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitShortReverseBytes(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitShortReverseBytes(HInvoke* invoke) {
+  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+}
+
+
+// TODO: Consider Quick's way of doing Double abs through integer operations, as the immediate we
+//       need is 64b.
+
+static void CreateFloatToFloatPlusTemps(ArenaAllocator* arena, HInvoke* invoke) {
+  // TODO: Enable memory operations when the assembler supports them.
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  // TODO: Allow x86 to work with memory. This requires assembler support, see below.
+  // locations->SetInAt(0, Location::Any());               // X86 can work on memory directly.
+  locations->SetOut(Location::SameAsFirstInput());
+  locations->AddTemp(Location::RequiresRegister());     // Immediate constant.
+  locations->AddTemp(Location::RequiresFpuRegister());  // FP version of above.
+}
+
+static void MathAbsFP(LocationSummary* locations, bool is64bit, X86_64Assembler* assembler) {
+  Location output = locations->Out();
+  CpuRegister cpu_temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+
+  if (output.IsFpuRegister()) {
+    // In-register
+    XmmRegister xmm_temp = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+
+    if (is64bit) {
+      __ movq(cpu_temp, Immediate(INT64_C(0x7FFFFFFFFFFFFFFF)));
+      __ movd(xmm_temp, cpu_temp);
+      __ andpd(output.AsFpuRegister<XmmRegister>(), xmm_temp);
+    } else {
+      __ movl(cpu_temp, Immediate(INT64_C(0x7FFFFFFF)));
+      __ movd(xmm_temp, cpu_temp);
+      __ andps(output.AsFpuRegister<XmmRegister>(), xmm_temp);
+    }
+  } else {
+    // TODO: update when assember support is available.
+    UNIMPLEMENTED(FATAL) << "Needs assembler support.";
+//  Once assembler support is available, in-memory operations look like this:
+//    if (is64bit) {
+//      DCHECK(output.IsDoubleStackSlot());
+//      // No 64b and with literal.
+//      __ movq(cpu_temp, Immediate(INT64_C(0x7FFFFFFFFFFFFFFF)));
+//      __ andq(Address(CpuRegister(RSP), output.GetStackIndex()), cpu_temp);
+//    } else {
+//      DCHECK(output.IsStackSlot());
+//      // Can use and with a literal directly.
+//      __ andl(Address(CpuRegister(RSP), output.GetStackIndex()), Immediate(INT64_C(0x7FFFFFFF)));
+//    }
+  }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAbsDouble(HInvoke* invoke) {
+  CreateFloatToFloatPlusTemps(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAbsDouble(HInvoke* invoke) {
+  MathAbsFP(invoke->GetLocations(), true, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAbsFloat(HInvoke* invoke) {
+  CreateFloatToFloatPlusTemps(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAbsFloat(HInvoke* invoke) {
+  MathAbsFP(invoke->GetLocations(), false, GetAssembler());
+}
+
+static void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+static void GenAbsInteger(LocationSummary* locations, bool is64bit, X86_64Assembler* assembler) {
+  Location output = locations->Out();
+  CpuRegister out = output.AsRegister<CpuRegister>();
+  CpuRegister mask = locations->GetTemp(0).AsRegister<CpuRegister>();
+
+  if (is64bit) {
+    // Create mask.
+    __ movq(mask, out);
+    __ sarq(mask, Immediate(63));
+    // Add mask.
+    __ addq(out, mask);
+    __ xorq(out, mask);
+  } else {
+    // Create mask.
+    __ movl(mask, out);
+    __ sarl(mask, Immediate(31));
+    // Add mask.
+    __ addl(out, mask);
+    __ xorl(out, mask);
+  }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAbsInt(HInvoke* invoke) {
+  CreateIntToIntPlusTemp(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAbsInt(HInvoke* invoke) {
+  GenAbsInteger(invoke->GetLocations(), false, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAbsLong(HInvoke* invoke) {
+  CreateIntToIntPlusTemp(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAbsLong(HInvoke* invoke) {
+  GenAbsInteger(invoke->GetLocations(), true, GetAssembler());
+}
+
+static void GenMinMaxFP(LocationSummary* locations, bool is_min, bool is_double,
+                        X86_64Assembler* assembler) {
+  Location op1_loc = locations->InAt(0);
+  Location op2_loc = locations->InAt(1);
+  Location out_loc = locations->Out();
+  XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
+
+  // Shortcut for same input locations.
+  if (op1_loc.Equals(op2_loc)) {
+    DCHECK(out_loc.Equals(op1_loc));
+    return;
+  }
+
+  //  (out := op1)
+  //  out <=? op2
+  //  if Nan jmp Nan_label
+  //  if out is min jmp done
+  //  if op2 is min jmp op2_label
+  //  handle -0/+0
+  //  jmp done
+  // Nan_label:
+  //  out := NaN
+  // op2_label:
+  //  out := op2
+  // done:
+  //
+  // This removes one jmp, but needs to copy one input (op1) to out.
+  //
+  // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath?
+
+  XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
+
+  Label nan, done, op2_label;
+  if (is_double) {
+    __ ucomisd(out, op2);
+  } else {
+    __ ucomiss(out, op2);
+  }
+
+  __ j(Condition::kParityEven, &nan);
+
+  __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
+  __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
+
+  // Handle 0.0/-0.0.
+  if (is_min) {
+    if (is_double) {
+      __ orpd(out, op2);
+    } else {
+      __ orps(out, op2);
+    }
+  } else {
+    if (is_double) {
+      __ andpd(out, op2);
+    } else {
+      __ andps(out, op2);
+    }
+  }
+  __ jmp(&done);
+
+  // NaN handling.
+  __ Bind(&nan);
+  CpuRegister cpu_temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+  // TODO: Literal pool. Trades 64b immediate in CPU reg for direct memory access.
+  if (is_double) {
+    __ movq(cpu_temp, Immediate(INT64_C(0x7FF8000000000000)));
+  } else {
+    __ movl(cpu_temp, Immediate(INT64_C(0x7FC00000)));
+  }
+  __ movd(out, cpu_temp, is_double);
+  __ jmp(&done);
+
+  // out := op2;
+  __ Bind(&op2_label);
+  if (is_double) {
+    __ movsd(out, op2);
+  } else {
+    __ movss(out, op2);
+  }
+
+  // Done.
+  __ Bind(&done);
+}
+
+static void CreateFPFPToFPPlusTempLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  locations->SetInAt(1, Location::RequiresFpuRegister());
+  // The following is sub-optimal, but all we can do for now. It would be fine to also accept
+  // the second input to be the output (we can simply swap inputs).
+  locations->SetOut(Location::SameAsFirstInput());
+  locations->AddTemp(Location::RequiresRegister());     // Immediate constant.
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMinDoubleDouble(HInvoke* invoke) {
+  CreateFPFPToFPPlusTempLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMinDoubleDouble(HInvoke* invoke) {
+  GenMinMaxFP(invoke->GetLocations(), true, true, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMinFloatFloat(HInvoke* invoke) {
+  CreateFPFPToFPPlusTempLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMinFloatFloat(HInvoke* invoke) {
+  GenMinMaxFP(invoke->GetLocations(), true, false, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
+  CreateFPFPToFPPlusTempLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
+  GenMinMaxFP(invoke->GetLocations(), false, true, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) {
+  CreateFPFPToFPPlusTempLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) {
+  GenMinMaxFP(invoke->GetLocations(), false, false, GetAssembler());
+}
+
+static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long,
+                      X86_64Assembler* assembler) {
+  Location op1_loc = locations->InAt(0);
+  Location op2_loc = locations->InAt(1);
+
+  // Shortcut for same input locations.
+  if (op1_loc.Equals(op2_loc)) {
+    // Can return immediately, as op1_loc == out_loc.
+    // Note: if we ever support separate registers, e.g., output into memory, we need to check for
+    //       a copy here.
+    DCHECK(locations->Out().Equals(op1_loc));
+    return;
+  }
+
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+  CpuRegister op2 = op2_loc.AsRegister<CpuRegister>();
+
+  //  (out := op1)
+  //  out <=? op2
+  //  if out is min jmp done
+  //  out := op2
+  // done:
+
+  if (is_long) {
+    __ cmpq(out, op2);
+  } else {
+    __ cmpl(out, op2);
+  }
+
+  __ cmov(is_min ? Condition::kGreater : Condition::kLess, out, op2, is_long);
+}
+
+static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMinIntInt(HInvoke* invoke) {
+  CreateIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMinIntInt(HInvoke* invoke) {
+  GenMinMax(invoke->GetLocations(), true, false, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMinLongLong(HInvoke* invoke) {
+  CreateIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMinLongLong(HInvoke* invoke) {
+  GenMinMax(invoke->GetLocations(), true, true, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMaxIntInt(HInvoke* invoke) {
+  CreateIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMaxIntInt(HInvoke* invoke) {
+  GenMinMax(invoke->GetLocations(), false, false, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathMaxLongLong(HInvoke* invoke) {
+  CreateIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathMaxLongLong(HInvoke* invoke) {
+  GenMinMax(invoke->GetLocations(), false, true, GetAssembler());
+}
+
+static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  locations->SetOut(Location::RequiresFpuRegister());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathSqrt(HInvoke* invoke) {
+  CreateFPToFPLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathSqrt(HInvoke* invoke) {
+  LocationSummary* locations = invoke->GetLocations();
+  XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
+  XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
+
+  GetAssembler()->sqrtsd(out, in);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitStringCharAt(HInvoke* invoke) {
+  // The inputs plus one temp.
+  LocationSummary* locations = new (arena_) LocationSummary(invoke,
+                                                            LocationSummary::kCallOnSlowPath,
+                                                            kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitStringCharAt(HInvoke* invoke) {
+  LocationSummary* locations = invoke->GetLocations();
+
+  // Location of reference to data array
+  const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
+  // Location of count
+  const int32_t count_offset = mirror::String::CountOffset().Int32Value();
+  // Starting offset within data array
+  const int32_t offset_offset = mirror::String::OffsetOffset().Int32Value();
+  // Start of char data with array_
+  const int32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
+
+  CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister idx = locations->InAt(1).AsRegister<CpuRegister>();
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+  Location temp_loc = locations->GetTemp(0);
+  CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
+
+  // Note: Nullcheck has been done before in a HNullCheck before the HInvokeVirtual. If/when we
+  //       move to (coalesced) implicit checks, we have to do a null check below.
+  DCHECK(!kCoalescedImplicitNullCheck);
+
+  // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth
+  //       the cost.
+  // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
+  //       we will not optimize the code for constants (which would save a register).
+
+  SlowPathCodeX86_64* slow_path = new (GetArena()) IntrinsicSlowPathX86_64(invoke);
+  codegen_->AddSlowPath(slow_path);
+
+  X86_64Assembler* assembler = GetAssembler();
+
+  __ cmpl(idx, Address(obj, count_offset));
+  __ j(kAboveEqual, slow_path->GetEntryLabel());
+
+  // Get the actual element.
+  __ movl(temp, idx);                          // temp := idx.
+  __ addl(temp, Address(obj, offset_offset));  // temp := offset + idx.
+  __ movl(out, Address(obj, value_offset));    // obj := obj.array.
+  // out = out[2*temp].
+  __ movzxw(out, Address(out, temp, ScaleFactor::TIMES_2, data_offset));
+
+  __ Bind(slow_path->GetExitLabel());
+}
+
+static void GenPeek(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
+  CpuRegister address = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();  // == address, here for clarity.
+  // x86 allows unaligned access. We do not have to check the input or use specific instructions
+  // to avoid a SIGBUS.
+  switch (size) {
+    case Primitive::kPrimByte:
+      __ movsxb(out, Address(address, 0));
+      break;
+    case Primitive::kPrimShort:
+      __ movsxw(out, Address(address, 0));
+      break;
+    case Primitive::kPrimInt:
+      __ movl(out, Address(address, 0));
+      break;
+    case Primitive::kPrimLong:
+      __ movq(out, Address(address, 0));
+      break;
+    default:
+      LOG(FATAL) << "Type not recognized for peek: " << size;
+      UNREACHABLE();
+  }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekByte(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekByte(HInvoke* invoke) {
+  GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekIntNative(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekIntNative(HInvoke* invoke) {
+  GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekLongNative(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekLongNative(HInvoke* invoke) {
+  GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPeekShortNative(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPeekShortNative(HInvoke* invoke) {
+  GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+}
+
+static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+}
+
+static void GenPoke(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
+  CpuRegister address = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister value = locations->InAt(1).AsRegister<CpuRegister>();
+  // x86 allows unaligned access. We do not have to check the input or use specific instructions
+  // to avoid a SIGBUS.
+  switch (size) {
+    case Primitive::kPrimByte:
+      __ movb(Address(address, 0), value);
+      break;
+    case Primitive::kPrimShort:
+      __ movw(Address(address, 0), value);
+      break;
+    case Primitive::kPrimInt:
+      __ movl(Address(address, 0), value);
+      break;
+    case Primitive::kPrimLong:
+      __ movq(Address(address, 0), value);
+      break;
+    default:
+      LOG(FATAL) << "Type not recognized for poke: " << size;
+      UNREACHABLE();
+  }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeByte(HInvoke* invoke) {
+  CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeByte(HInvoke* invoke) {
+  GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeIntNative(HInvoke* invoke) {
+  CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeIntNative(HInvoke* invoke) {
+  GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeLongNative(HInvoke* invoke) {
+  CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeLongNative(HInvoke* invoke) {
+  GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMemoryPokeShortNative(HInvoke* invoke) {
+  CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMemoryPokeShortNative(HInvoke* invoke) {
+  GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitThreadCurrentThread(HInvoke* invoke) {
+  LocationSummary* locations = new (arena_) LocationSummary(invoke,
+                                                            LocationSummary::kNoCall,
+                                                            kIntrinsified);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitThreadCurrentThread(HInvoke* invoke) {
+  CpuRegister out = invoke->GetLocations()->Out().AsRegister<CpuRegister>();
+  GetAssembler()->gs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86_64WordSize>(), true));
+}
+
+static void GenUnsafeGet(LocationSummary* locations, bool is_long,
+                         bool is_volatile ATTRIBUTE_UNUSED, X86_64Assembler* assembler) {
+  CpuRegister base = locations->InAt(1).AsRegister<CpuRegister>();
+  CpuRegister offset = locations->InAt(2).AsRegister<CpuRegister>();
+  CpuRegister trg = locations->Out().AsRegister<CpuRegister>();
+
+  if (is_long) {
+    __ movq(trg, Address(base, offset, ScaleFactor::TIMES_1, 0));
+  } else {
+    // TODO: Distinguish object. In case we move to an actual compressed heap, retrieving an object
+    //       pointer will entail an unpack operation.
+    __ movl(trg, Address(base, offset, ScaleFactor::TIMES_1, 0));
+  }
+}
+
+static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetInAt(2, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitUnsafeGet(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(arena_, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetVolatile(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(arena_, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetLong(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(arena_, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
+  CreateIntIntIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitUnsafeGet(HInvoke* invoke) {
+  GenUnsafeGet(invoke->GetLocations(), false, false, GetAssembler());
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetVolatile(HInvoke* invoke) {
+  GenUnsafeGet(invoke->GetLocations(), false, true, GetAssembler());
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetLong(HInvoke* invoke) {
+  GenUnsafeGet(invoke->GetLocations(), true, false, GetAssembler());
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
+  GenUnsafeGet(invoke->GetLocations(), true, true, GetAssembler());
+}
+
+static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
+                                                       Primitive::Type type,
+                                                       HInvoke* invoke) {
+  LocationSummary* locations = new (arena) LocationSummary(invoke,
+                                                           LocationSummary::kNoCall,
+                                                           kIntrinsified);
+  locations->SetInAt(0, Location::NoLocation());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetInAt(2, Location::RequiresRegister());
+  locations->SetInAt(3, Location::RequiresRegister());
+  if (type == Primitive::kPrimNot) {
+    // Need temp registers for card-marking.
+    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());
+  }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePut(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutOrdered(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutVolatile(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutObject(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLong(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke);
+}
+void IntrinsicLocationsBuilderX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
+  CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke);
+}
+
+// We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
+// memory model.
+static void GenUnsafePut(LocationSummary* locations, Primitive::Type type, bool is_volatile,
+                         CodeGeneratorX86_64* codegen) {
+  X86_64Assembler* assembler = reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler());
+  CpuRegister base = locations->InAt(1).AsRegister<CpuRegister>();
+  CpuRegister offset = locations->InAt(2).AsRegister<CpuRegister>();
+  CpuRegister value = locations->InAt(3).AsRegister<CpuRegister>();
+
+  if (type == Primitive::kPrimLong) {
+    __ movq(Address(base, offset, ScaleFactor::TIMES_1, 0), value);
+  } else {
+    __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value);
+  }
+
+  if (is_volatile) {
+    __ mfence();
+  }
+
+  if (type == Primitive::kPrimNot) {
+    codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
+                        locations->GetTemp(1).AsRegister<CpuRegister>(),
+                        base,
+                        value);
+  }
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePut(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutOrdered(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutVolatile(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObject(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLong(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_);
+}
+void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
+  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, codegen_);
+}
+
+// Unimplemented intrinsics.
+
+#define UNIMPLEMENTED_INTRINSIC(Name)                                                   \
+void IntrinsicLocationsBuilderX86_64::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
+}                                                                                       \
+void IntrinsicCodeGeneratorX86_64::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
+}
+
+UNIMPLEMENTED_INTRINSIC(IntegerReverse)
+UNIMPLEMENTED_INTRINSIC(LongReverse)
+UNIMPLEMENTED_INTRINSIC(MathFloor)
+UNIMPLEMENTED_INTRINSIC(MathCeil)
+UNIMPLEMENTED_INTRINSIC(MathRint)
+UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
+UNIMPLEMENTED_INTRINSIC(MathRoundFloat)
+UNIMPLEMENTED_INTRINSIC(StringIsEmpty)  // Might not want to do these two anyways, inlining should
+UNIMPLEMENTED_INTRINSIC(StringLength)   // be good enough here.
+UNIMPLEMENTED_INTRINSIC(StringCompareTo)
+UNIMPLEMENTED_INTRINSIC(StringIndexOf)
+UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter)
+UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
+UNIMPLEMENTED_INTRINSIC(UnsafeCASInt)
+UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
+UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
+UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+
+}  // namespace x86_64
+}  // namespace art
diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h
new file mode 100644
index 0000000..c1fa99c
--- /dev/null
+++ b/compiler/optimizing/intrinsics_x86_64.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 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_INTRINSICS_X86_64_H_
+#define ART_COMPILER_OPTIMIZING_INTRINSICS_X86_64_H_
+
+#include "intrinsics.h"
+
+namespace art {
+
+class ArenaAllocator;
+class HInvokeStaticOrDirect;
+class HInvokeVirtual;
+
+namespace x86_64 {
+
+class CodeGeneratorX86_64;
+class X86_64Assembler;
+
+class IntrinsicLocationsBuilderX86_64 FINAL : public IntrinsicVisitor {
+ public:
+  explicit IntrinsicLocationsBuilderX86_64(ArenaAllocator* arena) : arena_(arena) {}
+
+  // Define visitor methods.
+
+#define OPTIMIZING_INTRINSICS(Name, IsStatic)   \
+  void Visit ## Name(HInvoke* invoke) OVERRIDE;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+
+  // Check whether an invoke is an intrinsic, and if so, create a location summary. Returns whether
+  // a corresponding LocationSummary with the intrinsified_ flag set was generated and attached to
+  // the invoke.
+  bool TryDispatch(HInvoke* invoke);
+
+ private:
+  ArenaAllocator* arena_;
+
+  DISALLOW_COPY_AND_ASSIGN(IntrinsicLocationsBuilderX86_64);
+};
+
+class IntrinsicCodeGeneratorX86_64 FINAL : public IntrinsicVisitor {
+ public:
+  explicit IntrinsicCodeGeneratorX86_64(CodeGeneratorX86_64* codegen) : codegen_(codegen) {}
+
+  // Define visitor methods.
+
+#define OPTIMIZING_INTRINSICS(Name, IsStatic)   \
+  void Visit ## Name(HInvoke* invoke) OVERRIDE;
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+
+ private:
+  X86_64Assembler* GetAssembler();
+
+  ArenaAllocator* GetArena();
+
+  CodeGeneratorX86_64* codegen_;
+
+  DISALLOW_COPY_AND_ASSIGN(IntrinsicCodeGeneratorX86_64);
+};
+
+}  // namespace x86_64
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_X86_64_H_
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index 6dd4207..2ab9b57 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -22,6 +22,7 @@
 #include "code_generator_x86.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
+#include "driver/compiler_options.h"
 #include "graph_visualizer.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
@@ -42,18 +43,15 @@
   HGraph* graph = builder.BuildGraph(*item);
   ASSERT_NE(graph, nullptr);
 
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
+  graph->TryBuildingSsa();
 
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
-  ASSERT_EQ(liveness.GetLinearPostOrder().Size(), number_of_blocks);
+  ASSERT_EQ(liveness.GetLinearOrder().Size(), number_of_blocks);
   for (size_t i = 0; i < number_of_blocks; ++i) {
-    ASSERT_EQ(liveness.GetLinearPostOrder().Get(number_of_blocks - i - 1)->GetBlockId(),
-              expected_order[i]);
+    ASSERT_EQ(liveness.GetLinearOrder().Get(i)->GetBlockId(), expected_order[i]);
   }
 }
 
@@ -194,4 +192,58 @@
   TestCode(data, blocks, 12);
 }
 
+TEST(LinearizeTest, CFG6) {
+  //            Block0
+  //              |
+  //            Block1
+  //              |
+  //            Block2 ++++++++++++++
+  //              |                 +
+  //            Block3              +
+  //            /     \             +
+  //       Block8     Block4        +
+  //         |         /   \        +
+  //       Block5 <- Block9 Block6  +
+  //         |
+  //       Block7
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::GOTO | 0x0100,
+    Instruction::IF_EQ, 0x0004,
+    Instruction::IF_EQ, 0x0003,
+    Instruction::RETURN_VOID,
+    Instruction::GOTO | 0xFA00);
+
+  const int blocks[] = {0, 1, 2, 3, 4, 6, 9, 8, 5, 7};
+  TestCode(data, blocks, arraysize(blocks));
+}
+
+TEST(LinearizeTest, CFG7) {
+  // Structure of this graph (+ are back edges)
+  //            Block0
+  //              |
+  //            Block1
+  //              |
+  //            Block2 ++++++++
+  //              |           +
+  //            Block3        +
+  //            /    \        +
+  //        Block4  Block8    +
+  //        /  \        |     +
+  //   Block5 Block9 - Block6 +
+  //     |
+  //   Block7
+  //
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::GOTO | 0x0100,
+    Instruction::IF_EQ, 0x0005,
+    Instruction::IF_EQ, 0x0003,
+    Instruction::RETURN_VOID,
+    Instruction::GOTO | 0xFA00);
+
+  const int blocks[] = {0, 1, 2, 3, 4, 9, 8, 6, 5, 7};
+  TestCode(data, blocks, arraysize(blocks));
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 03f8625..ff23eda 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -19,8 +19,10 @@
 #include "code_generator_x86.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
+#include "prepare_for_register_allocation.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/arena_allocator.h"
 
@@ -35,9 +37,9 @@
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
   RemoveSuspendChecks(graph);
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
+  graph->TryBuildingSsa();
+  // `Inline` conditions into ifs.
+  PrepareForRegisterAllocation(graph).Run();
   return graph;
 }
 
@@ -62,7 +64,7 @@
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildGraph(data, &allocator);
 
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -70,9 +72,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);
 }
@@ -108,7 +110,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildGraph(data, &allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -116,9 +118,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);
 }
@@ -157,7 +159,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildGraph(data, &allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -190,7 +192,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);
 }
 
@@ -234,7 +236,7 @@
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildGraph(data, &allocator);
   RemoveSuspendChecks(graph);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -260,7 +262,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.
@@ -312,7 +314,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildGraph(data, &allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -335,7 +337,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();
@@ -383,12 +385,12 @@
     Instruction::ADD_INT, 1 << 8,
     Instruction::GOTO | 0x300,
     Instruction::ADD_INT, 1 << 8,
-    Instruction::RETURN | 1 << 8);
+    Instruction::RETURN);
 
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildGraph(data, &allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -407,7 +409,10 @@
   interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
   range = interval->GetFirstRange();
   ASSERT_EQ(4u, range->GetStart());
-  ASSERT_EQ(29u, range->GetEnd());
+  ASSERT_EQ(17u, range->GetEnd());
+  range = range->GetNext();
+  ASSERT_EQ(20u, range->GetStart());
+  ASSERT_EQ(23u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 
   // Test for the first add.
@@ -426,9 +431,8 @@
   ASSERT_EQ(26u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 
-  // Test for the phi, which is unused.
   HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi();
-  ASSERT_EQ(phi->NumberOfUses(), 0u);
+  ASSERT_EQ(phi->NumberOfUses(), 1u);
   interval = phi->GetLiveInterval();
   range = interval->GetFirstRange();
   ASSERT_EQ(26u, range->GetStart());
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 2d86169..f2d49ac 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -19,8 +19,10 @@
 #include "code_generator_x86.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
+#include "prepare_for_register_allocation.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/arena_allocator.h"
 
@@ -47,10 +49,10 @@
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
   ASSERT_NE(graph, nullptr);
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
-  x86::CodeGeneratorX86 codegen(graph);
+  graph->TryBuildingSsa();
+  // `Inline` conditions into ifs.
+  PrepareForRegisterAllocation(graph).Run();
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 1c36cdf..990d662 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -20,15 +20,19 @@
 
 namespace art {
 
-LocationSummary::LocationSummary(HInstruction* instruction, CallKind call_kind)
+LocationSummary::LocationSummary(HInstruction* instruction,
+                                 CallKind call_kind,
+                                 bool intrinsified)
     : inputs_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()),
       temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0),
       environment_(instruction->GetBlock()->GetGraph()->GetArena(),
                    instruction->EnvironmentSize()),
+      output_overlaps_(Location::kOutputOverlap),
       call_kind_(call_kind),
       stack_mask_(nullptr),
       register_mask_(0),
-      live_registers_() {
+      live_registers_(),
+      intrinsified_(intrinsified) {
   inputs_.SetSize(instruction->InputCount());
   for (size_t i = 0; i < instruction->InputCount(); ++i) {
     inputs_.Put(i, Location());
@@ -52,4 +56,15 @@
       : Location::RequiresRegister();
 }
 
+Location Location::ByteRegisterOrConstant(int reg, HInstruction* instruction) {
+  return instruction->IsConstant()
+      ? Location::ConstantLocation(instruction->AsConstant())
+      : Location::RegisterLocation(reg);
+}
+
+std::ostream& operator<<(std::ostream& os, const Location& location) {
+  os << location.DebugString();
+  return os;
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index f358e05..dda6c94 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -19,14 +19,17 @@
 
 #include "base/bit_field.h"
 #include "base/bit_vector.h"
-#include "utils/allocation.h"
+#include "base/value_object.h"
+#include "utils/arena_object.h"
 #include "utils/growable_array.h"
-#include "utils/managed_register.h"
 
 namespace art {
 
 class HConstant;
 class HInstruction;
+class Location;
+
+std::ostream& operator<<(std::ostream& os, const Location& location);
 
 /**
  * A Location is an abstraction over the potential location
@@ -34,34 +37,56 @@
  */
 class Location : public ValueObject {
  public:
+  enum OutputOverlap {
+    kOutputOverlap,
+    kNoOutputOverlap
+  };
+
   enum Kind {
     kInvalid = 0,
     kConstant = 1,
-    kStackSlot = 2,  // Word size slot.
+    kStackSlot = 2,  // 32bit stack slot.
     kDoubleStackSlot = 3,  // 64bit stack slot.
-    kRegister = 4,
+
+    kRegister = 4,  // Core register.
+
+    // We do not use the value 5 because it conflicts with kLocationConstantMask.
+    kDoNotUse5 = 5,
+
+    kFpuRegister = 6,  // Float register.
+
+    kRegisterPair = 7,  // Long register.
+
+    kFpuRegisterPair = 8,  // Double register.
+
+    // We do not use the value 9 because it conflicts with kLocationConstantMask.
+    kDoNotUse9 = 9,
+
     // On 32bits architectures, quick can pass a long where the
     // low bits are in the last parameter register, and the high
     // bits are in a stack slot. The kQuickParameter kind is for
     // handling this special case.
-    kQuickParameter = 6,
+    kQuickParameter = 10,
 
     // Unallocated location represents a location that is not fixed and can be
     // allocated by a register allocator.  Each unallocated location has
     // a policy that specifies what kind of location is suitable. Payload
     // contains register allocation policy.
-    kUnallocated = 7,
+    kUnallocated = 11,
   };
 
   Location() : value_(kInvalid) {
-    // Verify that non-tagged location kinds do not interfere with kConstantTag.
-    COMPILE_ASSERT((kInvalid & kLocationTagMask) != kConstant, TagError);
-    COMPILE_ASSERT((kUnallocated & kLocationTagMask) != kConstant, TagError);
-    COMPILE_ASSERT((kStackSlot & kLocationTagMask) != kConstant, TagError);
-    COMPILE_ASSERT((kDoubleStackSlot & kLocationTagMask) != kConstant, TagError);
-    COMPILE_ASSERT((kRegister & kLocationTagMask) != kConstant, TagError);
-    COMPILE_ASSERT((kQuickParameter & kLocationTagMask) != kConstant, TagError);
-    COMPILE_ASSERT((kConstant & kLocationTagMask) == kConstant, TagError);
+    // Verify that non-constant location kinds do not interfere with kConstant.
+    static_assert((kInvalid & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kUnallocated & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kStackSlot & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kDoubleStackSlot & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kRegister & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kQuickParameter & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kFpuRegister & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kRegisterPair & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kFpuRegisterPair & kLocationConstantMask) != kConstant, "TagError");
+    static_assert((kConstant & kLocationConstantMask) == kConstant, "TagError");
 
     DCHECK(!IsValid());
   }
@@ -74,17 +99,17 @@
   }
 
   bool IsConstant() const {
-    return (value_ & kLocationTagMask) == kConstant;
+    return (value_ & kLocationConstantMask) == kConstant;
   }
 
   static Location ConstantLocation(HConstant* constant) {
     DCHECK(constant != nullptr);
-    return Location(kConstant | reinterpret_cast<uword>(constant));
+    return Location(kConstant | reinterpret_cast<uintptr_t>(constant));
   }
 
   HConstant* GetConstant() const {
     DCHECK(IsConstant());
-    return reinterpret_cast<HConstant*>(value_ & ~kLocationTagMask);
+    return reinterpret_cast<HConstant*>(value_ & ~kLocationConstantMask);
   }
 
   bool IsValid() const {
@@ -101,27 +126,113 @@
   }
 
   // Register locations.
-  static Location RegisterLocation(ManagedRegister reg) {
-    return Location(kRegister, reg.RegId());
+  static Location RegisterLocation(int reg) {
+    return Location(kRegister, reg);
+  }
+
+  static Location FpuRegisterLocation(int reg) {
+    return Location(kFpuRegister, reg);
+  }
+
+  static Location RegisterPairLocation(int low, int high) {
+    return Location(kRegisterPair, low << 16 | high);
+  }
+
+  static Location FpuRegisterPairLocation(int low, int high) {
+    return Location(kFpuRegisterPair, low << 16 | high);
   }
 
   bool IsRegister() const {
     return GetKind() == kRegister;
   }
 
-  ManagedRegister reg() const {
-    DCHECK(IsRegister());
-    return static_cast<ManagedRegister>(GetPayload());
+  bool IsFpuRegister() const {
+    return GetKind() == kFpuRegister;
   }
 
-  static uword EncodeStackIndex(intptr_t stack_index) {
+  bool IsRegisterPair() const {
+    return GetKind() == kRegisterPair;
+  }
+
+  bool IsFpuRegisterPair() const {
+    return GetKind() == kFpuRegisterPair;
+  }
+
+  int reg() const {
+    DCHECK(IsRegister() || IsFpuRegister());
+    return GetPayload();
+  }
+
+  int low() const {
+    DCHECK(IsPair());
+    return GetPayload() >> 16;
+  }
+
+  int high() const {
+    DCHECK(IsPair());
+    return GetPayload() & 0xFFFF;
+  }
+
+  template <typename T>
+  T AsRegister() const {
+    DCHECK(IsRegister());
+    return static_cast<T>(reg());
+  }
+
+  template <typename T>
+  T AsFpuRegister() const {
+    DCHECK(IsFpuRegister());
+    return static_cast<T>(reg());
+  }
+
+  template <typename T>
+  T AsRegisterPairLow() const {
+    DCHECK(IsRegisterPair());
+    return static_cast<T>(low());
+  }
+
+  template <typename T>
+  T AsRegisterPairHigh() const {
+    DCHECK(IsRegisterPair());
+    return static_cast<T>(high());
+  }
+
+  template <typename T>
+  T AsFpuRegisterPairLow() const {
+    DCHECK(IsFpuRegisterPair());
+    return static_cast<T>(low());
+  }
+
+  template <typename T>
+  T AsFpuRegisterPairHigh() const {
+    DCHECK(IsFpuRegisterPair());
+    return static_cast<T>(high());
+  }
+
+  bool IsPair() const {
+    return IsRegisterPair() || IsFpuRegisterPair();
+  }
+
+  Location ToLow() const {
+    return IsRegisterPair()
+        ? Location::RegisterLocation(low())
+        : Location::FpuRegisterLocation(low());
+  }
+
+  Location ToHigh() const {
+    return IsRegisterPair()
+        ? Location::RegisterLocation(high())
+        : Location::FpuRegisterLocation(high());
+  }
+
+  static uintptr_t EncodeStackIndex(intptr_t stack_index) {
     DCHECK(-kStackIndexBias <= stack_index);
     DCHECK(stack_index < kStackIndexBias);
-    return static_cast<uword>(kStackIndexBias + stack_index);
+    return static_cast<uintptr_t>(kStackIndexBias + stack_index);
   }
 
   static Location StackSlot(intptr_t stack_index) {
-    uword payload = EncodeStackIndex(stack_index);
+    uintptr_t payload = EncodeStackIndex(stack_index);
     Location loc(kStackSlot, payload);
     // Ensure that sign is preserved.
     DCHECK_EQ(loc.GetStackIndex(), stack_index);
@@ -133,7 +244,7 @@
   }
 
   static Location DoubleStackSlot(intptr_t stack_index) {
-    uword payload = EncodeStackIndex(stack_index);
+    uintptr_t payload = EncodeStackIndex(stack_index);
     Location loc(kDoubleStackSlot, payload);
     // Ensure that sign is preserved.
     DCHECK_EQ(loc.GetStackIndex(), stack_index);
@@ -156,23 +267,24 @@
     return GetPayload() - kStackIndexBias + word_size;
   }
 
-  static Location QuickParameter(uint32_t parameter_index) {
-    return Location(kQuickParameter, parameter_index);
+  static Location QuickParameter(uint16_t register_index, uint16_t stack_index) {
+    return Location(kQuickParameter, register_index << 16 | stack_index);
   }
 
-  uint32_t GetQuickParameterIndex() const {
+  uint32_t GetQuickParameterRegisterIndex() const {
     DCHECK(IsQuickParameter());
-    return GetPayload();
+    return GetPayload() >> 16;
+  }
+
+  uint32_t GetQuickParameterStackIndex() const {
+    DCHECK(IsQuickParameter());
+    return GetPayload() & 0xFFFF;
   }
 
   bool IsQuickParameter() const {
     return GetKind() == kQuickParameter;
   }
 
-  arm::ArmManagedRegister AsArm() const;
-  x86::X86ManagedRegister AsX86() const;
-  x86_64::X86_64ManagedRegister AsX86_64() const;
-
   Kind GetKind() const {
     return IsConstant() ? kConstant : KindField::Decode(value_);
   }
@@ -190,7 +302,14 @@
       case kQuickParameter: return "Q";
       case kUnallocated: return "U";
       case kConstant: return "C";
+      case kFpuRegister: return "F";
+      case kRegisterPair: return "RP";
+      case kFpuRegisterPair: return "FP";
+      case kDoNotUse5:  // fall-through
+      case kDoNotUse9:
+        LOG(FATAL) << "Should not use this location kind";
     }
+    UNREACHABLE();
     return "?";
   }
 
@@ -198,6 +317,7 @@
   enum Policy {
     kAny,
     kRequiresRegister,
+    kRequiresFpuRegister,
     kSameAsFirstInput,
   };
 
@@ -218,7 +338,12 @@
     return UnallocatedLocation(kRequiresRegister);
   }
 
+  static Location RequiresFpuRegister() {
+    return UnallocatedLocation(kRequiresFpuRegister);
+  }
+
   static Location RegisterOrConstant(HInstruction* instruction);
+  static Location ByteRegisterOrConstant(int reg, HInstruction* instruction);
 
   // The location of the first input to the instruction will be
   // used to replace this unallocated location.
@@ -231,27 +356,27 @@
     return PolicyField::Decode(GetPayload());
   }
 
-  uword GetEncoding() const {
+  uintptr_t GetEncoding() const {
     return GetPayload();
   }
 
  private:
   // Number of bits required to encode Kind value.
   static constexpr uint32_t kBitsForKind = 4;
-  static constexpr uint32_t kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind;
-  static constexpr uword kLocationTagMask = 0x3;
+  static constexpr uint32_t kBitsForPayload = kBitsPerIntPtrT - kBitsForKind;
+  static constexpr uintptr_t kLocationConstantMask = 0x3;
 
-  explicit Location(uword value) : value_(value) {}
+  explicit Location(uintptr_t value) : value_(value) {}
 
-  Location(Kind kind, uword payload)
+  Location(Kind kind, uintptr_t payload)
       : value_(KindField::Encode(kind) | PayloadField::Encode(payload)) {}
 
-  uword GetPayload() const {
+  uintptr_t GetPayload() const {
     return PayloadField::Decode(value_);
   }
 
   typedef BitField<Kind, 0, kBitsForKind> KindField;
-  typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
+  typedef BitField<uintptr_t, kBitsForKind, kBitsForPayload> PayloadField;
 
   // Layout for kUnallocated locations payload.
   typedef BitField<Policy, 0, 3> PolicyField;
@@ -263,16 +388,31 @@
   // Location either contains kind and payload fields or a tagged handle for
   // a constant locations. Values of enumeration Kind are selected in such a
   // way that none of them can be interpreted as a kConstant tag.
-  uword value_;
+  uintptr_t value_;
 };
+std::ostream& operator<<(std::ostream& os, const Location::Kind& rhs);
+std::ostream& operator<<(std::ostream& os, const Location::Policy& rhs);
 
 class RegisterSet : public ValueObject {
  public:
   RegisterSet() : core_registers_(0), floating_point_registers_(0) {}
 
   void Add(Location loc) {
-    // TODO: floating point registers.
-    core_registers_ |= (1 << loc.reg().RegId());
+    if (loc.IsRegister()) {
+      core_registers_ |= (1 << loc.reg());
+    } else {
+      DCHECK(loc.IsFpuRegister());
+      floating_point_registers_ |= (1 << loc.reg());
+    }
+  }
+
+  void Remove(Location loc) {
+    if (loc.IsRegister()) {
+      core_registers_ &= ~(1 << loc.reg());
+    } else {
+      DCHECK(loc.IsFpuRegister()) << loc;
+      floating_point_registers_ &= ~(1 << loc.reg());
+    }
   }
 
   bool ContainsCoreRegister(uint32_t id) {
@@ -287,6 +427,10 @@
     return (register_set & (1 << reg)) != 0;
   }
 
+  size_t GetNumberOfRegisters() const {
+    return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_);
+  }
+
  private:
   uint32_t core_registers_;
   uint32_t floating_point_registers_;
@@ -302,7 +446,7 @@
  * The intent is to have the code for generating the instruction independent of
  * register allocation. A register allocator just has to provide a LocationSummary.
  */
-class LocationSummary : public ArenaObject {
+class LocationSummary : public ArenaObject<kArenaAllocMisc> {
  public:
   enum CallKind {
     kNoCall,
@@ -310,9 +454,12 @@
     kCall
   };
 
-  LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
+  LocationSummary(HInstruction* instruction,
+                  CallKind call_kind = kNoCall,
+                  bool intrinsified = false);
 
   void SetInAt(uint32_t at, Location location) {
+    DCHECK(inputs_.Get(at).IsUnallocated() || inputs_.Get(at).IsInvalid());
     inputs_.Put(at, location);
   }
 
@@ -324,8 +471,18 @@
     return inputs_.Size();
   }
 
-  void SetOut(Location location) {
-    output_ = Location(location);
+  void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
+    DCHECK(output_.IsUnallocated() || output_.IsInvalid());
+    output_overlaps_ = overlaps;
+    output_ = location;
+  }
+
+  void UpdateOut(Location location) {
+    // The only reason for updating an output is for parameters where
+    // we only know the exact stack slot after doing full register
+    // allocation.
+    DCHECK(output_.IsStackSlot() || output_.IsDoubleStackSlot());
+    output_ = location;
   }
 
   void AddTemp(Location location) {
@@ -337,6 +494,7 @@
   }
 
   void SetTempAt(uint32_t at, Location location) {
+    DCHECK(temps_.Get(at).IsUnallocated() || temps_.Get(at).IsInvalid());
     temps_.Put(at, location);
   }
 
@@ -387,20 +545,39 @@
     return &live_registers_;
   }
 
-  bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
+  size_t GetNumberOfLiveRegisters() const {
+    return live_registers_.GetNumberOfRegisters();
+  }
+
+  bool InputOverlapsWithOutputOrTemp(uint32_t input_index, bool is_environment) const {
     if (is_environment) return true;
-    Location location = Out();
-    // TODO: Add more policies.
-    if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
+    if ((input_index == 0)
+        && output_.IsUnallocated()
+        && (output_.GetPolicy() == Location::kSameAsFirstInput)) {
+      return false;
+    }
+    Location input = inputs_.Get(input_index);
+    if (input.IsRegister() || input.IsFpuRegister() || input.IsPair()) {
       return false;
     }
     return true;
   }
 
+  bool OutputOverlapsWithInputs() const {
+    return output_overlaps_ == Location::kOutputOverlap;
+  }
+
+  bool Intrinsified() const {
+    return intrinsified_;
+  }
+
  private:
   GrowableArray<Location> inputs_;
   GrowableArray<Location> temps_;
   GrowableArray<Location> environment_;
+  // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
+  // share the same register as the inputs.
+  Location::OutputOverlap output_overlaps_;
   Location output_;
   const CallKind call_kind_;
 
@@ -413,6 +590,11 @@
   // Registers that are in use at this position.
   RegisterSet live_registers_;
 
+  // Whether these are locations for an intrinsified call.
+  const bool intrinsified_;
+
+  ART_FRIEND_TEST(RegisterAllocatorTest, ExpectedInRegisterHint);
+  ART_FRIEND_TEST(RegisterAllocatorTest, SameAsFirstInputHint);
   DISALLOW_COPY_AND_ASSIGN(LocationSummary);
 };
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 5c4ab8e..ec53366 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -15,6 +15,7 @@
  */
 
 #include "nodes.h"
+
 #include "ssa_builder.h"
 #include "utils/growable_array.h"
 
@@ -30,23 +31,56 @@
   VisitBlockForBackEdges(entry_block_, visited, &visiting);
 }
 
-void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
+static void RemoveAsUser(HInstruction* instruction) {
+  for (size_t i = 0; i < instruction->InputCount(); i++) {
+    instruction->InputAt(i)->RemoveUser(instruction, i);
+  }
+
+  HEnvironment* environment = instruction->GetEnvironment();
+  if (environment != nullptr) {
+    for (size_t i = 0, e = environment->Size(); i < e; ++i) {
+      HInstruction* vreg = environment->GetInstructionAt(i);
+      if (vreg != nullptr) {
+        vreg->RemoveEnvironmentUser(environment, i);
+      }
+    }
+  }
+}
+
+void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
   for (size_t i = 0; i < blocks_.Size(); ++i) {
     if (!visited.IsBitSet(i)) {
       HBasicBlock* block = blocks_.Get(i);
-      for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
-        block->GetSuccessors().Get(j)->RemovePredecessor(block);
-      }
       for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-        block->RemovePhi(it.Current()->AsPhi());
+        RemoveAsUser(it.Current());
       }
       for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-        block->RemoveInstruction(it.Current());
+        RemoveAsUser(it.Current());
       }
     }
   }
 }
 
+void HGraph::RemoveBlock(HBasicBlock* block) const {
+  for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
+    block->GetSuccessors().Get(j)->RemovePredecessor(block);
+  }
+  for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+    block->RemovePhi(it.Current()->AsPhi());
+  }
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+    block->RemoveInstruction(it.Current());
+  }
+}
+
+void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
+  for (size_t i = 0; i < blocks_.Size(); ++i) {
+    if (!visited.IsBitSet(i)) {
+      RemoveBlock(blocks_.Get(i));
+    }
+  }
+}
+
 void HGraph::VisitBlockForBackEdges(HBasicBlock* block,
                                     ArenaBitVector* visited,
                                     ArenaBitVector* visiting) {
@@ -72,16 +106,21 @@
   // (1) Find the back edges in the graph doing a DFS traversal.
   FindBackEdges(&visited);
 
-  // (2) Remove blocks not visited during the initial DFS.
-  //     Step (3) requires dead blocks to be removed from the
+  // (2) Remove instructions and phis from blocks not visited during
+  //     the initial DFS as users from other instructions, so that
+  //     users can be safely removed before uses later.
+  RemoveInstructionsAsUsersFromDeadBlocks(visited);
+
+  // (3) Remove blocks not visited during the initial DFS.
+  //     Step (4) requires dead blocks to be removed from the
   //     predecessors list of live blocks.
   RemoveDeadBlocks(visited);
 
-  // (3) Simplify the CFG now, so that we don't need to recompute
+  // (4) Simplify the CFG now, so that we don't need to recompute
   //     dominators and the reverse post order.
   SimplifyCFG();
 
-  // (4) Compute the immediate dominator of each block. We visit
+  // (5) Compute the immediate dominator of each block. We visit
   //     the successors of a block only when all its forward branches
   //     have been processed.
   GrowableArray<size_t> visits(arena_, blocks_.Size());
@@ -132,7 +171,7 @@
   }
 }
 
-void HGraph::TransformToSSA() {
+void HGraph::TransformToSsa() {
   DCHECK(!reverse_post_order_.IsEmpty());
   SsaBuilder ssa_builder(this);
   ssa_builder.BuildSsa();
@@ -237,7 +276,7 @@
   }
 }
 
-bool HGraph::FindNaturalLoops() const {
+bool HGraph::AnalyzeNaturalLoops() const {
   for (size_t i = 0; i < blocks_.Size(); ++i) {
     HBasicBlock* block = blocks_.Get(i);
     if (block->IsLoopHeader()) {
@@ -308,9 +347,17 @@
   return false;
 }
 
+static void UpdateInputsUsers(HInstruction* instruction) {
+  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
+    instruction->InputAt(i)->AddUseAt(instruction, i);
+  }
+  // Environment should be created later.
+  DCHECK(!instruction->HasEnvironment());
+}
+
 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);
@@ -325,6 +372,7 @@
   }
   instruction->SetBlock(this);
   instruction->SetId(GetGraph()->GetNextInstructionId());
+  UpdateInputsUsers(instruction);
 }
 
 void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
@@ -342,6 +390,7 @@
   DCHECK_EQ(instruction->GetId(), -1);
   instruction->SetBlock(block);
   instruction->SetId(block->GetGraph()->GetNextInstructionId());
+  UpdateInputsUsers(instruction);
   instruction_list->AddInstruction(instruction);
 }
 
@@ -353,6 +402,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) {
@@ -362,19 +430,7 @@
   instruction->SetBlock(nullptr);
   instruction_list->RemoveInstruction(instruction);
 
-  for (size_t i = 0; i < instruction->InputCount(); i++) {
-    instruction->InputAt(i)->RemoveUser(instruction, i);
-  }
-
-  HEnvironment* environment = instruction->GetEnvironment();
-  if (environment != nullptr) {
-    for (size_t i = 0, e = environment->Size(); i < e; ++i) {
-      HInstruction* vreg = environment->GetInstructionAt(i);
-      if (vreg != nullptr) {
-        vreg->RemoveEnvironmentUser(environment, i);
-      }
-    }
-  }
+  RemoveAsUser(instruction);
 }
 
 void HBasicBlock::RemoveInstruction(HInstruction* instruction) {
@@ -393,7 +449,7 @@
   HUseListNode<T>* current = *list;
   while (current != nullptr) {
     if (current->GetUser() == user && current->GetIndex() == input_index) {
-      if (previous == NULL) {
+      if (previous == nullptr) {
         *list = current->GetTail();
       } else {
         previous->SetTail(current->GetTail());
@@ -404,6 +460,22 @@
   }
 }
 
+HInstruction* HInstruction::GetNextDisregardingMoves() const {
+  HInstruction* next = GetNext();
+  while (next != nullptr && next->IsParallelMove()) {
+    next = next->GetNext();
+  }
+  return next;
+}
+
+HInstruction* HInstruction::GetPreviousDisregardingMoves() const {
+  HInstruction* previous = GetPrevious();
+  while (previous != nullptr && previous->IsParallelMove()) {
+    previous = previous->GetPrevious();
+  }
+  return previous;
+}
+
 void HInstruction::RemoveUser(HInstruction* user, size_t input_index) {
   RemoveFromUseList(user, input_index, &uses_);
 }
@@ -421,9 +493,6 @@
     instruction->previous_ = last_instruction_;
     last_instruction_ = instruction;
   }
-  for (size_t i = 0; i < instruction->InputCount(); i++) {
-    instruction->InputAt(i)->AddUseAt(instruction, i);
-  }
 }
 
 void HInstructionList::RemoveInstruction(HInstruction* instruction) {
@@ -465,7 +534,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) {
@@ -520,6 +593,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;
 }
@@ -530,7 +609,7 @@
   input->AddUseAt(this, inputs_.Size() - 1);
 }
 
-#define DEFINE_ACCEPT(name)                                                    \
+#define DEFINE_ACCEPT(name, super)                                             \
 void H##name::Accept(HGraphVisitor* visitor) {                                 \
   visitor->Visit##name(this);                                                  \
 }
@@ -546,6 +625,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);
@@ -555,43 +640,41 @@
   }
 }
 
-HConstant* HBinaryOperation::TryStaticEvaluation(ArenaAllocator* allocator) const {
-  if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
-    int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
-                             GetRight()->AsIntConstant()->GetValue());
-    return new(allocator) HIntConstant(value);
-  } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
-    int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
-                             GetRight()->AsLongConstant()->GetValue());
-    return new(allocator) HLongConstant(value);
+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;
 }
 
-bool HCondition::NeedsMaterialization() const {
-  if (!HasOnlyOneUse()) {
-    return true;
+HConstant* HBinaryOperation::TryStaticEvaluation() const {
+  if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
+    int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
+                             GetRight()->AsIntConstant()->GetValue());
+    return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+  } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
+    int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
+                             GetRight()->AsLongConstant()->GetValue());
+    if (GetResultType() == Primitive::kPrimLong) {
+      return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
+    } else {
+      DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
+      return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+    }
   }
-  HUseListNode<HInstruction>* uses = GetUses();
-  HInstruction* user = uses->GetUser();
-  if (!user->IsIf()) {
-    return true;
-  }
-
-  // TODO: if there is no intervening instructions with side-effect between this condition
-  // and the If instruction, we should move the condition just before the If.
-  if (GetNext() != user) {
-    return true;
-  }
-  return false;
+  return nullptr;
 }
 
 bool HCondition::IsBeforeWhenDisregardMoves(HIf* if_) const {
-  HInstruction* previous = if_->GetPrevious();
-  while (previous != nullptr && previous->IsParallelMove()) {
-    previous = previous->GetPrevious();
-  }
-  return previous == this;
+  return this == if_->GetPreviousDisregardingMoves();
 }
 
 bool HInstruction::Equals(HInstruction* other) const {
@@ -608,4 +691,96 @@
   return true;
 }
 
+std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
+#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
+  switch (rhs) {
+    FOR_EACH_INSTRUCTION(DECLARE_CASE)
+    default:
+      os << "Unknown instruction kind " << static_cast<int>(rhs);
+      break;
+  }
+#undef DECLARE_CASE
+  return os;
+}
+
+void HInstruction::InsertBefore(HInstruction* cursor) {
+  next_->previous_ = previous_;
+  if (previous_ != nullptr) {
+    previous_->next_ = next_;
+  }
+  if (block_->instructions_.first_instruction_ == this) {
+    block_->instructions_.first_instruction_ = next_;
+  }
+
+  previous_ = cursor->previous_;
+  if (previous_ != nullptr) {
+    previous_->next_ = this;
+  }
+  next_ = cursor;
+  cursor->previous_ = this;
+  block_ = cursor->block_;
+}
+
+void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
+  // We currently only support graphs with one entry block, one body block, and one exit block.
+  DCHECK_EQ(GetBlocks().Size(), 3u);
+
+  // Walk over the entry block and:
+  // - Move constants from the entry block to the outer_graph's entry block,
+  // - Replace HParameterValue instructions with their real value.
+  // - Remove suspend checks, that hold an environment.
+  int parameter_index = 0;
+  for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
+    HInstruction* current = it.Current();
+    if (current->IsConstant()) {
+      current->InsertBefore(outer_graph->GetEntryBlock()->GetLastInstruction());
+    } else if (current->IsParameterValue()) {
+      current->ReplaceWith(invoke->InputAt(parameter_index++));
+    } else {
+      DCHECK(current->IsGoto() || current->IsSuspendCheck());
+      entry_block_->RemoveInstruction(current);
+    }
+  }
+
+  // Insert the body's instructions except the last, just after the `invoke`
+  // instruction.
+  HBasicBlock* body = GetBlocks().Get(1);
+  DCHECK(!body->IsExitBlock());
+  HInstruction* last = body->GetLastInstruction();
+  HInstruction* first = body->GetFirstInstruction();
+
+  if (first != last) {
+    HInstruction* antelast = last->GetPrevious();
+
+    // Update the instruction list of the body to only contain the last
+    // instruction.
+    last->previous_ = nullptr;
+    body->instructions_.first_instruction_ = last;
+    body->instructions_.last_instruction_ = last;
+
+    // Update the instruction list of the `invoke`'s block to now contain the
+    // body's instructions.
+    antelast->next_ = invoke->GetNext();
+    antelast->next_->previous_ = antelast;
+    first->previous_ = invoke;
+    invoke->next_ = first;
+
+    // Update the block pointer of all instructions.
+    for (HInstruction* current = antelast; current != invoke; current = current->GetPrevious()) {
+      current->SetBlock(invoke->GetBlock());
+    }
+  }
+
+  // Replace the invoke with the return value of the inlined graph.
+  if (last->IsReturn()) {
+    invoke->ReplaceWith(last->InputAt(0));
+    body->RemoveInstruction(last);
+  } else {
+    DCHECK(last->IsReturnVoid());
+  }
+
+  // Finally remove the invoke from the caller.
+  invoke->GetBlock()->RemoveInstruction(invoke);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3d65366..e19bfce 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -17,10 +17,11 @@
 #ifndef ART_COMPILER_OPTIMIZING_NODES_H_
 #define ART_COMPILER_OPTIMIZING_NODES_H_
 
+#include "invoke_type.h"
 #include "locations.h"
 #include "offsets.h"
 #include "primitive.h"
-#include "utils/allocation.h"
+#include "utils/arena_object.h"
 #include "utils/arena_bit_vector.h"
 #include "utils/growable_array.h"
 
@@ -30,6 +31,7 @@
 class HEnvironment;
 class HInstruction;
 class HIntConstant;
+class HInvoke;
 class HGraphVisitor;
 class HPhi;
 class HSuspendCheck;
@@ -42,6 +44,9 @@
 static const int kDefaultNumberOfDominatedBlocks = 1;
 static const int kDefaultNumberOfBackEdges = 1;
 
+static constexpr uint32_t kMaxIntShiftValue = 0x1f;
+static constexpr uint64_t kMaxLongShiftValue = 0x3f;
+
 enum IfCondition {
   kCondEQ,
   kCondNE,
@@ -72,6 +77,8 @@
   HInstruction* last_instruction_;
 
   friend class HBasicBlock;
+  friend class HGraph;
+  friend class HInstruction;
   friend class HInstructionIterator;
   friend class HBackwardInstructionIterator;
 
@@ -79,20 +86,23 @@
 };
 
 // Control-flow graph of a method. Contains a list of basic blocks.
-class HGraph : public ArenaObject {
+class HGraph : public ArenaObject<kArenaAllocMisc> {
  public:
-  explicit HGraph(ArenaAllocator* arena)
+  HGraph(ArenaAllocator* arena, int start_instruction_id = 0)
       : arena_(arena),
         blocks_(arena, kDefaultNumberOfBlocks),
         reverse_post_order_(arena, kDefaultNumberOfBlocks),
+        entry_block_(nullptr),
+        exit_block_(nullptr),
         maximum_number_of_out_vregs_(0),
         number_of_vregs_(0),
         number_of_in_vregs_(0),
-        number_of_temporaries_(0),
-        current_instruction_id_(0) {}
+        temporaries_vreg_slots_(0),
+        current_instruction_id_(start_instruction_id) {}
 
   ArenaAllocator* GetArena() const { return arena_; }
   const GrowableArray<HBasicBlock*>& GetBlocks() const { return blocks_; }
+  HBasicBlock* GetBlock(size_t id) const { return blocks_.Get(id); }
 
   HBasicBlock* GetEntryBlock() const { return entry_block_; }
   HBasicBlock* GetExitBlock() const { return exit_block_; }
@@ -102,36 +112,56 @@
 
   void AddBlock(HBasicBlock* block);
 
+  // Try building the SSA form of this graph, with dominance computation and loop
+  // recognition. Returns whether it was successful in doing all these steps.
+  bool TryBuildingSsa() {
+    BuildDominatorTree();
+    TransformToSsa();
+    return AnalyzeNaturalLoops();
+  }
+
   void BuildDominatorTree();
-  void TransformToSSA();
+  void TransformToSsa();
   void SimplifyCFG();
 
-  // Find all natural loops in this graph. Aborts computation and returns false
-  // if one loop is not natural, that is the header does not dominate the back
-  // edge.
-  bool FindNaturalLoops() const;
+  // Analyze all natural loops in this graph. Returns false if one
+  // loop is not natural, that is the header does not dominate the
+  // back edge.
+  bool AnalyzeNaturalLoops() const;
+
+  // Inline this graph in `outer_graph`, replacing the given `invoke` instruction.
+  void InlineInto(HGraph* outer_graph, HInvoke* invoke);
 
   void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
   void SimplifyLoop(HBasicBlock* header);
 
-  int GetNextInstructionId() {
+  int32_t GetNextInstructionId() {
+    DCHECK_NE(current_instruction_id_, INT32_MAX);
     return current_instruction_id_++;
   }
 
+  int32_t GetCurrentInstructionId() const {
+    return current_instruction_id_;
+  }
+
+  void SetCurrentInstructionId(int32_t id) {
+    current_instruction_id_ = id;
+  }
+
   uint16_t GetMaximumNumberOfOutVRegs() const {
     return maximum_number_of_out_vregs_;
   }
 
-  void UpdateMaximumNumberOfOutVRegs(uint16_t new_value) {
-    maximum_number_of_out_vregs_ = std::max(new_value, maximum_number_of_out_vregs_);
+  void SetMaximumNumberOfOutVRegs(uint16_t new_value) {
+    maximum_number_of_out_vregs_ = new_value;
   }
 
-  void UpdateNumberOfTemporaries(size_t count) {
-    number_of_temporaries_ = std::max(count, number_of_temporaries_);
+  void UpdateTemporariesVRegSlots(size_t slots) {
+    temporaries_vreg_slots_ = std::max(slots, temporaries_vreg_slots_);
   }
 
-  size_t GetNumberOfTemporaries() const {
-    return number_of_temporaries_;
+  size_t GetTemporariesVRegSlots() const {
+    return temporaries_vreg_slots_;
   }
 
   void SetNumberOfVRegs(uint16_t number_of_vregs) {
@@ -146,10 +176,6 @@
     number_of_in_vregs_ = value;
   }
 
-  uint16_t GetNumberOfInVRegs() const {
-    return number_of_in_vregs_;
-  }
-
   uint16_t GetNumberOfLocalVRegs() const {
     return number_of_vregs_ - number_of_in_vregs_;
   }
@@ -167,7 +193,9 @@
   void VisitBlockForBackEdges(HBasicBlock* block,
                               ArenaBitVector* visited,
                               ArenaBitVector* visiting);
+  void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
   void RemoveDeadBlocks(const ArenaBitVector& visited) const;
+  void RemoveBlock(HBasicBlock* block) const;
 
   ArenaAllocator* const arena_;
 
@@ -189,16 +217,17 @@
   // The number of virtual registers used by parameters of this method.
   uint16_t number_of_in_vregs_;
 
-  // The number of temporaries that will be needed for the baseline compiler.
-  size_t number_of_temporaries_;
+  // Number of vreg size slots that the temporaries use (used in baseline compiler).
+  size_t temporaries_vreg_slots_;
 
   // The current id to assign to a newly added instruction. See HInstruction.id_.
-  int current_instruction_id_;
+  int32_t current_instruction_id_;
 
+  ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
   DISALLOW_COPY_AND_ASSIGN(HGraph);
 };
 
-class HLoopInformation : public ArenaObject {
+class HLoopInformation : public ArenaObject<kArenaAllocMisc> {
  public:
   HLoopInformation(HBasicBlock* header, HGraph* graph)
       : header_(header),
@@ -230,7 +259,7 @@
     return false;
   }
 
-  int NumberOfBackEdges() const {
+  size_t NumberOfBackEdges() const {
     return back_edges_.Size();
   }
 
@@ -277,7 +306,7 @@
 // as a double linked list. Each block knows its predecessors and
 // successors.
 
-class HBasicBlock : public ArenaObject {
+class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
  public:
   explicit HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
       : graph_(graph),
@@ -289,7 +318,8 @@
         block_id_(-1),
         dex_pc_(dex_pc),
         lifetime_start_(kNoLifetime),
-        lifetime_end_(kNoLifetime) {}
+        lifetime_end_(kNoLifetime),
+        is_catch_block_(false) {}
 
   const GrowableArray<HBasicBlock*>& GetPredecessors() const {
     return predecessors_;
@@ -398,6 +428,7 @@
   void ReplaceAndRemoveInstructionWith(HInstruction* initial,
                                        HInstruction* replacement);
   void AddPhi(HPhi* phi);
+  void InsertPhiAfter(HPhi* instruction, HPhi* cursor);
   void RemovePhi(HPhi* phi);
 
   bool IsLoopHeader() const {
@@ -446,6 +477,9 @@
 
   uint32_t GetDexPc() const { return dex_pc_; }
 
+  bool IsCatchBlock() const { return is_catch_block_; }
+  void SetIsCatchBlock() { is_catch_block_ = true; }
+
  private:
   HGraph* const graph_;
   GrowableArray<HBasicBlock*> predecessors_;
@@ -460,54 +494,86 @@
   const uint32_t dex_pc_;
   size_t lifetime_start_;
   size_t lifetime_end_;
+  bool is_catch_block_;
+
+  friend class HGraph;
+  friend class HInstruction;
 
   DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
 };
 
-#define FOR_EACH_CONCRETE_INSTRUCTION(M)                   \
-  M(Add)                                                   \
-  M(Condition)                                             \
-  M(Equal)                                                 \
-  M(NotEqual)                                              \
-  M(LessThan)                                              \
-  M(LessThanOrEqual)                                       \
-  M(GreaterThan)                                           \
-  M(GreaterThanOrEqual)                                    \
-  M(Exit)                                                  \
-  M(Goto)                                                  \
-  M(If)                                                    \
-  M(IntConstant)                                           \
-  M(InvokeStatic)                                          \
-  M(InvokeVirtual)                                         \
-  M(LoadLocal)                                             \
-  M(Local)                                                 \
-  M(LongConstant)                                          \
-  M(NewInstance)                                           \
-  M(Not)                                                   \
-  M(ParameterValue)                                        \
-  M(ParallelMove)                                          \
-  M(Phi)                                                   \
-  M(Return)                                                \
-  M(ReturnVoid)                                            \
-  M(StoreLocal)                                            \
-  M(Sub)                                                   \
-  M(Compare)                                               \
-  M(InstanceFieldGet)                                      \
-  M(InstanceFieldSet)                                      \
-  M(ArrayGet)                                              \
-  M(ArraySet)                                              \
-  M(ArrayLength)                                           \
-  M(BoundsCheck)                                           \
-  M(NullCheck)                                             \
-  M(Temporary)                                             \
-  M(SuspendCheck)                                          \
+#define FOR_EACH_CONCRETE_INSTRUCTION(M)                                \
+  M(Add, BinaryOperation)                                               \
+  M(And, BinaryOperation)                                               \
+  M(ArrayGet, Instruction)                                              \
+  M(ArrayLength, Instruction)                                           \
+  M(ArraySet, Instruction)                                              \
+  M(BoundsCheck, Instruction)                                           \
+  M(CheckCast, Instruction)                                             \
+  M(ClinitCheck, Instruction)                                           \
+  M(Compare, BinaryOperation)                                           \
+  M(Condition, BinaryOperation)                                         \
+  M(Div, BinaryOperation)                                               \
+  M(DivZeroCheck, Instruction)                                          \
+  M(DoubleConstant, Constant)                                           \
+  M(Equal, Condition)                                                   \
+  M(Exit, Instruction)                                                  \
+  M(FloatConstant, Constant)                                            \
+  M(Goto, Instruction)                                                  \
+  M(GreaterThan, Condition)                                             \
+  M(GreaterThanOrEqual, Condition)                                      \
+  M(If, Instruction)                                                    \
+  M(InstanceFieldGet, Instruction)                                      \
+  M(InstanceFieldSet, Instruction)                                      \
+  M(InstanceOf, Instruction)                                            \
+  M(IntConstant, Constant)                                              \
+  M(InvokeInterface, Invoke)                                            \
+  M(InvokeStaticOrDirect, Invoke)                                       \
+  M(InvokeVirtual, Invoke)                                              \
+  M(LessThan, Condition)                                                \
+  M(LessThanOrEqual, Condition)                                         \
+  M(LoadClass, Instruction)                                             \
+  M(LoadException, Instruction)                                         \
+  M(LoadLocal, Instruction)                                             \
+  M(LoadString, Instruction)                                            \
+  M(Local, Instruction)                                                 \
+  M(LongConstant, Constant)                                             \
+  M(MonitorOperation, Instruction)                                      \
+  M(Mul, BinaryOperation)                                               \
+  M(Neg, UnaryOperation)                                                \
+  M(NewArray, Instruction)                                              \
+  M(NewInstance, Instruction)                                           \
+  M(Not, UnaryOperation)                                                \
+  M(NotEqual, Condition)                                                \
+  M(NullCheck, Instruction)                                             \
+  M(Or, BinaryOperation)                                                \
+  M(ParallelMove, Instruction)                                          \
+  M(ParameterValue, Instruction)                                        \
+  M(Phi, Instruction)                                                   \
+  M(Rem, BinaryOperation)                                               \
+  M(Return, Instruction)                                                \
+  M(ReturnVoid, Instruction)                                            \
+  M(Shl, BinaryOperation)                                               \
+  M(Shr, BinaryOperation)                                               \
+  M(StaticFieldGet, Instruction)                                        \
+  M(StaticFieldSet, Instruction)                                        \
+  M(StoreLocal, Instruction)                                            \
+  M(Sub, BinaryOperation)                                               \
+  M(SuspendCheck, Instruction)                                          \
+  M(Temporary, Instruction)                                             \
+  M(Throw, Instruction)                                                 \
+  M(TypeConversion, Instruction)                                        \
+  M(UShr, BinaryOperation)                                              \
+  M(Xor, BinaryOperation)                                               \
 
-#define FOR_EACH_INSTRUCTION(M)                            \
-  FOR_EACH_CONCRETE_INSTRUCTION(M)                         \
-  M(Constant)                                              \
-  M(BinaryOperation)
+#define FOR_EACH_INSTRUCTION(M)                                         \
+  FOR_EACH_CONCRETE_INSTRUCTION(M)                                      \
+  M(Constant, Instruction)                                              \
+  M(UnaryOperation, Instruction)                                        \
+  M(BinaryOperation, Instruction)                                       \
+  M(Invoke, Instruction)
 
-#define FORWARD_DECLARATION(type) class H##type;
+#define FORWARD_DECLARATION(type, super) class H##type;
 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
 #undef FORWARD_DECLARATION
 
@@ -522,7 +588,7 @@
   virtual void Accept(HGraphVisitor* visitor)
 
 template <typename T>
-class HUseListNode : public ArenaObject {
+class HUseListNode : public ArenaObject<kArenaAllocMisc> {
  public:
   HUseListNode(T* user, size_t index, HUseListNode* tail)
       : user_(user), index_(index), tail_(tail) {}
@@ -604,7 +670,7 @@
   size_t flags_;
 };
 
-class HInstruction : public ArenaObject {
+class HInstruction : public ArenaObject<kArenaAllocMisc> {
  public:
   explicit HInstruction(SideEffects side_effects)
       : previous_(nullptr),
@@ -622,7 +688,7 @@
 
   virtual ~HInstruction() {}
 
-#define DECLARE_KIND(type) k##type,
+#define DECLARE_KIND(type, super) k##type,
   enum InstructionKind {
     FOR_EACH_INSTRUCTION(DECLARE_KIND)
   };
@@ -631,6 +697,9 @@
   HInstruction* GetNext() const { return next_; }
   HInstruction* GetPrevious() const { return previous_; }
 
+  HInstruction* GetNextDisregardingMoves() const;
+  HInstruction* GetPreviousDisregardingMoves() const;
+
   HBasicBlock* GetBlock() const { return block_; }
   void SetBlock(HBasicBlock* block) { block_ = block; }
   bool IsInBlock() const { return block_ != nullptr; }
@@ -648,8 +717,11 @@
 
   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(); }
 
+  virtual bool CanDoImplicitNullCheck() const { return false; }
+
   void AddUseAt(HInstruction* user, size_t index) {
     uses_ = new (block_->GetGraph()->GetArena()) HUseListNode<HInstruction>(user, index, uses_);
   }
@@ -680,9 +752,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; }
@@ -703,12 +776,16 @@
   void SetLocations(LocationSummary* locations) { locations_ = locations; }
 
   void ReplaceWith(HInstruction* instruction);
+  void ReplaceInput(HInstruction* replacement, size_t index);
+
+  // Insert `this` instruction in `cursor`'s graph, just before `cursor`.
+  void InsertBefore(HInstruction* cursor);
 
   bool HasOnlyOneUse() const {
     return uses_ != nullptr && uses_->GetTail() == nullptr;
   }
 
-#define INSTRUCTION_TYPE_CHECK(type)                                           \
+#define INSTRUCTION_TYPE_CHECK(type, super)                                    \
   bool Is##type() const { return (As##type() != nullptr); }                    \
   virtual const H##type* As##type() const { return nullptr; }                  \
   virtual H##type* As##type() { return nullptr; }
@@ -720,15 +797,21 @@
   virtual bool CanBeMoved() const { return false; }
 
   // Returns whether the two instructions are of the same kind.
-  virtual bool InstructionTypeEquals(HInstruction* other) const { return false; }
+  virtual bool InstructionTypeEquals(HInstruction* other) const {
+    UNUSED(other);
+    return false;
+  }
 
   // Returns whether any data encoded in the two instructions is equal.
   // This method does not look at the inputs. Both instructions must be
   // of the same type, otherwise the method has undefined behavior.
-  virtual bool InstructionDataEquals(HInstruction* other) const { return false; }
+  virtual bool InstructionDataEquals(HInstruction* other) const {
+    UNUSED(other);
+    return false;
+  }
 
   // Returns whether two instructions are equal, that is:
-  // 1) They have the same type and contain the same data,
+  // 1) They have the same type and contain the same data (InstructionDataEquals).
   // 2) Their inputs are identical.
   bool Equals(HInstruction* other) const;
 
@@ -786,10 +869,12 @@
   const SideEffects side_effects_;
 
   friend class HBasicBlock;
+  friend class HGraph;
   friend class HInstructionList;
 
   DISALLOW_COPY_AND_ASSIGN(HInstruction);
 };
+std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs);
 
 template<typename T>
 class HUseIterator : public ValueObject {
@@ -815,7 +900,7 @@
 };
 
 // A HEnvironment object contains the values of virtual registers at a given location.
-class HEnvironment : public ArenaObject {
+class HEnvironment : public ArenaObject<kArenaAllocMisc> {
  public:
   HEnvironment(ArenaAllocator* arena, size_t number_of_vregs) : vregs_(arena, number_of_vregs) {
     vregs_.SetSize(number_of_vregs);
@@ -947,14 +1032,14 @@
  public:
   intptr_t length() const { return 0; }
   const T& operator[](intptr_t i) const {
+    UNUSED(i);
     LOG(FATAL) << "Unreachable";
-    static T sentinel = 0;
-    return sentinel;
+    UNREACHABLE();
   }
   T& operator[](intptr_t i) {
+    UNUSED(i);
     LOG(FATAL) << "Unreachable";
-    static T sentinel = 0;
-    return sentinel;
+    UNREACHABLE();
   }
 };
 
@@ -988,8 +1073,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
@@ -1023,7 +1108,7 @@
 };
 
 // The exit instruction is the only instruction of the exit block.
-// Instructions aborting the method (HTrow and HReturn) must branch to the
+// Instructions aborting the method (HThrow and HReturn) must branch to the
 // exit block.
 class HExit : public HTemplateInstruction<0> {
  public:
@@ -1042,7 +1127,7 @@
  public:
   HGoto() : HTemplateInstruction(SideEffects::None()) {}
 
-  virtual bool IsControlFlow() const { return true; }
+  bool IsControlFlow() const OVERRIDE { return true; }
 
   HBasicBlock* GetSuccessor() const {
     return GetBlock()->GetSuccessors().Get(0);
@@ -1063,7 +1148,7 @@
     SetRawInputAt(0, input);
   }
 
-  virtual bool IsControlFlow() const { return true; }
+  bool IsControlFlow() const OVERRIDE { return true; }
 
   HBasicBlock* IfTrueSuccessor() const {
     return GetBlock()->GetSuccessors().Get(0);
@@ -1081,6 +1166,37 @@
   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 {
+    UNUSED(other);
+    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,
@@ -1097,12 +1213,15 @@
   virtual bool IsCommutative() { return false; }
 
   virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+  virtual bool InstructionDataEquals(HInstruction* other) const {
+    UNUSED(other);
+    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;
@@ -1117,13 +1236,13 @@
 class HCondition : public HBinaryOperation {
  public:
   HCondition(HInstruction* first, HInstruction* second)
-      : HBinaryOperation(Primitive::kPrimBoolean, first, second) {}
+      : HBinaryOperation(Primitive::kPrimBoolean, first, second),
+        needs_materialization_(true) {}
 
   virtual bool IsCommutative() { return true; }
 
-  // For register allocation purposes, returns whether this instruction needs to be
-  // materialized (that is, not just be in the processor flags).
-  bool NeedsMaterialization() const;
+  bool NeedsMaterialization() const { return needs_materialization_; }
+  void ClearNeedsMaterialization() { needs_materialization_ = false; }
 
   // For code generation purposes, returns whether this instruction is just before
   // `if_`, and disregard moves in between.
@@ -1134,6 +1253,10 @@
   virtual IfCondition GetCondition() const = 0;
 
  private:
+  // For register allocation purposes, returns whether this instruction needs to be
+  // materialized (that is, not just be in the processor flags).
+  bool needs_materialization_;
+
   DISALLOW_COPY_AND_ASSIGN(HCondition);
 };
 
@@ -1143,8 +1266,12 @@
   HEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x == y ? 1 : 0;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x == y ? 1 : 0;
+  }
 
   DECLARE_INSTRUCTION(Equal);
 
@@ -1161,8 +1288,12 @@
   HNotEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x != y ? 1 : 0;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x != y ? 1 : 0;
+  }
 
   DECLARE_INSTRUCTION(NotEqual);
 
@@ -1179,8 +1310,12 @@
   HLessThan(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x < y ? 1 : 0;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x < y ? 1 : 0;
+  }
 
   DECLARE_INSTRUCTION(LessThan);
 
@@ -1197,8 +1332,12 @@
   HLessThanOrEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x <= y ? 1 : 0;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x <= y ? 1 : 0;
+  }
 
   DECLARE_INSTRUCTION(LessThanOrEqual);
 
@@ -1215,8 +1354,12 @@
   HGreaterThan(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x > y ? 1 : 0;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x > y ? 1 : 0;
+  }
 
   DECLARE_INSTRUCTION(GreaterThan);
 
@@ -1233,8 +1376,12 @@
   HGreaterThanOrEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x >= y ? 1 : 0;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x >= y ? 1 : 0;
+  }
 
   DECLARE_INSTRUCTION(GreaterThanOrEqual);
 
@@ -1251,28 +1398,45 @@
 // Result is 0 if input0 == input1, 1 if input0 > input1, or -1 if input0 < input1.
 class HCompare : public HBinaryOperation {
  public:
-  HCompare(Primitive::Type type, HInstruction* first, HInstruction* second)
-      : HBinaryOperation(Primitive::kPrimInt, first, second) {
+  // The bias applies for floating point operations and indicates how NaN
+  // comparisons are treated:
+  enum Bias {
+    kNoBias,  // bias is not applicable (i.e. for long operation)
+    kGtBias,  // return 1 for NaN comparisons
+    kLtBias,  // return -1 for NaN comparisons
+  };
+
+  HCompare(Primitive::Type type, HInstruction* first, HInstruction* second, Bias bias)
+      : HBinaryOperation(Primitive::kPrimInt, first, second), bias_(bias) {
     DCHECK_EQ(type, first->GetType());
     DCHECK_EQ(type, second->GetType());
   }
 
-  virtual int32_t Evaluate(int32_t x, int32_t y) const {
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
     return
       x == y ? 0 :
       x > y ? 1 :
       -1;
   }
-  virtual int64_t Evaluate(int64_t x, int64_t y) const {
+
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
     return
       x == y ? 0 :
       x > y ? 1 :
       -1;
   }
 
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return bias_ == other->AsCompare()->bias_;
+  }
+
+  bool IsGtBias() { return bias_ == kGtBias; }
+
   DECLARE_INSTRUCTION(Compare);
 
  private:
+  const Bias bias_;
+
   DISALLOW_COPY_AND_ASSIGN(HCompare);
 };
 
@@ -1338,6 +1502,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 {
@@ -1380,25 +1586,24 @@
   DISALLOW_COPY_AND_ASSIGN(HLongConstant);
 };
 
+enum class Intrinsics {
+#define OPTIMIZING_INTRINSICS(Name, IsStatic) k ## Name,
+#include "intrinsics_list.h"
+  kNone,
+  INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+};
+std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic);
+
 class HInvoke : public HInstruction {
  public:
-  HInvoke(ArenaAllocator* arena,
-          uint32_t number_of_arguments,
-          Primitive::Type return_type,
-          uint32_t dex_pc)
-    : HInstruction(SideEffects::All()),
-      inputs_(arena, number_of_arguments),
-      return_type_(return_type),
-      dex_pc_(dex_pc) {
-    inputs_.SetSize(number_of_arguments);
-  }
-
   virtual size_t InputCount() const { return inputs_.Size(); }
   virtual HInstruction* InputAt(size_t i) const { return inputs_.Get(i); }
 
   // Runtime needs to walk the stack, so Dex -> Dex calls need to
   // know their environment.
-  virtual bool NeedsEnvironment() const { return true; }
+  bool NeedsEnvironment() const OVERRIDE { return true; }
 
   void SetArgumentAt(size_t index, HInstruction* argument) {
     SetRawInputAt(index, argument);
@@ -1412,33 +1617,68 @@
 
   uint32_t GetDexPc() const { return dex_pc_; }
 
+  uint32_t GetDexMethodIndex() const { return dex_method_index_; }
+
+  Intrinsics GetIntrinsic() {
+    return intrinsic_;
+  }
+
+  void SetIntrinsic(Intrinsics intrinsic) {
+    intrinsic_ = intrinsic;
+  }
+
+  DECLARE_INSTRUCTION(Invoke);
+
  protected:
+  HInvoke(ArenaAllocator* arena,
+          uint32_t number_of_arguments,
+          Primitive::Type return_type,
+          uint32_t dex_pc,
+          uint32_t dex_method_index)
+    : HInstruction(SideEffects::All()),
+      inputs_(arena, number_of_arguments),
+      return_type_(return_type),
+      dex_pc_(dex_pc),
+      dex_method_index_(dex_method_index),
+      intrinsic_(Intrinsics::kNone) {
+    inputs_.SetSize(number_of_arguments);
+  }
+
   GrowableArray<HInstruction*> inputs_;
   const Primitive::Type return_type_;
   const uint32_t dex_pc_;
+  const uint32_t dex_method_index_;
+  Intrinsics intrinsic_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(HInvoke);
 };
 
-class HInvokeStatic : public HInvoke {
+class HInvokeStaticOrDirect : public HInvoke {
  public:
-  HInvokeStatic(ArenaAllocator* arena,
-                uint32_t number_of_arguments,
-                Primitive::Type return_type,
-                uint32_t dex_pc,
-                uint32_t index_in_dex_cache)
-      : HInvoke(arena, number_of_arguments, return_type, dex_pc),
-        index_in_dex_cache_(index_in_dex_cache) {}
+  HInvokeStaticOrDirect(ArenaAllocator* arena,
+                        uint32_t number_of_arguments,
+                        Primitive::Type return_type,
+                        uint32_t dex_pc,
+                        uint32_t dex_method_index,
+                        InvokeType invoke_type)
+      : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
+        invoke_type_(invoke_type) {}
 
-  uint32_t GetIndexInDexCache() const { return index_in_dex_cache_; }
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    // We access the method via the dex cache so we can't do an implicit null check.
+    // TODO: for intrinsics we can generate implicit null checks.
+    return false;
+  }
 
-  DECLARE_INSTRUCTION(InvokeStatic);
+  InvokeType GetInvokeType() const { return invoke_type_; }
+
+  DECLARE_INSTRUCTION(InvokeStaticOrDirect);
 
  private:
-  const uint32_t index_in_dex_cache_;
+  const InvokeType invoke_type_;
 
-  DISALLOW_COPY_AND_ASSIGN(HInvokeStatic);
+  DISALLOW_COPY_AND_ASSIGN(HInvokeStaticOrDirect);
 };
 
 class HInvokeVirtual : public HInvoke {
@@ -1447,10 +1687,16 @@
                  uint32_t number_of_arguments,
                  Primitive::Type return_type,
                  uint32_t dex_pc,
+                 uint32_t dex_method_index,
                  uint32_t vtable_index)
-      : HInvoke(arena, number_of_arguments, return_type, dex_pc),
+      : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
         vtable_index_(vtable_index) {}
 
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    // TODO: Add implicit null checks in intrinsics.
+    return !GetLocations()->Intrinsified();
+  }
+
   uint32_t GetVTableIndex() const { return vtable_index_; }
 
   DECLARE_INSTRUCTION(InvokeVirtual);
@@ -1461,6 +1707,33 @@
   DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual);
 };
 
+class HInvokeInterface : public HInvoke {
+ public:
+  HInvokeInterface(ArenaAllocator* arena,
+                   uint32_t number_of_arguments,
+                   Primitive::Type return_type,
+                   uint32_t dex_pc,
+                   uint32_t dex_method_index,
+                   uint32_t imt_index)
+      : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
+        imt_index_(imt_index) {}
+
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    // TODO: Add implicit null checks in intrinsics.
+    return !GetLocations()->Intrinsified();
+  }
+
+  uint32_t GetImtIndex() const { return imt_index_; }
+  uint32_t GetDexMethodIndex() const { return dex_method_index_; }
+
+  DECLARE_INSTRUCTION(InvokeInterface);
+
+ private:
+  const uint32_t imt_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HInvokeInterface);
+};
+
 class HNewInstance : public HExpression<0> {
  public:
   HNewInstance(uint32_t dex_pc, uint16_t type_index)
@@ -1472,7 +1745,12 @@
   uint16_t GetTypeIndex() const { return type_index_; }
 
   // Calls runtime so needs an environment.
-  virtual bool NeedsEnvironment() const { return true; }
+  bool NeedsEnvironment() const OVERRIDE { return true; }
+  // It may throw when called on:
+  //   - interfaces
+  //   - abstract/innaccessible/unknown classes
+  // TODO: optimize when possible.
+  bool CanThrow() const OVERRIDE { return true; }
 
   DECLARE_INSTRUCTION(NewInstance);
 
@@ -1483,6 +1761,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)
@@ -1490,8 +1806,12 @@
 
   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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x + y;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x + y;
+  }
 
   DECLARE_INSTRUCTION(Add);
 
@@ -1504,10 +1824,12 @@
   HSub(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  virtual bool IsCommutative() { return false; }
-
-  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; }
+  virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    return x - y;
+  }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    return x - y;
+  }
 
   DECLARE_INSTRUCTION(Sub);
 
@@ -1515,6 +1837,203 @@
   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);
+};
+
+class HDiv : public HBinaryOperation {
+ public:
+  HDiv(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
+      : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {}
+
+  virtual int32_t Evaluate(int32_t x, int32_t y) const {
+    // Our graph structure ensures we never have 0 for `y` during constant folding.
+    DCHECK_NE(y, 0);
+    // Special case -1 to avoid getting a SIGFPE on x86(_64).
+    return (y == -1) ? -x : x / y;
+  }
+
+  virtual int64_t Evaluate(int64_t x, int64_t y) const {
+    DCHECK_NE(y, 0);
+    // Special case -1 to avoid getting a SIGFPE on x86(_64).
+    return (y == -1) ? -x : x / y;
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  DECLARE_INSTRUCTION(Div);
+
+ private:
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HDiv);
+};
+
+class HRem : public HBinaryOperation {
+ public:
+  HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
+      : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {}
+
+  virtual int32_t Evaluate(int32_t x, int32_t y) const {
+    DCHECK_NE(y, 0);
+    // Special case -1 to avoid getting a SIGFPE on x86(_64).
+    return (y == -1) ? 0 : x % y;
+  }
+
+  virtual int64_t Evaluate(int64_t x, int64_t y) const {
+    DCHECK_NE(y, 0);
+    // Special case -1 to avoid getting a SIGFPE on x86(_64).
+    return (y == -1) ? 0 : x % y;
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  DECLARE_INSTRUCTION(Rem);
+
+ private:
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HRem);
+};
+
+class HDivZeroCheck : public HExpression<1> {
+ public:
+  HDivZeroCheck(HInstruction* value, uint32_t dex_pc)
+      : HExpression(value->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+    SetRawInputAt(0, value);
+  }
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    UNUSED(other);
+    return true;
+  }
+
+  bool NeedsEnvironment() const OVERRIDE { return true; }
+  bool CanThrow() const OVERRIDE { return true; }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  DECLARE_INSTRUCTION(DivZeroCheck);
+
+ private:
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
+};
+
+class HShl : public HBinaryOperation {
+ public:
+  HShl(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x << (y & kMaxIntShiftValue); }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x << (y & kMaxLongShiftValue); }
+
+  DECLARE_INSTRUCTION(Shl);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HShl);
+};
+
+class HShr : public HBinaryOperation {
+ public:
+  HShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x >> (y & kMaxIntShiftValue); }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x >> (y & kMaxLongShiftValue); }
+
+  DECLARE_INSTRUCTION(Shr);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HShr);
+};
+
+class HUShr : public HBinaryOperation {
+ public:
+  HUShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+    uint32_t ux = static_cast<uint32_t>(x);
+    uint32_t uy = static_cast<uint32_t>(y) & kMaxIntShiftValue;
+    return static_cast<int32_t>(ux >> uy);
+  }
+
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
+    uint64_t ux = static_cast<uint64_t>(x);
+    uint64_t uy = static_cast<uint64_t>(y) & kMaxLongShiftValue;
+    return static_cast<int64_t>(ux >> uy);
+  }
+
+  DECLARE_INSTRUCTION(UShr);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HUShr);
+};
+
+class HAnd : public HBinaryOperation {
+ public:
+  HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  bool IsCommutative() OVERRIDE { return true; }
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; }
+
+  DECLARE_INSTRUCTION(And);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HAnd);
+};
+
+class HOr : public HBinaryOperation {
+ public:
+  HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  bool IsCommutative() OVERRIDE { return true; }
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; }
+
+  DECLARE_INSTRUCTION(Or);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HOr);
+};
+
+class HXor : public HBinaryOperation {
+ public:
+  HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  bool IsCommutative() OVERRIDE { return true; }
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; }
+
+  DECLARE_INSTRUCTION(Xor);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HXor);
+};
+
 // The value of a parameter in this method. Its location depends on
 // the calling convention.
 class HParameterValue : public HExpression<0> {
@@ -1534,14 +2053,19 @@
   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 bool InstructionDataEquals(HInstruction* other) const {
+    UNUSED(other);
+    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);
 
@@ -1549,6 +2073,34 @@
   DISALLOW_COPY_AND_ASSIGN(HNot);
 };
 
+class HTypeConversion : public HExpression<1> {
+ public:
+  // Instantiate a type conversion of `input` to `result_type`.
+  HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc)
+      : HExpression(result_type, SideEffects::None()), dex_pc_(dex_pc) {
+    SetRawInputAt(0, input);
+    DCHECK_NE(input->GetType(), result_type);
+  }
+
+  HInstruction* GetInput() const { return InputAt(0); }
+  Primitive::Type GetInputType() const { return GetInput()->GetType(); }
+  Primitive::Type GetResultType() const { return GetType(); }
+
+  // Required by the x86 and ARM code generators when producing calls
+  // to the runtime.
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
+
+  DECLARE_INSTRUCTION(TypeConversion);
+
+ private:
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HTypeConversion);
+};
+
 class HPhi : public HInstruction {
  public:
   HPhi(ArenaAllocator* arena, uint32_t reg_number, size_t number_of_inputs, Primitive::Type type)
@@ -1598,10 +2150,15 @@
   }
 
   virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+  virtual bool InstructionDataEquals(HInstruction* other) const {
+    UNUSED(other);
+    return true;
+  }
 
   virtual bool NeedsEnvironment() const { return true; }
 
+  virtual bool CanThrow() const { return true; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
   DECLARE_INSTRUCTION(NullCheck);
@@ -1614,39 +2171,49 @@
 
 class FieldInfo : public ValueObject {
  public:
-  FieldInfo(MemberOffset field_offset, Primitive::Type field_type)
-      : field_offset_(field_offset), field_type_(field_type) {}
+  FieldInfo(MemberOffset field_offset, Primitive::Type field_type, bool is_volatile)
+      : field_offset_(field_offset), field_type_(field_type), is_volatile_(is_volatile) {}
 
   MemberOffset GetFieldOffset() const { return field_offset_; }
   Primitive::Type GetFieldType() const { return field_type_; }
+  bool IsVolatile() const { return is_volatile_; }
 
  private:
   const MemberOffset field_offset_;
   const Primitive::Type field_type_;
+  const bool is_volatile_;
 };
 
 class HInstanceFieldGet : public HExpression<1> {
  public:
   HInstanceFieldGet(HInstruction* value,
                     Primitive::Type field_type,
-                    MemberOffset field_offset)
+                    MemberOffset field_offset,
+                    bool is_volatile)
       : HExpression(field_type, SideEffects::DependsOnSomething()),
-        field_info_(field_offset, field_type) {
+        field_info_(field_offset, field_type, is_volatile) {
     SetRawInputAt(0, value);
   }
 
-  virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const {
-    size_t other_offset = other->AsInstanceFieldGet()->GetFieldOffset().SizeValue();
-    return other_offset == GetFieldOffset().SizeValue();
+  bool CanBeMoved() const OVERRIDE { return !IsVolatile(); }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    HInstanceFieldGet* other_get = other->AsInstanceFieldGet();
+    return GetFieldOffset().SizeValue() == other_get->GetFieldOffset().SizeValue();
   }
 
-  virtual size_t ComputeHashCode() const {
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    return GetFieldOffset().Uint32Value() < kPageSize;
+  }
+
+  size_t ComputeHashCode() const OVERRIDE {
     return (HInstruction::ComputeHashCode() << 7) | GetFieldOffset().SizeValue();
   }
 
+  const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
   Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  bool IsVolatile() const { return field_info_.IsVolatile(); }
 
   DECLARE_INSTRUCTION(InstanceFieldGet);
 
@@ -1661,15 +2228,23 @@
   HInstanceFieldSet(HInstruction* object,
                     HInstruction* value,
                     Primitive::Type field_type,
-                    MemberOffset field_offset)
+                    MemberOffset field_offset,
+                    bool is_volatile)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
-        field_info_(field_offset, field_type) {
+        field_info_(field_offset, field_type, is_volatile) {
     SetRawInputAt(0, object);
     SetRawInputAt(1, value);
   }
 
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    return GetFieldOffset().Uint32Value() < kPageSize;
+  }
+
+  const FieldInfo& GetFieldInfo() const { return field_info_; }
   MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
   Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  bool IsVolatile() const { return field_info_.IsVolatile(); }
+  HInstruction* GetValue() const { return InputAt(1); }
 
   DECLARE_INSTRUCTION(InstanceFieldSet);
 
@@ -1687,8 +2262,24 @@
     SetRawInputAt(1, index);
   }
 
-  virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    UNUSED(other);
+    return true;
+  }
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    // TODO: We can be smarter here.
+    // Currently, the array access is always preceded by an ArrayLength or a NullCheck
+    // which generates the implicit null check. There are cases when these can be removed
+    // to produce better code. If we ever add optimizations to do so we should allow an
+    // implicit check here (as long as the address falls in the first page).
+    return false;
+  }
+
+  void SetType(Primitive::Type type) { type_ = type; }
+
+  HInstruction* GetArray() const { return InputAt(0); }
+  HInstruction* GetIndex() const { return InputAt(1); }
 
   DECLARE_INSTRUCTION(ArrayGet);
 
@@ -1701,31 +2292,57 @@
   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),
+        needs_type_check_(value->GetType() == Primitive::kPrimNot) {
     SetRawInputAt(0, array);
     SetRawInputAt(1, index);
     SetRawInputAt(2, value);
   }
 
-  virtual bool NeedsEnvironment() const {
+  bool NeedsEnvironment() const OVERRIDE {
     // We currently always call a runtime method to catch array store
     // exceptions.
-    return InputAt(2)->GetType() == Primitive::kPrimNot;
+    return needs_type_check_;
   }
 
+  bool CanDoImplicitNullCheck() const OVERRIDE {
+    // TODO: Same as for ArrayGet.
+    return false;
+  }
+
+  void ClearNeedsTypeCheck() {
+    needs_type_check_ = false;
+  }
+
+  bool NeedsTypeCheck() const { return needs_type_check_; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
-  Primitive::Type GetComponentType() const { return component_type_; }
+  HInstruction* GetArray() const { return InputAt(0); }
+  HInstruction* GetIndex() const { return InputAt(1); }
+  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_;
+  bool needs_type_check_;
 
   DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
@@ -1739,8 +2356,12 @@
     SetRawInputAt(0, array);
   }
 
-  virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    UNUSED(other);
+    return true;
+  }
+  bool CanDoImplicitNullCheck() const OVERRIDE { return true; }
 
   DECLARE_INSTRUCTION(ArrayLength);
 
@@ -1758,10 +2379,15 @@
   }
 
   virtual bool CanBeMoved() const { return true; }
-  virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+  virtual bool InstructionDataEquals(HInstruction* other) const {
+    UNUSED(other);
+    return true;
+  }
 
   virtual bool NeedsEnvironment() const { return true; }
 
+  virtual bool CanThrow() const { return true; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
   DECLARE_INSTRUCTION(BoundsCheck);
@@ -1776,8 +2402,8 @@
  * Some DEX instructions are folded into multiple HInstructions that need
  * to stay live until the last HInstruction. This class
  * is used as a marker for the baseline compiler to ensure its preceding
- * HInstruction stays live. `index` is the temporary number that is used
- * for knowing the stack offset where to store the instruction.
+ * HInstruction stays live. `index` represents the stack location index of the
+ * instruction (the actual offset is computed as index * vreg_size).
  */
 class HTemporary : public HTemplateInstruction<0> {
  public:
@@ -1785,6 +2411,12 @@
 
   size_t GetIndex() const { return index_; }
 
+  Primitive::Type GetType() const OVERRIDE {
+    // The previous instruction is the one that will be stored in the temporary location.
+    DCHECK(GetPrevious() != nullptr);
+    return GetPrevious()->GetType();
+  }
+
   DECLARE_INSTRUCTION(Temporary);
 
  private:
@@ -1812,7 +2444,330 @@
   DISALLOW_COPY_AND_ASSIGN(HSuspendCheck);
 };
 
-class MoveOperands : public ArenaObject {
+/**
+ * Instruction to load a Class object.
+ */
+class HLoadClass : public HExpression<0> {
+ public:
+  HLoadClass(uint16_t type_index,
+             bool is_referrers_class,
+             uint32_t dex_pc)
+      : HExpression(Primitive::kPrimNot, SideEffects::None()),
+        type_index_(type_index),
+        is_referrers_class_(is_referrers_class),
+        dex_pc_(dex_pc),
+        generate_clinit_check_(false) {}
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return other->AsLoadClass()->type_index_ == type_index_;
+  }
+
+  size_t ComputeHashCode() const OVERRIDE { return type_index_; }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+  uint16_t GetTypeIndex() const { return type_index_; }
+  bool IsReferrersClass() const { return is_referrers_class_; }
+
+  bool NeedsEnvironment() const OVERRIDE {
+    // Will call runtime and load the class if the class is not loaded yet.
+    // TODO: finer grain decision.
+    return !is_referrers_class_;
+  }
+
+  bool MustGenerateClinitCheck() const {
+    return generate_clinit_check_;
+  }
+
+  void SetMustGenerateClinitCheck() {
+    generate_clinit_check_ = true;
+  }
+
+  bool CanCallRuntime() const {
+    return MustGenerateClinitCheck() || !is_referrers_class_;
+  }
+
+  DECLARE_INSTRUCTION(LoadClass);
+
+ private:
+  const uint16_t type_index_;
+  const bool is_referrers_class_;
+  const uint32_t dex_pc_;
+  // Whether this instruction must generate the initialization check.
+  // Used for code generation.
+  bool generate_clinit_check_;
+
+  DISALLOW_COPY_AND_ASSIGN(HLoadClass);
+};
+
+class HLoadString : public HExpression<0> {
+ public:
+  HLoadString(uint32_t string_index, uint32_t dex_pc)
+      : HExpression(Primitive::kPrimNot, SideEffects::None()),
+        string_index_(string_index),
+        dex_pc_(dex_pc) {}
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return other->AsLoadString()->string_index_ == string_index_;
+  }
+
+  size_t ComputeHashCode() const OVERRIDE { return string_index_; }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+  uint32_t GetStringIndex() const { return string_index_; }
+
+  // TODO: Can we deopt or debug when we resolve a string?
+  bool NeedsEnvironment() const OVERRIDE { return false; }
+
+  DECLARE_INSTRUCTION(LoadString);
+
+ private:
+  const uint32_t string_index_;
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HLoadString);
+};
+
+// TODO: Pass this check to HInvokeStaticOrDirect nodes.
+/**
+ * Performs an initialization check on its Class object input.
+ */
+class HClinitCheck : public HExpression<1> {
+ public:
+  explicit HClinitCheck(HLoadClass* constant, uint32_t dex_pc)
+      : HExpression(Primitive::kPrimNot, SideEffects::All()),
+        dex_pc_(dex_pc) {
+    SetRawInputAt(0, constant);
+  }
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    UNUSED(other);
+    return true;
+  }
+
+  bool NeedsEnvironment() const OVERRIDE {
+    // May call runtime to initialize the class.
+    return true;
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  HLoadClass* GetLoadClass() const { return InputAt(0)->AsLoadClass(); }
+
+  DECLARE_INSTRUCTION(ClinitCheck);
+
+ private:
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HClinitCheck);
+};
+
+class HStaticFieldGet : public HExpression<1> {
+ public:
+  HStaticFieldGet(HInstruction* cls,
+                  Primitive::Type field_type,
+                  MemberOffset field_offset,
+                  bool is_volatile)
+      : HExpression(field_type, SideEffects::DependsOnSomething()),
+        field_info_(field_offset, field_type, is_volatile) {
+    SetRawInputAt(0, cls);
+  }
+
+
+  bool CanBeMoved() const OVERRIDE { return !IsVolatile(); }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    HStaticFieldGet* other_get = other->AsStaticFieldGet();
+    return GetFieldOffset().SizeValue() == other_get->GetFieldOffset().SizeValue();
+  }
+
+  size_t ComputeHashCode() const OVERRIDE {
+    return (HInstruction::ComputeHashCode() << 7) | GetFieldOffset().SizeValue();
+  }
+
+  const FieldInfo& GetFieldInfo() const { return field_info_; }
+  MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
+  Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  bool IsVolatile() const { return field_info_.IsVolatile(); }
+
+  DECLARE_INSTRUCTION(StaticFieldGet);
+
+ private:
+  const FieldInfo field_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(HStaticFieldGet);
+};
+
+class HStaticFieldSet : public HTemplateInstruction<2> {
+ public:
+  HStaticFieldSet(HInstruction* cls,
+                  HInstruction* value,
+                  Primitive::Type field_type,
+                  MemberOffset field_offset,
+                  bool is_volatile)
+      : HTemplateInstruction(SideEffects::ChangesSomething()),
+        field_info_(field_offset, field_type, is_volatile) {
+    SetRawInputAt(0, cls);
+    SetRawInputAt(1, value);
+  }
+
+  const FieldInfo& GetFieldInfo() const { return field_info_; }
+  MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
+  Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+  bool IsVolatile() const { return field_info_.IsVolatile(); }
+
+  HInstruction* GetValue() const { return InputAt(1); }
+
+  DECLARE_INSTRUCTION(StaticFieldSet);
+
+ private:
+  const FieldInfo field_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
+};
+
+// Implement the move-exception DEX instruction.
+class HLoadException : public HExpression<0> {
+ public:
+  HLoadException() : HExpression(Primitive::kPrimNot, SideEffects::None()) {}
+
+  DECLARE_INSTRUCTION(LoadException);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HLoadException);
+};
+
+class HThrow : public HTemplateInstruction<1> {
+ public:
+  HThrow(HInstruction* exception, uint32_t dex_pc)
+      : HTemplateInstruction(SideEffects::None()), dex_pc_(dex_pc) {
+    SetRawInputAt(0, exception);
+  }
+
+  bool IsControlFlow() const OVERRIDE { return true; }
+
+  bool NeedsEnvironment() const OVERRIDE { return true; }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  DECLARE_INSTRUCTION(Throw);
+
+ private:
+  uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HThrow);
+};
+
+class HInstanceOf : public HExpression<2> {
+ public:
+  HInstanceOf(HInstruction* object,
+              HLoadClass* constant,
+              bool class_is_final,
+              uint32_t dex_pc)
+      : HExpression(Primitive::kPrimBoolean, SideEffects::None()),
+        class_is_final_(class_is_final),
+        dex_pc_(dex_pc) {
+    SetRawInputAt(0, object);
+    SetRawInputAt(1, constant);
+  }
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+
+  bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+    return true;
+  }
+
+  bool NeedsEnvironment() const OVERRIDE {
+    return false;
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  bool IsClassFinal() const { return class_is_final_; }
+
+  DECLARE_INSTRUCTION(InstanceOf);
+
+ private:
+  const bool class_is_final_;
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HInstanceOf);
+};
+
+class HCheckCast : public HTemplateInstruction<2> {
+ public:
+  HCheckCast(HInstruction* object,
+             HLoadClass* constant,
+             bool class_is_final,
+             uint32_t dex_pc)
+      : HTemplateInstruction(SideEffects::None()),
+        class_is_final_(class_is_final),
+        dex_pc_(dex_pc) {
+    SetRawInputAt(0, object);
+    SetRawInputAt(1, constant);
+  }
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+
+  bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+    return true;
+  }
+
+  bool NeedsEnvironment() const OVERRIDE {
+    // Instruction may throw a CheckCastError.
+    return true;
+  }
+
+  bool CanThrow() const OVERRIDE { return true; }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  bool IsClassFinal() const { return class_is_final_; }
+
+  DECLARE_INSTRUCTION(CheckCast);
+
+ private:
+  const bool class_is_final_;
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HCheckCast);
+};
+
+class HMonitorOperation : public HTemplateInstruction<1> {
+ public:
+  enum OperationKind {
+    kEnter,
+    kExit,
+  };
+
+  HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc)
+    : HTemplateInstruction(SideEffects::None()), kind_(kind), dex_pc_(dex_pc) {
+    SetRawInputAt(0, object);
+  }
+
+  // Instruction may throw a Java exception, so we need an environment.
+  bool NeedsEnvironment() const OVERRIDE { return true; }
+  bool CanThrow() const OVERRIDE { return true; }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  bool IsEnter() const { return kind_ == kEnter; }
+
+  DECLARE_INSTRUCTION(MonitorOperation);
+
+ private:
+  const OperationKind kind_;
+  const uint32_t dex_pc_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
+};
+
+class MoveOperands : public ArenaObject<kArenaAllocMisc> {
  public:
   MoveOperands(Location source, Location destination, HInstruction* instruction)
       : source_(source), destination_(destination), instruction_(instruction) {}
@@ -1873,8 +2828,6 @@
   // This is only used in debug mode, to ensure we do not connect interval siblings
   // in the same parallel move.
   HInstruction* instruction_;
-
-  DISALLOW_COPY_AND_ASSIGN(MoveOperands);
 };
 
 static constexpr size_t kDefaultNumberOfMoves = 4;
@@ -1884,18 +2837,53 @@
   explicit HParallelMove(ArenaAllocator* arena)
       : HTemplateInstruction(SideEffects::None()), moves_(arena, kDefaultNumberOfMoves) {}
 
-  void AddMove(MoveOperands* move) {
-    if (kIsDebugBuild && move->GetInstruction() != nullptr) {
-      for (size_t i = 0, e = moves_.Size(); i < e; ++i) {
-        DCHECK_NE(moves_.Get(i)->GetInstruction(), move->GetInstruction())
-          << "Doing parallel moves for the same instruction.";
+  void AddMove(Location source, Location destination, HInstruction* instruction) {
+    DCHECK(source.IsValid());
+    DCHECK(destination.IsValid());
+    // The parallel move resolver does not handle pairs. So we decompose the
+    // pair locations into two moves.
+    if (source.IsPair() && destination.IsPair()) {
+      AddMove(source.ToLow(), destination.ToLow(), instruction);
+      AddMove(source.ToHigh(), destination.ToHigh(), nullptr);
+    } else if (source.IsPair()) {
+      DCHECK(destination.IsDoubleStackSlot()) << destination;
+      AddMove(source.ToLow(), Location::StackSlot(destination.GetStackIndex()), instruction);
+      AddMove(source.ToHigh(), Location::StackSlot(destination.GetHighStackIndex(4)), nullptr);
+    } else if (destination.IsPair()) {
+      if (source.IsConstant()) {
+        // We put the same constant in the move. The code generator will handle which
+        // low or high part to use.
+        AddMove(source, destination.ToLow(), instruction);
+        AddMove(source, destination.ToHigh(), nullptr);
+      } else {
+        DCHECK(source.IsDoubleStackSlot());
+        AddMove(Location::StackSlot(source.GetStackIndex()), destination.ToLow(), instruction);
+        // TODO: rewrite GetHighStackIndex to not require a word size. It's supposed to
+        // always be 4.
+        static constexpr int kHighOffset = 4;
+        AddMove(Location::StackSlot(source.GetHighStackIndex(kHighOffset)),
+                destination.ToHigh(),
+                nullptr);
       }
+    } else {
+      if (kIsDebugBuild) {
+        if (instruction != nullptr) {
+          for (size_t i = 0, e = moves_.Size(); i < e; ++i) {
+            DCHECK_NE(moves_.Get(i).GetInstruction(), instruction)
+              << "Doing parallel moves for the same instruction.";
+          }
+        }
+        for (size_t i = 0, e = moves_.Size(); i < e; ++i) {
+          DCHECK(!destination.Equals(moves_.Get(i).GetDestination()))
+              << "Same destination for two moves in a parallel move.";
+        }
+      }
+      moves_.Add(MoveOperands(source, destination, instruction));
     }
-    moves_.Add(move);
   }
 
   MoveOperands* MoveOperandsAt(size_t index) const {
-    return moves_.Get(index);
+    return moves_.GetRawStorage() + index;
   }
 
   size_t NumMoves() const { return moves_.Size(); }
@@ -1903,7 +2891,7 @@
   DECLARE_INSTRUCTION(ParallelMove);
 
  private:
-  GrowableArray<MoveOperands*> moves_;
+  GrowableArray<MoveOperands> moves_;
 
   DISALLOW_COPY_AND_ASSIGN(HParallelMove);
 };
@@ -1913,15 +2901,19 @@
   explicit HGraphVisitor(HGraph* graph) : graph_(graph) {}
   virtual ~HGraphVisitor() {}
 
-  virtual void VisitInstruction(HInstruction* instruction) {}
+  virtual void VisitInstruction(HInstruction* instruction) { UNUSED(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.
-#define DECLARE_VISIT_INSTRUCTION(name)                                        \
+#define DECLARE_VISIT_INSTRUCTION(name, super)                                        \
   virtual void Visit##name(H##name* instr) { VisitInstruction(instr); }
 
   FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -1929,11 +2921,28 @@
 #undef DECLARE_VISIT_INSTRUCTION
 
  private:
-  HGraph* graph_;
+  HGraph* const graph_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphVisitor);
 };
 
+class HGraphDelegateVisitor : public HGraphVisitor {
+ public:
+  explicit HGraphDelegateVisitor(HGraph* graph) : HGraphVisitor(graph) {}
+  virtual ~HGraphDelegateVisitor() {}
+
+  // Visit functions that delegate to to super class.
+#define DECLARE_VISIT_INSTRUCTION(name, super)                                        \
+  virtual void Visit##name(H##name* instr) OVERRIDE { Visit##super(instr); }
+
+  FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HGraphDelegateVisitor);
+};
+
 class HInsertionOrderIterator : public ValueObject {
  public:
   explicit HInsertionOrderIterator(const HGraph& graph) : graph_(graph), index_(0) {}
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index b75bacb..70dd8d7 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -63,4 +63,55 @@
   ASSERT_FALSE(parameter->HasUses());
 }
 
+/**
+ * Test that inserting an instruction in the graph updates user lists.
+ */
+TEST(Node, InsertInstruction) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter1 = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+  HInstruction* parameter2 = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+  entry->AddInstruction(parameter1);
+  entry->AddInstruction(parameter2);
+  entry->AddInstruction(new (&allocator) HExit());
+
+  ASSERT_FALSE(parameter1->HasUses());
+  ASSERT_EQ(parameter1->NumberOfUses(), 0u);
+
+  HInstruction* to_insert = new (&allocator) HNullCheck(parameter1, 0);
+  entry->InsertInstructionBefore(to_insert, parameter2);
+
+  ASSERT_TRUE(parameter1->HasUses());
+  ASSERT_EQ(parameter1->NumberOfUses(), 1u);
+}
+
+/**
+ * Test that adding an instruction in the graph updates user lists.
+ */
+TEST(Node, AddInstruction) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+  entry->AddInstruction(parameter);
+
+  ASSERT_FALSE(parameter->HasUses());
+  ASSERT_EQ(parameter->NumberOfUses(), 0u);
+
+  HInstruction* to_add = new (&allocator) HNullCheck(parameter, 0);
+  entry->AddInstruction(to_add);
+
+  ASSERT_TRUE(parameter->HasUses());
+  ASSERT_EQ(parameter->NumberOfUses(), 1u);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
new file mode 100644
index 0000000..b99f678
--- /dev/null
+++ b/compiler/optimizing/optimization.cc
@@ -0,0 +1,44 @@
+/*
+ * 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::Check() {
+  if (kIsDebugBuild) {
+    if (is_in_ssa_form_) {
+      SSAChecker checker(graph_->GetArena(), graph_);
+      checker.Run();
+      if (!checker.IsValid()) {
+        LOG(FATAL) << "Error after " << GetPassName() << ": "
+                   << Dumpable<SSAChecker>(checker);
+      }
+    } else {
+      GraphChecker checker(graph_->GetArena(), graph_);
+      checker.Run();
+      if (!checker.IsValid()) {
+        LOG(FATAL) << "Error after " << GetPassName() << ": "
+                   << Dumpable<GraphChecker>(checker);
+      }
+    }
+  }
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
new file mode 100644
index 0000000..e36ef19
--- /dev/null
+++ b/compiler/optimizing/optimization.h
@@ -0,0 +1,61 @@
+/*
+ * 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 "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)
+      : graph_(graph),
+        is_in_ssa_form_(is_in_ssa_form),
+        pass_name_(pass_name) {}
+
+  virtual ~HOptimization() {}
+
+  // Return the name of the pass.
+  const char* GetPassName() const { return pass_name_; }
+
+  // Peform the analysis itself.
+  virtual void Run() = 0;
+
+  // 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_;
+
+  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 65bdb18..1e0d65a 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -19,16 +19,27 @@
 #include <fstream>
 #include <stdint.h>
 
+#include "bounds_check_elimination.h"
 #include "builder.h"
 #include "code_generator.h"
 #include "compiler.h"
+#include "constant_folding.h"
+#include "dead_code_elimination.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
+#include "elf_writer_quick.h"
 #include "graph_visualizer.h"
 #include "gvn.h"
+#include "inliner.h"
 #include "instruction_simplifier.h"
+#include "intrinsics.h"
+#include "jni/quick/jni_compiler.h"
+#include "mirror/art_method-inl.h"
 #include "nodes.h"
+#include "prepare_for_register_allocation.h"
 #include "register_allocator.h"
+#include "ssa_builder.h"
 #include "ssa_phi_elimination.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/arena_allocator.h"
@@ -59,13 +70,8 @@
 };
 
 /**
- * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
- */
-static bool kIsVisualizerEnabled = false;
-
-/**
  * Filter to apply to the visualizer. Methods whose name contain that filter will
- * be in the file.
+ * be dumped.
  */
 static const char* kStringFilter = "";
 
@@ -85,15 +91,6 @@
                           jobject class_loader,
                           const DexFile& dex_file) const OVERRIDE;
 
-  CompiledMethod* TryCompile(const DexFile::CodeItem* code_item,
-                             uint32_t access_flags,
-                             InvokeType invoke_type,
-                             uint16_t class_def_idx,
-                             uint32_t method_idx,
-                             jobject class_loader,
-                             const DexFile& dex_file) const;
-
-  // For the following methods we will use the fallback. This is a delegation pattern.
   CompiledMethod* JniCompile(uint32_t access_flags,
                              uint32_t method_idx,
                              const DexFile& dex_file) const OVERRIDE;
@@ -107,28 +104,38 @@
                 const std::string& android_root,
                 bool is_host) const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE;
+  Backend* GetCodeGenerator(CompilationUnit* cu ATTRIBUTE_UNUSED,
+                            void* compilation_unit ATTRIBUTE_UNUSED) const OVERRIDE {
+    return nullptr;
+  }
 
-  void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE;
+  void InitCompilationUnit(CompilationUnit& cu ATTRIBUTE_UNUSED) const OVERRIDE {}
 
-  void Init() const OVERRIDE;
+  void Init() OVERRIDE;
 
-  void UnInit() const OVERRIDE;
+  void UnInit() const OVERRIDE {}
 
  private:
   // Whether we should run any optimization or register allocation. If false, will
   // just run the code generation after the graph was built.
   const bool run_optimizations_;
-  mutable AtomicInteger total_compiled_methods_;
-  mutable AtomicInteger unoptimized_compiled_methods_;
-  mutable AtomicInteger optimized_compiled_methods_;
+
+  // Optimize and compile `graph`.
+  CompiledMethod* CompileOptimized(HGraph* graph,
+                                   CodeGenerator* codegen,
+                                   CompilerDriver* driver,
+                                   const DexCompilationUnit& dex_compilation_unit,
+                                   const HGraphVisualizer& visualizer) const;
+
+  // Just compile without doing optimizations.
+  CompiledMethod* CompileBaseline(CodeGenerator* codegen,
+                                  CompilerDriver* driver,
+                                  const DexCompilationUnit& dex_compilation_unit) const;
+
+  mutable OptimizingCompilerStats compilation_stats_;
 
   std::unique_ptr<std::ostream> visualizer_output_;
 
-  // Delegate to another compiler in case the optimizing compiler cannot compile a method.
-  // Currently the fallback is the quick compiler.
-  std::unique_ptr<Compiler> delegate_;
-
   DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
 };
 
@@ -138,202 +145,180 @@
     : Compiler(driver, kMaximumCompilationTimeBeforeWarning),
       run_optimizations_(
           driver->GetCompilerOptions().GetCompilerFilter() != CompilerOptions::kTime),
-      total_compiled_methods_(0),
-      unoptimized_compiled_methods_(0),
-      optimized_compiled_methods_(0),
-      delegate_(Create(driver, Compiler::Kind::kQuick)) {
-  if (kIsVisualizerEnabled) {
-    visualizer_output_.reset(new std::ofstream("art.cfg"));
+      compilation_stats_() {}
+
+void OptimizingCompiler::Init() {
+  // Enable C1visualizer output. Must be done in Init() because the compiler
+  // driver is not fully initialized when passed to the compiler's constructor.
+  CompilerDriver* driver = GetCompilerDriver();
+  const std::string cfg_file_name = driver->GetDumpCfgFileName();
+  if (!cfg_file_name.empty()) {
+    CHECK_EQ(driver->GetThreadCount(), 1U)
+      << "Graph visualizer requires the compiler to run single-threaded. "
+      << "Invoke the compiler with '-j1'.";
+    visualizer_output_.reset(new std::ofstream(cfg_file_name));
   }
 }
 
-void OptimizingCompiler::Init() const {
-  delegate_->Init();
-}
-
-void OptimizingCompiler::UnInit() const {
-  delegate_->UnInit();
-}
-
 OptimizingCompiler::~OptimizingCompiler() {
-  if (total_compiled_methods_ == 0) {
-    LOG(INFO) << "Did not compile any method.";
-  } else {
-    size_t unoptimized_percent = (unoptimized_compiled_methods_ * 100 / total_compiled_methods_);
-    size_t optimized_percent = (optimized_compiled_methods_ * 100 / total_compiled_methods_);
-    LOG(INFO) << "Compiled " << total_compiled_methods_ << " methods: "
-              << unoptimized_percent << "% (" << unoptimized_compiled_methods_ << ") unoptimized, "
-              << optimized_percent << "% (" << optimized_compiled_methods_ << ") optimized.";
-  }
+  compilation_stats_.Log();
 }
 
-bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file,
-                                          CompilationUnit* cu) const {
-  return delegate_->CanCompileMethod(method_idx, dex_file, cu);
+bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx ATTRIBUTE_UNUSED,
+                                          const DexFile& dex_file ATTRIBUTE_UNUSED,
+                                          CompilationUnit* cu ATTRIBUTE_UNUSED) const {
+  return true;
 }
 
 CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags,
                                                uint32_t method_idx,
                                                const DexFile& dex_file) const {
-  return delegate_->JniCompile(access_flags, method_idx, dex_file);
+  return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file);
 }
 
 uintptr_t OptimizingCompiler::GetEntryPointOf(mirror::ArtMethod* method) const {
-  return delegate_->GetEntryPointOf(method);
+  return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize(
+      InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet())));
 }
 
 bool OptimizingCompiler::WriteElf(art::File* file, OatWriter* oat_writer,
                                   const std::vector<const art::DexFile*>& dex_files,
                                   const std::string& android_root, bool is_host) const {
-  return delegate_->WriteElf(file, oat_writer, dex_files, android_root, is_host);
+  return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host,
+                                       *GetCompilerDriver());
 }
 
-Backend* OptimizingCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
-  return delegate_->GetCodeGenerator(cu, compilation_unit);
+static bool IsInstructionSetSupported(InstructionSet instruction_set) {
+  return instruction_set == kArm64
+      || (instruction_set == kThumb2 && !kArm32QuickCodeUseSoftFloat)
+      || instruction_set == kX86
+      || instruction_set == kX86_64;
 }
 
-void OptimizingCompiler::InitCompilationUnit(CompilationUnit& cu) const {
-  delegate_->InitCompilationUnit(cu);
+static bool CanOptimize(const DexFile::CodeItem& code_item) {
+  // TODO: We currently cannot optimize methods with try/catch.
+  return code_item.tries_size_ == 0;
 }
 
-CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
-                                               uint32_t access_flags,
-                                               InvokeType invoke_type,
-                                               uint16_t class_def_idx,
-                                               uint32_t method_idx,
-                                               jobject class_loader,
-                                               const DexFile& dex_file) const {
-  total_compiled_methods_++;
-  InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
-  // Always use the thumb2 assembler: some runtime functionality (like implicit stack
-  // overflow checks) assume thumb2.
-  if (instruction_set == kArm) {
-    instruction_set = kThumb2;
+static void RunOptimizations(HGraph* graph,
+                             CompilerDriver* driver,
+                             OptimizingCompilerStats* stats,
+                             const DexCompilationUnit& dex_compilation_unit,
+                             const HGraphVisualizer& visualizer) {
+  SsaRedundantPhiElimination redundant_phi(graph);
+  SsaDeadPhiElimination dead_phi(graph);
+  HDeadCodeElimination dce(graph);
+  HConstantFolding fold1(graph);
+  InstructionSimplifier simplify1(graph);
+
+  HInliner inliner(graph, dex_compilation_unit, driver, stats);
+
+  HConstantFolding fold2(graph);
+  GVNOptimization gvn(graph);
+  BoundsCheckElimination bce(graph);
+  InstructionSimplifier simplify2(graph);
+
+  IntrinsicsRecognizer intrinsics(graph, dex_compilation_unit.GetDexFile(), driver);
+
+  HOptimization* optimizations[] = {
+    &redundant_phi,
+    &dead_phi,
+    &intrinsics,
+    &dce,
+    &fold1,
+    &simplify1,
+    &inliner,
+    &fold2,
+    &gvn,
+    &bce,
+    &simplify2
+  };
+
+  for (size_t i = 0; i < arraysize(optimizations); ++i) {
+    HOptimization* optimization = optimizations[i];
+    visualizer.DumpGraph(optimization->GetPassName(), /*is_after=*/false);
+    optimization->Run();
+    visualizer.DumpGraph(optimization->GetPassName(), /*is_after=*/true);
+    optimization->Check();
   }
+}
 
-  // Do not attempt to compile on architectures we do not support.
-  if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) {
-    return nullptr;
+// The stack map we generate must be 4-byte aligned on ARM. Since existing
+// maps are generated alongside these stack maps, we must also align them.
+static ArrayRef<const uint8_t> AlignVectorSize(std::vector<uint8_t>& vector) {
+  size_t size = vector.size();
+  size_t aligned_size = RoundUp(size, 4);
+  for (; size < aligned_size; ++size) {
+    vector.push_back(0);
   }
+  return ArrayRef<const uint8_t>(vector);
+}
 
-  DexCompilationUnit dex_compilation_unit(
-    nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item,
-    class_def_idx, method_idx, access_flags,
-    GetCompilerDriver()->GetVerifiedMethod(&dex_file, method_idx));
 
-  // For testing purposes, we put a special marker on method names that should be compiled
-  // with this compiler. This makes sure we're not regressing.
-  bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos;
-  bool shouldOptimize =
-      dex_compilation_unit.GetSymbol().find("00024reg_00024") != std::string::npos;
+CompiledMethod* OptimizingCompiler::CompileOptimized(HGraph* graph,
+                                                     CodeGenerator* codegen,
+                                                     CompilerDriver* compiler_driver,
+                                                     const DexCompilationUnit& dex_compilation_unit,
+                                                     const HGraphVisualizer& visualizer) const {
+  RunOptimizations(
+      graph, compiler_driver, &compilation_stats_, dex_compilation_unit, visualizer);
 
-  ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file, GetCompilerDriver());
+  PrepareForRegisterAllocation(graph).Run();
+  SsaLivenessAnalysis liveness(*graph, codegen);
+  liveness.Analyze();
+  visualizer.DumpGraph(kLivenessPassName);
 
-  HGraph* graph = builder.BuildGraph(*code_item);
-  if (graph == nullptr) {
-    if (shouldCompile) {
-      LOG(FATAL) << "Could not build graph in optimizing compiler";
-    }
-    return nullptr;
-  }
-
-  CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, instruction_set);
-  if (codegen == nullptr) {
-    if (shouldCompile) {
-      LOG(FATAL) << "Could not find code generator for optimizing compiler";
-    }
-    return nullptr;
-  }
-
-  HGraphVisualizer visualizer(
-      visualizer_output_.get(), graph, kStringFilter, *codegen, dex_compilation_unit);
-  visualizer.DumpGraph("builder");
+  RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
+  register_allocator.AllocateRegisters();
+  visualizer.DumpGraph(kRegisterAllocatorPassName);
 
   CodeVectorAllocator allocator;
+  codegen->CompileOptimized(&allocator);
 
-  if (run_optimizations_ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
-    optimized_compiled_methods_++;
-    graph->BuildDominatorTree();
-    graph->TransformToSSA();
-    visualizer.DumpGraph("ssa");
-    graph->FindNaturalLoops();
+  std::vector<uint8_t> stack_map;
+  codegen->BuildStackMaps(&stack_map);
 
-    SsaRedundantPhiElimination(graph).Run();
-    SsaDeadPhiElimination(graph).Run();
-    InstructionSimplifier(graph).Run();
-    GlobalValueNumberer(graph->GetArena(), graph).Run();
-    visualizer.DumpGraph(kGVNPassName);
+  compilation_stats_.RecordStat(MethodCompilationStat::kCompiledOptimized);
 
-    SsaLivenessAnalysis liveness(*graph, codegen);
-    liveness.Analyze();
-    visualizer.DumpGraph(kLivenessPassName);
+  return CompiledMethod::SwapAllocCompiledMethodStackMap(
+      compiler_driver,
+      codegen->GetInstructionSet(),
+      ArrayRef<const uint8_t>(allocator.GetMemory()),
+      codegen->GetFrameSize(),
+      codegen->GetCoreSpillMask(),
+      0, /* FPR spill mask, unused */
+      ArrayRef<const uint8_t>(stack_map));
+}
 
-    RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
-    register_allocator.AllocateRegisters();
 
-    visualizer.DumpGraph(kRegisterAllocatorPassName);
-    codegen->CompileOptimized(&allocator);
+CompiledMethod* OptimizingCompiler::CompileBaseline(
+    CodeGenerator* codegen,
+    CompilerDriver* compiler_driver,
+    const DexCompilationUnit& dex_compilation_unit) const {
+  CodeVectorAllocator allocator;
+  codegen->CompileBaseline(&allocator);
 
-    std::vector<uint8_t> mapping_table;
-    SrcMap src_mapping_table;
-    codegen->BuildMappingTable(&mapping_table,
-            GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
-                 &src_mapping_table : nullptr);
+  std::vector<uint8_t> mapping_table;
+  DefaultSrcMap src_mapping_table;
+  bool include_debug_symbol = compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols();
+  codegen->BuildMappingTable(&mapping_table, include_debug_symbol ? &src_mapping_table : nullptr);
+  std::vector<uint8_t> vmap_table;
+  codegen->BuildVMapTable(&vmap_table);
+  std::vector<uint8_t> gc_map;
+  codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
 
-    std::vector<uint8_t> stack_map;
-    codegen->BuildStackMaps(&stack_map);
-
-    return new CompiledMethod(GetCompilerDriver(),
-                              instruction_set,
-                              allocator.GetMemory(),
-                              codegen->GetFrameSize(),
-                              codegen->GetCoreSpillMask(),
-                              0, /* FPR spill mask, unused */
-                              mapping_table,
-                              stack_map);
-  } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
-    LOG(FATAL) << "Could not allocate registers in optimizing compiler";
-    return nullptr;
-  } else {
-    unoptimized_compiled_methods_++;
-    codegen->CompileBaseline(&allocator);
-
-    // Run these phases to get some test coverage.
-    graph->BuildDominatorTree();
-    graph->TransformToSSA();
-    visualizer.DumpGraph("ssa");
-    graph->FindNaturalLoops();
-    SsaRedundantPhiElimination(graph).Run();
-    SsaDeadPhiElimination(graph).Run();
-    GlobalValueNumberer(graph->GetArena(), graph).Run();
-    SsaLivenessAnalysis liveness(*graph, codegen);
-    liveness.Analyze();
-    visualizer.DumpGraph(kLivenessPassName);
-
-    std::vector<uint8_t> mapping_table;
-    SrcMap src_mapping_table;
-    codegen->BuildMappingTable(&mapping_table,
-            GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
-                 &src_mapping_table : nullptr);
-    std::vector<uint8_t> vmap_table;
-    codegen->BuildVMapTable(&vmap_table);
-    std::vector<uint8_t> gc_map;
-    codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
-
-    return new CompiledMethod(GetCompilerDriver(),
-                              instruction_set,
-                              allocator.GetMemory(),
-                              codegen->GetFrameSize(),
-                              codegen->GetCoreSpillMask(),
-                              0, /* FPR spill mask, unused */
-                              &src_mapping_table,
-                              mapping_table,
-                              vmap_table,
-                              gc_map,
-                              nullptr);
-  }
+  compilation_stats_.RecordStat(MethodCompilationStat::kCompiledBaseline);
+  return CompiledMethod::SwapAllocCompiledMethod(compiler_driver,
+                                                 codegen->GetInstructionSet(),
+                                                 ArrayRef<const uint8_t>(allocator.GetMemory()),
+                                                 codegen->GetFrameSize(),
+                                                 codegen->GetCoreSpillMask(),
+                                                 0, /* FPR spill mask, unused */
+                                                 &src_mapping_table,
+                                                 AlignVectorSize(mapping_table),
+                                                 AlignVectorSize(vmap_table),
+                                                 AlignVectorSize(gc_map),
+                                                 ArrayRef<const uint8_t>());
 }
 
 CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
@@ -343,14 +328,101 @@
                                             uint32_t method_idx,
                                             jobject class_loader,
                                             const DexFile& dex_file) const {
-  CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
-                                      method_idx, class_loader, dex_file);
-  if (method != nullptr) {
-    return method;
+  UNUSED(invoke_type);
+  compilation_stats_.RecordStat(MethodCompilationStat::kAttemptCompilation);
+  CompilerDriver* compiler_driver = GetCompilerDriver();
+  InstructionSet instruction_set = compiler_driver->GetInstructionSet();
+  // Always use the thumb2 assembler: some runtime functionality (like implicit stack
+  // overflow checks) assume thumb2.
+  if (instruction_set == kArm) {
+    instruction_set = kThumb2;
   }
 
-  return delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx,
-                            class_loader, dex_file);
+  // Do not attempt to compile on architectures we do not support.
+  if (!IsInstructionSetSupported(instruction_set)) {
+    compilation_stats_.RecordStat(MethodCompilationStat::kNotCompiledUnsupportedIsa);
+    return nullptr;
+  }
+
+  if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) {
+    compilation_stats_.RecordStat(MethodCompilationStat::kNotCompiledPathological);
+    return nullptr;
+  }
+
+  DexCompilationUnit dex_compilation_unit(
+    nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item,
+    class_def_idx, method_idx, access_flags,
+    compiler_driver->GetVerifiedMethod(&dex_file, method_idx));
+
+  std::string method_name = PrettyMethod(method_idx, dex_file);
+
+  // For testing purposes, we put a special marker on method names that should be compiled
+  // with this compiler. This makes sure we're not regressing.
+  bool shouldCompile = method_name.find("$opt$") != std::string::npos;
+  bool shouldOptimize = method_name.find("$opt$reg$") != std::string::npos;
+
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  HGraphBuilder builder(&arena,
+                        &dex_compilation_unit,
+                        &dex_compilation_unit,
+                        &dex_file,
+                        compiler_driver,
+                        &compilation_stats_);
+
+  VLOG(compiler) << "Building " << PrettyMethod(method_idx, dex_file);
+  HGraph* graph = builder.BuildGraph(*code_item);
+  if (graph == nullptr) {
+    CHECK(!shouldCompile) << "Could not build graph in optimizing compiler";
+    return nullptr;
+  }
+
+  std::unique_ptr<CodeGenerator> codegen(
+      CodeGenerator::Create(graph,
+                            instruction_set,
+                            *compiler_driver->GetInstructionSetFeatures(),
+                            compiler_driver->GetCompilerOptions()));
+  if (codegen.get() == nullptr) {
+    CHECK(!shouldCompile) << "Could not find code generator for optimizing compiler";
+    compilation_stats_.RecordStat(MethodCompilationStat::kNotCompiledNoCodegen);
+    return nullptr;
+  }
+
+  HGraphVisualizer visualizer(
+      visualizer_output_.get(), graph, kStringFilter, *codegen.get(), method_name.c_str());
+  visualizer.DumpGraph("builder");
+
+  bool can_optimize = CanOptimize(*code_item);
+  bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set);
+  CompiledMethod* result = nullptr;
+  if (run_optimizations_ && can_optimize && can_allocate_registers) {
+    VLOG(compiler) << "Optimizing " << PrettyMethod(method_idx, dex_file);
+    if (!graph->TryBuildingSsa()) {
+      LOG(INFO) << "Skipping compilation of "
+                << PrettyMethod(method_idx, dex_file)
+                << ": it contains a non natural loop";
+      // We could not transform the graph to SSA, bailout.
+      compilation_stats_.RecordStat(MethodCompilationStat::kNotCompiledCannotBuildSSA);
+    } else {
+      result = CompileOptimized(graph, codegen.get(), compiler_driver, dex_compilation_unit, visualizer);
+    }
+  } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
+    LOG(FATAL) << "Could not allocate registers in optimizing compiler";
+    UNREACHABLE();
+  } else {
+    VLOG(compiler) << "Compile baseline " << PrettyMethod(method_idx, dex_file);
+
+    if (!run_optimizations_) {
+      compilation_stats_.RecordStat(MethodCompilationStat::kNotOptimizedDisabled);
+    } else if (!can_optimize) {
+      compilation_stats_.RecordStat(MethodCompilationStat::kNotOptimizedTryCatch);
+    } else if (!can_allocate_registers) {
+      compilation_stats_.RecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator);
+    }
+
+    result = CompileBaseline(codegen.get(), compiler_driver, dex_compilation_unit);
+  }
+  return result;
 }
 
 Compiler* CreateOptimizingCompiler(CompilerDriver* driver) {
diff --git a/compiler/optimizing/optimizing_compiler.h b/compiler/optimizing/optimizing_compiler.h
index a415eca..d076fb5 100644
--- a/compiler/optimizing/optimizing_compiler.h
+++ b/compiler/optimizing/optimizing_compiler.h
@@ -24,6 +24,6 @@
 
 Compiler* CreateOptimizingCompiler(CompilerDriver* driver);
 
-}
+}  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_H_
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
new file mode 100644
index 0000000..cc2723d
--- /dev/null
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -0,0 +1,111 @@
+/*
+ * 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_OPTIMIZING_COMPILER_STATS_H_
+#define ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_
+
+#include <sstream>
+#include <string>
+
+#include "atomic.h"
+
+namespace art {
+
+enum MethodCompilationStat {
+  kAttemptCompilation = 0,
+  kCompiledBaseline,
+  kCompiledOptimized,
+  kInlinedInvoke,
+  kNotCompiledUnsupportedIsa,
+  kNotCompiledPathological,
+  kNotCompiledHugeMethod,
+  kNotCompiledLargeMethodNoBranches,
+  kNotCompiledCannotBuildSSA,
+  kNotCompiledNoCodegen,
+  kNotCompiledUnresolvedMethod,
+  kNotCompiledUnresolvedField,
+  kNotCompiledNonSequentialRegPair,
+  kNotOptimizedTryCatch,
+  kNotOptimizedDisabled,
+  kNotCompiledCantAccesType,
+  kNotOptimizedRegisterAllocator,
+  kNotCompiledUnhandledInstruction,
+  kLastStat
+};
+
+class OptimizingCompilerStats {
+ public:
+  OptimizingCompilerStats() {}
+
+  void RecordStat(MethodCompilationStat stat) {
+    compile_stats_[stat]++;
+  }
+
+  void Log() const {
+    if (compile_stats_[kAttemptCompilation] == 0) {
+      LOG(INFO) << "Did not compile any method.";
+    } else {
+      size_t unoptimized_percent =
+          compile_stats_[kCompiledBaseline] * 100 / compile_stats_[kAttemptCompilation];
+      size_t optimized_percent =
+          compile_stats_[kCompiledOptimized] * 100 / compile_stats_[kAttemptCompilation];
+      std::ostringstream oss;
+      oss << "Attempted compilation of " << compile_stats_[kAttemptCompilation] << " methods: "
+          << unoptimized_percent << "% (" << compile_stats_[kCompiledBaseline] << ") unoptimized, "
+          << optimized_percent << "% (" << compile_stats_[kCompiledOptimized] << ") optimized.";
+      for (int i = 0; i < kLastStat; i++) {
+        if (compile_stats_[i] != 0) {
+          oss << "\n" << PrintMethodCompilationStat(i) << ": " << compile_stats_[i];
+        }
+      }
+      LOG(INFO) << oss.str();
+    }
+  }
+
+ private:
+  std::string PrintMethodCompilationStat(int stat) const {
+    switch (stat) {
+      case kAttemptCompilation : return "kAttemptCompilation";
+      case kCompiledBaseline : return "kCompiledBaseline";
+      case kCompiledOptimized : return "kCompiledOptimized";
+      case kInlinedInvoke : return "kInlinedInvoke";
+      case kNotCompiledUnsupportedIsa : return "kNotCompiledUnsupportedIsa";
+      case kNotCompiledPathological : return "kNotCompiledPathological";
+      case kNotCompiledHugeMethod : return "kNotCompiledHugeMethod";
+      case kNotCompiledLargeMethodNoBranches : return "kNotCompiledLargeMethodNoBranches";
+      case kNotCompiledCannotBuildSSA : return "kNotCompiledCannotBuildSSA";
+      case kNotCompiledNoCodegen : return "kNotCompiledNoCodegen";
+      case kNotCompiledUnresolvedMethod : return "kNotCompiledUnresolvedMethod";
+      case kNotCompiledUnresolvedField : return "kNotCompiledUnresolvedField";
+      case kNotCompiledNonSequentialRegPair : return "kNotCompiledNonSequentialRegPair";
+      case kNotOptimizedDisabled : return "kNotOptimizedDisabled";
+      case kNotOptimizedTryCatch : return "kNotOptimizedTryCatch";
+      case kNotCompiledCantAccesType : return "kNotCompiledCantAccesType";
+      case kNotOptimizedRegisterAllocator : return "kNotOptimizedRegisterAllocator";
+      case kNotCompiledUnhandledInstruction : return "kNotCompiledUnhandledInstruction";
+      default: LOG(FATAL) << "invalid stat";
+    }
+    return "";
+  }
+
+  AtomicInteger compile_stats_[kLastStat];
+
+  DISALLOW_COPY_AND_ASSIGN(OptimizingCompilerStats);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_STATS_H_
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 6dd53e5..b3eb1e2 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -30,23 +30,27 @@
 #define NUM_INSTRUCTIONS(...)  \
   (sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t))
 
-#define ZERO_REGISTER_CODE_ITEM(...)                                       \
-    { 0, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
+#define N_REGISTERS_CODE_ITEM(NUM_REGS, ...)                            \
+    { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
 
-#define ONE_REGISTER_CODE_ITEM(...)                                        \
-    { 1, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
+#define ZERO_REGISTER_CODE_ITEM(...)   N_REGISTERS_CODE_ITEM(0, __VA_ARGS__)
+#define ONE_REGISTER_CODE_ITEM(...)    N_REGISTERS_CODE_ITEM(1, __VA_ARGS__)
+#define TWO_REGISTERS_CODE_ITEM(...)   N_REGISTERS_CODE_ITEM(2, __VA_ARGS__)
+#define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__)
+#define FOUR_REGISTERS_CODE_ITEM(...)  N_REGISTERS_CODE_ITEM(4, __VA_ARGS__)
+#define FIVE_REGISTERS_CODE_ITEM(...)  N_REGISTERS_CODE_ITEM(5, __VA_ARGS__)
+#define SIX_REGISTERS_CODE_ITEM(...)   N_REGISTERS_CODE_ITEM(6, __VA_ARGS__)
 
-#define TWO_REGISTERS_CODE_ITEM(...)                                       \
-    { 2, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
-
-#define THREE_REGISTERS_CODE_ITEM(...)                                     \
-    { 3, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
 
 LiveInterval* BuildInterval(const size_t ranges[][2],
                             size_t number_of_ranges,
                             ArenaAllocator* allocator,
-                            int reg = -1) {
-  LiveInterval* interval = new (allocator) LiveInterval(allocator, Primitive::kPrimInt);
+                            int reg = -1,
+                            HInstruction* defined_by = nullptr) {
+  LiveInterval* interval = LiveInterval::MakeInterval(allocator, Primitive::kPrimInt, defined_by);
+  if (defined_by != nullptr) {
+    defined_by->SetLiveInterval(interval);
+  }
   for (size_t i = number_of_ranges; i > 0; --i) {
     interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]);
   }
@@ -68,8 +72,10 @@
 }
 
 // Create a control-flow graph from Dex instructions.
-inline HGraph* CreateCFG(ArenaAllocator* allocator, const uint16_t* data) {
-  HGraphBuilder builder(allocator);
+inline HGraph* CreateCFG(ArenaAllocator* allocator,
+                         const uint16_t* data,
+                         Primitive::Type return_type = Primitive::kPrimInt) {
+  HGraphBuilder builder(allocator, return_type);
   const DexFile::CodeItem* item =
     reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
@@ -94,6 +100,11 @@
   return result;
 }
 
+// Returns if the instruction is removed from the graph.
+inline bool IsRemoved(HInstruction* instruction) {
+  return instruction->GetBlock() == nullptr;
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
diff --git a/compiler/optimizing/parallel_move_resolver.cc b/compiler/optimizing/parallel_move_resolver.cc
index cadd3c5..debe466 100644
--- a/compiler/optimizing/parallel_move_resolver.cc
+++ b/compiler/optimizing/parallel_move_resolver.cc
@@ -37,10 +37,12 @@
 
   // Perform the moves with constant sources.
   for (size_t i = 0; i < moves_.Size(); ++i) {
-    const MoveOperands& move = *moves_.Get(i);
-    if (!move.IsEliminated()) {
-      DCHECK(move.GetSource().IsConstant());
+    MoveOperands* move = moves_.Get(i);
+    if (!move->IsEliminated()) {
+      DCHECK(move->GetSource().IsConstant());
       EmitMove(i);
+      // Eliminate the move, in case following moves need a scratch register.
+      move->Eliminate();
     }
   }
 
@@ -55,6 +57,9 @@
   // unallocated, or the move was already eliminated).
   for (size_t i = 0; i < parallel_move->NumMoves(); ++i) {
     MoveOperands* move = parallel_move->MoveOperandsAt(i);
+    // The parallel move resolver algorithm does not work with register pairs.
+    DCHECK(!move->GetSource().IsPair());
+    DCHECK(!move->GetDestination().IsPair());
     if (!move->IsRedundant()) {
       moves_.Add(move);
     }
@@ -130,13 +135,13 @@
     // this move's source or destination needs to have their source
     // changed to reflect the state of affairs after the swap.
     Location source = move->GetSource();
-    Location destination = move->GetDestination();
+    Location swap_destination = move->GetDestination();
     move->Eliminate();
     for (size_t i = 0; i < moves_.Size(); ++i) {
       const MoveOperands& other_move = *moves_.Get(i);
       if (other_move.Blocks(source)) {
-        moves_.Get(i)->SetSource(destination);
-      } else if (other_move.Blocks(destination)) {
+        moves_.Get(i)->SetSource(swap_destination);
+      } else if (other_move.Blocks(swap_destination)) {
         moves_.Get(i)->SetSource(source);
       }
     }
@@ -170,8 +175,7 @@
   DCHECK_NE(blocked, if_scratch);
   int scratch = -1;
   for (int reg = 0; reg < register_count; ++reg) {
-    if ((blocked != reg) &&
-        IsScratchLocation(Location::RegisterLocation(ManagedRegister(reg)))) {
+    if ((blocked != reg) && IsScratchLocation(Location::RegisterLocation(reg))) {
       scratch = reg;
       break;
     }
diff --git a/compiler/optimizing/parallel_move_resolver.h b/compiler/optimizing/parallel_move_resolver.h
index fcc1de6..7ec1dd2 100644
--- a/compiler/optimizing/parallel_move_resolver.h
+++ b/compiler/optimizing/parallel_move_resolver.h
@@ -17,7 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_
 #define ART_COMPILER_OPTIMIZING_PARALLEL_MOVE_RESOLVER_H_
 
-#include "utils/allocation.h"
+#include "base/value_object.h"
 #include "utils/growable_array.h"
 
 namespace art {
@@ -58,6 +58,9 @@
   };
 
   bool IsScratchLocation(Location loc);
+
+  // Allocate a scratch register for performing a move. The method will try to use
+  // a register that is the destination of a move, but that move has not been emitted yet.
   int AllocateScratchRegister(int blocked, int if_scratch, int register_count, bool* spilled);
 
   // Emit a move.
diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc
index 863e107..28b5697 100644
--- a/compiler/optimizing/parallel_move_test.cc
+++ b/compiler/optimizing/parallel_move_test.cc
@@ -26,16 +26,26 @@
  public:
   explicit TestParallelMoveResolver(ArenaAllocator* allocator) : ParallelMoveResolver(allocator) {}
 
+  void Dump(Location location) {
+    if (location.IsConstant()) {
+      message_ << "C";
+    } else if (location.IsPair()) {
+      message_ << location.low() << "," << location.high();
+    } else {
+      message_ << location.reg();
+    }
+  }
+
   virtual void EmitMove(size_t index) {
     MoveOperands* move = moves_.Get(index);
     if (!message_.str().empty()) {
       message_ << " ";
     }
-    message_ << "("
-             << move->GetSource().reg().RegId()
-             << " -> "
-             << move->GetDestination().reg().RegId()
-             << ")";
+    message_ << "(";
+    Dump(move->GetSource());
+    message_ << " -> ";
+    Dump(move->GetDestination());
+    message_ << ")";
   }
 
   virtual void EmitSwap(size_t index) {
@@ -43,15 +53,15 @@
     if (!message_.str().empty()) {
       message_ << " ";
     }
-    message_ << "("
-             << move->GetSource().reg().RegId()
-             << " <-> "
-             << move->GetDestination().reg().RegId()
-             << ")";
+    message_ << "(";
+    Dump(move->GetSource());
+    message_ << " <-> ";
+    Dump(move->GetDestination());
+    message_ << ")";
   }
 
-  virtual void SpillScratch(int reg) {}
-  virtual void RestoreScratch(int reg) {}
+  virtual void SpillScratch(int reg ATTRIBUTE_UNUSED) {}
+  virtual void RestoreScratch(int reg ATTRIBUTE_UNUSED) {}
 
   std::string GetMessage() const {
     return  message_.str();
@@ -69,10 +79,10 @@
                                         size_t number_of_moves) {
   HParallelMove* moves = new (allocator) HParallelMove(allocator);
   for (size_t i = 0; i < number_of_moves; ++i) {
-    moves->AddMove(new (allocator) MoveOperands(
-        Location::RegisterLocation(ManagedRegister(operands[i][0])),
-        Location::RegisterLocation(ManagedRegister(operands[i][1])),
-        nullptr));
+    moves->AddMove(
+        Location::RegisterLocation(operands[i][0]),
+        Location::RegisterLocation(operands[i][1]),
+        nullptr);
   }
   return moves;
 }
@@ -116,16 +126,76 @@
 
   {
     TestParallelMoveResolver resolver(&allocator);
-    static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 1}};
+    static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}};
     resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
-    ASSERT_STREQ("(4 <-> 1) (3 <-> 4) (2 <-> 3) (0 -> 1)", resolver.GetMessage().c_str());
+    ASSERT_STREQ("(4 <-> 0) (3 <-> 4) (2 <-> 3) (1 <-> 2)", resolver.GetMessage().c_str());
+  }
+}
+
+TEST(ParallelMoveTest, ConstantLast) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  TestParallelMoveResolver resolver(&allocator);
+  HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
+  moves->AddMove(
+      Location::ConstantLocation(new (&allocator) HIntConstant(0)),
+      Location::RegisterLocation(0),
+      nullptr);
+  moves->AddMove(
+      Location::RegisterLocation(1),
+      Location::RegisterLocation(2),
+      nullptr);
+  resolver.EmitNativeCode(moves);
+  ASSERT_STREQ("(1 -> 2) (C -> 0)", resolver.GetMessage().c_str());
+}
+
+TEST(ParallelMoveTest, Pairs) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+
+  {
+    TestParallelMoveResolver resolver(&allocator);
+    HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
+    moves->AddMove(
+        Location::RegisterLocation(2),
+        Location::RegisterLocation(4),
+        nullptr);
+    moves->AddMove(
+        Location::RegisterPairLocation(0, 1),
+        Location::RegisterPairLocation(2, 3),
+        nullptr);
+    resolver.EmitNativeCode(moves);
+    ASSERT_STREQ("(2 -> 4) (0 -> 2) (1 -> 3)", resolver.GetMessage().c_str());
   }
 
   {
     TestParallelMoveResolver resolver(&allocator);
-    static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 1}, {5, 4}};
-    resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
-    ASSERT_STREQ("(4 <-> 1) (3 <-> 4) (2 <-> 3) (0 -> 1) (5 -> 4)", resolver.GetMessage().c_str());
+    HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
+    moves->AddMove(
+        Location::RegisterPairLocation(0, 1),
+        Location::RegisterPairLocation(2, 3),
+        nullptr);
+    moves->AddMove(
+        Location::RegisterLocation(2),
+        Location::RegisterLocation(4),
+        nullptr);
+    resolver.EmitNativeCode(moves);
+    ASSERT_STREQ("(2 -> 4) (0 -> 2) (1 -> 3)", resolver.GetMessage().c_str());
+  }
+
+  {
+    TestParallelMoveResolver resolver(&allocator);
+    HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
+    moves->AddMove(
+        Location::RegisterPairLocation(0, 1),
+        Location::RegisterPairLocation(2, 3),
+        nullptr);
+    moves->AddMove(
+        Location::RegisterLocation(2),
+        Location::RegisterLocation(0),
+        nullptr);
+    resolver.EmitNativeCode(moves);
+    ASSERT_STREQ("(2 <-> 0) (1 -> 3)", resolver.GetMessage().c_str());
   }
 }
 
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
new file mode 100644
index 0000000..7186dbe
--- /dev/null
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -0,0 +1,78 @@
+/*
+ * 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 "prepare_for_register_allocation.h"
+
+namespace art {
+
+void PrepareForRegisterAllocation::Run() {
+  // Order does not matter.
+  for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    // No need to visit the phis.
+    for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
+         inst_it.Advance()) {
+      inst_it.Current()->Accept(this);
+    }
+  }
+}
+
+void PrepareForRegisterAllocation::VisitNullCheck(HNullCheck* check) {
+  check->ReplaceWith(check->InputAt(0));
+}
+
+void PrepareForRegisterAllocation::VisitDivZeroCheck(HDivZeroCheck* check) {
+  check->ReplaceWith(check->InputAt(0));
+}
+
+void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) {
+  check->ReplaceWith(check->InputAt(0));
+}
+
+void PrepareForRegisterAllocation::VisitClinitCheck(HClinitCheck* check) {
+  HLoadClass* cls = check->GetLoadClass();
+  check->ReplaceWith(cls);
+  if (check->GetPrevious() == cls) {
+    // Pass the initialization duty to the `HLoadClass` instruction,
+    // and remove the instruction from the graph.
+    cls->SetMustGenerateClinitCheck();
+    check->GetBlock()->RemoveInstruction(check);
+  }
+}
+
+void PrepareForRegisterAllocation::VisitCondition(HCondition* condition) {
+  bool needs_materialization = false;
+  if (!condition->HasOnlyOneUse()) {
+    needs_materialization = true;
+  } else {
+    HUseListNode<HInstruction>* uses = condition->GetUses();
+    HInstruction* user = uses->GetUser();
+    if (!user->IsIf()) {
+      needs_materialization = true;
+    } else {
+      // TODO: if there is no intervening instructions with side-effect between this condition
+      // and the If instruction, we should move the condition just before the If.
+      if (condition->GetNext() != user) {
+        needs_materialization = true;
+      }
+    }
+  }
+  if (!needs_materialization) {
+    condition->ClearNeedsMaterialization();
+  }
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/prepare_for_register_allocation.h b/compiler/optimizing/prepare_for_register_allocation.h
new file mode 100644
index 0000000..0fdb65f
--- /dev/null
+++ b/compiler/optimizing/prepare_for_register_allocation.h
@@ -0,0 +1,47 @@
+/*
+ * 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_PREPARE_FOR_REGISTER_ALLOCATION_H_
+#define ART_COMPILER_OPTIMIZING_PREPARE_FOR_REGISTER_ALLOCATION_H_
+
+#include "nodes.h"
+
+namespace art {
+
+/**
+ * A simplification pass over the graph before doing register allocation.
+ * For example it changes uses of null checks and bounds checks to the original
+ * objects, to avoid creating a live range for these checks.
+ */
+class PrepareForRegisterAllocation : public HGraphDelegateVisitor {
+ public:
+  explicit PrepareForRegisterAllocation(HGraph* graph) : HGraphDelegateVisitor(graph) {}
+
+  void Run();
+
+ private:
+  virtual void VisitNullCheck(HNullCheck* check) OVERRIDE;
+  virtual void VisitDivZeroCheck(HDivZeroCheck* check) OVERRIDE;
+  virtual void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE;
+  virtual void VisitClinitCheck(HClinitCheck* check) OVERRIDE;
+  virtual void VisitCondition(HCondition* condition) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(PrepareForRegisterAllocation);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_PREPARE_FOR_REGISTER_ALLOCATION_H_
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 1d1d694..e120bc6 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"
@@ -25,6 +27,12 @@
 static constexpr size_t kMaxLifetimePosition = -1;
 static constexpr size_t kDefaultNumberOfSpillSlots = 4;
 
+// For simplicity, we implement register pairs as (reg, reg + 1).
+// Note that this is a requirement for double registers on ARM, since we
+// allocate SRegister.
+static int GetHighForLowRegister(int reg) { return reg + 1; }
+static bool IsLowRegister(int reg) { return (reg & 1) == 0; }
+
 RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
                                      CodeGenerator* codegen,
                                      const SsaLivenessAnalysis& liveness)
@@ -37,18 +45,22 @@
         handled_(allocator, 0),
         active_(allocator, 0),
         inactive_(allocator, 0),
-        physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
+        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_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())),
+        blocked_core_registers_(codegen->GetBlockedCoreRegisters()),
+        blocked_fp_registers_(codegen->GetBlockedFloatingPointRegisters()),
         reserved_out_slots_(0),
-        maximum_number_of_live_registers_(0) {
-  codegen->SetupBlockedRegisters(blocked_registers_);
-  physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
+        maximum_number_of_live_core_registers_(0),
+        maximum_number_of_live_fp_registers_(0) {
+  codegen->SetupBlockedRegisters();
+  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();
@@ -59,14 +71,24 @@
   if (!Supports(instruction_set)) {
     return false;
   }
+  if (instruction_set == kArm64
+      || instruction_set == kX86_64
+      || instruction_set == kArm
+      || instruction_set == kThumb2) {
+    return true;
+  }
   for (size_t i = 0, e = graph.GetBlocks().Size(); i < e; ++i) {
     for (HInstructionIterator it(graph.GetBlocks().Get(i)->GetInstructions());
          !it.Done();
          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 (instruction_set == kX86) {
+        if (current->GetType() == Primitive::kPrimLong ||
+            current->GetType() == Primitive::kPrimFloat ||
+            current->GetType() == Primitive::kPrimDouble) {
+          return false;
+        }
+      }
     }
   }
   return true;
@@ -88,19 +110,46 @@
     ValidateInternal(true);
     processing_core_registers_ = false;
     ValidateInternal(true);
+    // Check that the linear order is still correct with regards to lifetime positions.
+    // Since only parallel moves have been inserted during the register allocation,
+    // these checks are mostly for making sure these moves have been added correctly.
+    size_t current_liveness = 0;
+    for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
+      HBasicBlock* block = it.Current();
+      for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+        HInstruction* instruction = inst_it.Current();
+        DCHECK_LE(current_liveness, instruction->GetLifetimePosition());
+        current_liveness = instruction->GetLifetimePosition();
+      }
+      for (HInstructionIterator inst_it(block->GetInstructions());
+           !inst_it.Done();
+           inst_it.Advance()) {
+        HInstruction* instruction = inst_it.Current();
+        DCHECK_LE(current_liveness, instruction->GetLifetimePosition()) << instruction->DebugName();
+        current_liveness = instruction->GetLifetimePosition();
+      }
+    }
   }
 }
 
 void RegisterAllocator::BlockRegister(Location location,
                                       size_t start,
-                                      size_t end,
-                                      Primitive::Type type) {
-  int reg = location.reg().RegId();
-  LiveInterval* interval = physical_register_intervals_.Get(reg);
+                                      size_t end) {
+  int reg = location.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::kPrimFloat;
   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);
@@ -111,11 +160,12 @@
   // is the one with the lowest start position.
   for (HLinearPostOrderIterator it(liveness_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
-    for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-      ProcessInstruction(it.Current());
+    for (HBackwardInstructionIterator back_it(block->GetInstructions()); !back_it.Done();
+         back_it.Advance()) {
+      ProcessInstruction(back_it.Current());
     }
-    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-      ProcessInstruction(it.Current());
+    for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+      ProcessInstruction(inst_it.Current());
     }
   }
 
@@ -123,6 +173,16 @@
   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) {
+      // Fixed interval is added to inactive_ instead of unhandled_.
+      // It's also the only type of inactive interval whose start position
+      // can be after the current interval during linear scan.
+      // Fixed interval is never split and never moves to unhandled_.
+      inactive_.Add(fixed);
+    }
+  }
   LinearScan();
 
   inactive_.Reset();
@@ -133,8 +193,16 @@
   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) {
+      // Fixed interval is added to inactive_ instead of unhandled_.
+      // It's also the only type of inactive interval whose start position
+      // can be after the current interval during linear scan.
+      // Fixed interval is never split and never moves to unhandled_.
+      inactive_.Add(fixed);
+    }
+  }
   LinearScan();
 }
 
@@ -147,24 +215,45 @@
   // Create synthesized intervals for temporaries.
   for (size_t i = 0; i < locations->GetTempCount(); ++i) {
     Location temp = locations->GetTemp(i);
-    if (temp.IsRegister()) {
-      BlockRegister(temp, position, position + 1, Primitive::kPrimInt);
+    if (temp.IsRegister() || temp.IsFpuRegister()) {
+      BlockRegister(temp, position, position + 1);
     } else {
-      LiveInterval* interval =
-          LiveInterval::MakeTempInterval(allocator_, instruction, Primitive::kPrimInt);
-      temp_intervals_.Add(interval);
-      interval->AddRange(position, position + 1);
-      unhandled_core_intervals_.Add(interval);
+      DCHECK(temp.IsUnallocated());
+      switch (temp.GetPolicy()) {
+        case Location::kRequiresRegister: {
+          LiveInterval* interval =
+              LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
+          temp_intervals_.Add(interval);
+          interval->AddRange(position, position + 1);
+          unhandled_core_intervals_.Add(interval);
+          break;
+        }
+
+        case Location::kRequiresFpuRegister: {
+          LiveInterval* interval =
+              LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
+          temp_intervals_.Add(interval);
+          interval->AddRange(position, position + 1);
+          if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
+            interval->AddHighInterval(true);
+            LiveInterval* high = interval->GetHighInterval();
+            temp_intervals_.Add(high);
+            unhandled_fp_intervals_.Add(high);
+          }
+          unhandled_fp_intervals_.Add(interval);
+          break;
+        }
+
+        default:
+          LOG(FATAL) << "Unexpected policy for temporary location "
+                     << temp.GetPolicy();
+      }
     }
   }
 
   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();
@@ -181,31 +270,48 @@
       // maximum before updating locations.
       LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
       interval->AddRange(position, position + 1);
-      unhandled.Add(interval);
+      AddSorted(&unhandled_core_intervals_, interval);
+      AddSorted(&unhandled_fp_intervals_, interval);
     }
   }
 
   if (locations->WillCall()) {
     // Block all registers.
     for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
-      BlockRegister(Location::RegisterLocation(ManagedRegister(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);
+    } else if (input.IsPair()) {
+      BlockRegister(input.ToLow(), position, position + 1);
+      BlockRegister(input.ToHigh(), 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()));
+
+  if (codegen_->NeedsTwoRegisters(current->GetType())) {
+    current->AddHighInterval();
+  }
+
   // Some instructions define their output in fixed register/stack slot. We need
   // to ensure we know these locations before doing register allocation. For a
   // given register, we create an interval that covers these locations. The register
@@ -214,30 +320,54 @@
   //
   // The backwards walking ensures the ranges are ordered on increasing start positions.
   Location output = locations->Out();
-  if (output.IsRegister()) {
+  if (output.IsUnallocated() && output.GetPolicy() == Location::kSameAsFirstInput) {
+    Location first = locations->InAt(0);
+    if (first.IsRegister() || first.IsFpuRegister()) {
+      current->SetFrom(position + 1);
+      current->SetRegister(first.reg());
+    } else if (first.IsPair()) {
+      current->SetFrom(position + 1);
+      current->SetRegister(first.low());
+      LiveInterval* high = current->GetHighInterval();
+      high->SetRegister(first.high());
+      high->SetFrom(position + 1);
+    }
+  } else 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().RegId());
-    BlockRegister(output, position, position + 1, instruction->GetType());
+    current->SetRegister(output.reg());
+    BlockRegister(output, position, position + 1);
+  } else if (output.IsPair()) {
+    current->SetFrom(position + 1);
+    current->SetRegister(output.low());
+    LiveInterval* high = current->GetHighInterval();
+    high->SetRegister(output.high());
+    high->SetFrom(position + 1);
+    BlockRegister(output.ToLow(), position, position + 1);
+    BlockRegister(output.ToHigh(), position, position + 1);
   } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
     current->SetSpillSlot(output.GetStackIndex());
+  } else {
+    DCHECK(output.IsUnallocated() || output.IsConstant());
   }
 
   // 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);
-      // Don't add direclty to `unhandled`, it needs to be sorted and the start
+      LiveInterval* split = Split(current, first_register_use - 1);
+      // Don't add directly 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);
     } else {
       // Nothing to do, we won't allocate a register for this value.
     }
   } else {
-    DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
-    unhandled.Add(current);
+    // Don't add directly to `unhandled`, temp or safepoint intervals
+    // for this instruction may have been added, and those can be
+    // processed first.
+    AddSorted(&unhandled, current);
   }
 }
 
@@ -279,10 +409,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);
+      }
     }
   }
 
@@ -375,10 +514,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";
@@ -386,14 +525,42 @@
   stream << std::endl;
 }
 
+void RegisterAllocator::DumpAllIntervals(std::ostream& stream) const {
+  stream << "inactive: " << std::endl;
+  for (size_t i = 0; i < inactive_.Size(); i ++) {
+    DumpInterval(stream, inactive_.Get(i));
+  }
+  stream << "active: " << std::endl;
+  for (size_t i = 0; i < active_.Size(); i ++) {
+    DumpInterval(stream, active_.Get(i));
+  }
+  stream << "unhandled: " << std::endl;
+  auto unhandled = (unhandled_ != nullptr) ?
+      unhandled_ : &unhandled_core_intervals_;
+  for (size_t i = 0; i < unhandled->Size(); i ++) {
+    DumpInterval(stream, unhandled->Get(i));
+  }
+  stream << "handled: " << std::endl;
+  for (size_t i = 0; i < handled_.Size(); i ++) {
+    DumpInterval(stream, handled_.Get(i));
+  }
+}
+
 // By the book implementation of a linear scan register allocator.
 void RegisterAllocator::LinearScan() {
   while (!unhandled_->IsEmpty()) {
     // (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());
+    DCHECK(!current->IsLowInterval() || unhandled_->Peek()->IsHighInterval());
+
     size_t position = current->GetStart();
 
+    // Remember the inactive_ size here since the ones moved to inactive_ from
+    // active_ below shouldn't need to be re-checked.
+    size_t inactive_intervals_to_handle = inactive_.Size();
+
     // (2) Remove currently active intervals that are dead at this position.
     //     Move active intervals that have a lifetime hole at this position
     //     to inactive.
@@ -412,15 +579,18 @@
 
     // (3) Remove currently inactive intervals that are dead at this position.
     //     Move inactive intervals that cover this position to active.
-    for (size_t i = 0; i < inactive_.Size(); ++i) {
+    for (size_t i = 0; i < inactive_intervals_to_handle; ++i) {
       LiveInterval* interval = inactive_.Get(i);
+      DCHECK(interval->GetStart() < position || interval->IsFixed());
       if (interval->IsDeadAt(position)) {
         inactive_.Delete(interval);
         --i;
+        --inactive_intervals_to_handle;
         handled_.Add(interval);
       } else if (interval->Covers(position)) {
         inactive_.Delete(interval);
         --i;
+        --inactive_intervals_to_handle;
         active_.Add(interval);
       }
     }
@@ -428,8 +598,21 @@
     if (current->IsSlowPathSafepoint()) {
       // Synthesized interval to record the maximum number of live registers
       // at safepoints. No need to allocate a register for it.
-      maximum_number_of_live_registers_ =
-          std::max(maximum_number_of_live_registers_, active_.Size());
+      if (processing_core_registers_) {
+        maximum_number_of_live_core_registers_ =
+          std::max(maximum_number_of_live_core_registers_, active_.Size());
+      } else {
+        maximum_number_of_live_fp_registers_ =
+          std::max(maximum_number_of_live_fp_registers_, active_.Size());
+      }
+      DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() > current->GetStart());
+      continue;
+    }
+
+    if (current->IsHighInterval() && !current->GetLowInterval()->HasRegister()) {
+      DCHECK(!current->HasRegister());
+      // Allocating the low part was unsucessful. The splitted interval for the high part
+      // will be handled next (it is in the `unhandled_` list).
       continue;
     }
 
@@ -445,6 +628,9 @@
     //     intervals.
     if (success) {
       active_.Add(current);
+      if (current->HasHighInterval() && !current->GetHighInterval()->HasRegister()) {
+        current->GetHighInterval()->SetRegister(GetHighForLowRegister(current->GetRegister()));
+      }
     }
   }
 }
@@ -459,20 +645,6 @@
     free_until[i] = kMaxLifetimePosition;
   }
 
-  // For each inactive interval, set its register to be free until
-  // the next intersection with `current`.
-  // Thanks to SSA, this should only be needed for intervals
-  // that are the result of a split.
-  for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
-    LiveInterval* inactive = inactive_.Get(i);
-    DCHECK(inactive->HasRegister());
-    size_t next_intersection = inactive->FirstIntersectionWith(current);
-    if (next_intersection != kNoLifetime) {
-      free_until[inactive->GetRegister()] =
-          std::min(free_until[inactive->GetRegister()], next_intersection);
-    }
-  }
-
   // For each active interval, set its register to not free.
   for (size_t i = 0, e = active_.Size(); i < e; ++i) {
     LiveInterval* interval = active_.Get(i);
@@ -480,24 +652,62 @@
     free_until[interval->GetRegister()] = 0;
   }
 
-  int reg = -1;
-  if (current->HasRegister()) {
-    // Some instructions have a fixed register output.
-    reg = current->GetRegister();
-    DCHECK_NE(free_until[reg], 0u);
-  } else {
-    // Pick the register that is free the longest.
-    for (size_t i = 0; i < number_of_registers_; ++i) {
-      if (IsBlocked(i)) continue;
-      if (reg == -1 || free_until[i] > free_until[reg]) {
-        reg = i;
-        if (free_until[i] == kMaxLifetimePosition) break;
-      }
+  // For each inactive interval, set its register to be free until
+  // the next intersection with `current`.
+  for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
+    LiveInterval* inactive = inactive_.Get(i);
+    // Temp/Slow-path-safepoint interval has no holes.
+    DCHECK(!inactive->IsTemp() && !inactive->IsSlowPathSafepoint());
+    if (!current->IsSplit() && !inactive->IsFixed()) {
+      // Neither current nor inactive are fixed.
+      // Thanks to SSA, a non-split interval starting in a hole of an
+      // inactive interval should never intersect with that inactive interval.
+      // Only if it's not fixed though, because fixed intervals don't come from SSA.
+      DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
+      continue;
+    }
+
+    DCHECK(inactive->HasRegister());
+    if (free_until[inactive->GetRegister()] == 0) {
+      // Already used by some active interval. No need to intersect.
+      continue;
+    }
+    size_t next_intersection = inactive->FirstIntersectionWith(current);
+    if (next_intersection != kNoLifetime) {
+      free_until[inactive->GetRegister()] =
+          std::min(free_until[inactive->GetRegister()], next_intersection);
     }
   }
 
+  int reg = kNoRegister;
+  if (current->HasRegister()) {
+    // Some instructions have a fixed register output.
+    reg = current->GetRegister();
+    if (free_until[reg] == 0) {
+      DCHECK(current->IsHighInterval());
+      // AllocateBlockedReg will spill the holder of the register.
+      return false;
+    }
+  } else {
+    DCHECK(!current->IsHighInterval());
+    int hint = current->FindFirstRegisterHint(free_until);
+    if (hint != kNoRegister) {
+      DCHECK(!IsBlocked(hint));
+      reg = hint;
+    } else if (current->IsLowInterval()) {
+      reg = FindAvailableRegisterPair(free_until, current->GetStart());
+    } else {
+      reg = FindAvailableRegister(free_until);
+    }
+  }
+
+  DCHECK_NE(reg, kNoRegister);
   // If we could not find a register, we need to spill.
-  if (reg == -1 || free_until[reg] == 0) {
+  if (free_until[reg] == 0) {
+    return false;
+  }
+
+  if (current->IsLowInterval() && free_until[GetHighForLowRegister(reg)] == 0) {
     return false;
   }
 
@@ -514,10 +724,69 @@
 }
 
 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];
+}
+
+int RegisterAllocator::FindAvailableRegisterPair(size_t* next_use, size_t starting_at) const {
+  int reg = kNoRegister;
+  // Pick the register pair that is used the last.
+  for (size_t i = 0; i < number_of_registers_; ++i) {
+    if (IsBlocked(i)) continue;
+    if (!IsLowRegister(i)) continue;
+    int high_register = GetHighForLowRegister(i);
+    if (IsBlocked(high_register)) continue;
+    int existing_high_register = GetHighForLowRegister(reg);
+    if ((reg == kNoRegister) || (next_use[i] >= next_use[reg]
+                        && next_use[high_register] >= next_use[existing_high_register])) {
+      reg = i;
+      if (next_use[i] == kMaxLifetimePosition
+          && next_use[high_register] == kMaxLifetimePosition) {
+        break;
+      }
+    } else if (next_use[reg] <= starting_at || next_use[existing_high_register] <= starting_at) {
+      // If one of the current register is known to be unavailable, just unconditionally
+      // try a new one.
+      reg = i;
+    }
+  }
+  return reg;
+}
+
+int RegisterAllocator::FindAvailableRegister(size_t* next_use) const {
+  int reg = kNoRegister;
+  // Pick the register that is used the last.
+  for (size_t i = 0; i < number_of_registers_; ++i) {
+    if (IsBlocked(i)) continue;
+    if (reg == kNoRegister || next_use[i] > next_use[reg]) {
+      reg = i;
+      if (next_use[i] == kMaxLifetimePosition) break;
+    }
+  }
+  return reg;
+}
+
+bool RegisterAllocator::TrySplitNonPairIntervalAt(size_t position,
+                                                  size_t first_register_use,
+                                                  size_t* next_use) {
+  for (size_t i = 0, e = active_.Size(); i < e; ++i) {
+    LiveInterval* active = active_.Get(i);
+    DCHECK(active->HasRegister());
+    // Split the first interval found.
+    if (first_register_use <= next_use[active->GetRegister()]
+        && !active->IsLowInterval()
+        && !active->IsHighInterval()) {
+      LiveInterval* split = Split(active, position);
+      active_.DeleteAt(i);
+      if (split != active) {
+        handled_.Add(active);
+      }
+      AddSorted(unhandled_, split);
+      return true;
+    }
+  }
+  return false;
 }
 
 // Find the register that is used the last, and spill the interval
@@ -553,10 +822,18 @@
 
   // For each inactive interval, find the next use of its register after the
   // start of current.
-  // Thanks to SSA, this should only be needed for intervals
-  // that are the result of a split.
   for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
     LiveInterval* inactive = inactive_.Get(i);
+    // Temp/Slow-path-safepoint interval has no holes.
+    DCHECK(!inactive->IsTemp() && !inactive->IsSlowPathSafepoint());
+    if (!current->IsSplit() && !inactive->IsFixed()) {
+      // Neither current nor inactive are fixed.
+      // Thanks to SSA, a non-split interval starting in a hole of an
+      // inactive interval should never intersect with that inactive interval.
+      // Only if it's not fixed though, because fixed intervals don't come from SSA.
+      DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
+      continue;
+    }
     DCHECK(inactive->HasRegister());
     size_t next_intersection = inactive->FirstIntersectionWith(current);
     if (next_intersection != kNoLifetime) {
@@ -572,22 +849,50 @@
     }
   }
 
-  // Pick the register that is used the last.
-  int reg = -1;
-  for (size_t i = 0; i < number_of_registers_; ++i) {
-    if (IsBlocked(i)) continue;
-    if (reg == -1 || next_use[i] > next_use[reg]) {
-      reg = i;
-      if (next_use[i] == kMaxLifetimePosition) break;
-    }
+  int reg = kNoRegister;
+  bool should_spill = false;
+  if (current->HasRegister()) {
+    DCHECK(current->IsHighInterval());
+    reg = current->GetRegister();
+    // When allocating the low part, we made sure the high register was available.
+    DCHECK_LT(first_register_use, next_use[reg]);
+  } else if (current->IsLowInterval()) {
+    reg = FindAvailableRegisterPair(next_use, current->GetStart());
+    // We should spill if both registers are not available.
+    should_spill = (first_register_use >= next_use[reg])
+      || (first_register_use >= next_use[GetHighForLowRegister(reg)]);
+  } else {
+    DCHECK(!current->IsHighInterval());
+    reg = FindAvailableRegister(next_use);
+    should_spill = (first_register_use >= next_use[reg]);
   }
 
-  if (first_register_use >= next_use[reg]) {
-    // 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);
-    AddSorted(unhandled_, split);
+  DCHECK_NE(reg, kNoRegister);
+  if (should_spill) {
+    DCHECK(!current->IsHighInterval());
+    bool is_allocation_at_use_site = (current->GetStart() == (first_register_use - 1));
+    if (current->IsLowInterval()
+        && is_allocation_at_use_site
+        && TrySplitNonPairIntervalAt(current->GetStart(), first_register_use, next_use)) {
+      // If we're allocating a register for `current` because the instruction at
+      // that position requires it, but we think we should spill, then there are
+      // non-pair intervals blocking the allocation. We split the first
+      // interval found, and put ourselves first in the `unhandled_` list.
+      LiveInterval* existing = unhandled_->Peek();
+      DCHECK(existing->IsHighInterval());
+      DCHECK_EQ(existing->GetLowInterval(), current);
+      unhandled_->Add(current);
+    } else {
+      // 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 - 1);
+      DCHECK_NE(current, split) << "There is not enough registers available for "
+        << split->GetParent()->GetDefinedBy()->DebugName() << " "
+        << split->GetParent()->GetDefinedBy()->GetId()
+        << " at " << first_register_use - 1;
+      AddSorted(unhandled_, split);
+    }
     return false;
   } else {
     // Use this register and spill the active and inactives interval that
@@ -600,26 +905,78 @@
         DCHECK(!active->IsFixed());
         LiveInterval* split = Split(active, current->GetStart());
         active_.DeleteAt(i);
-        handled_.Add(active);
+        if (split != active) {
+          handled_.Add(active);
+        }
         AddSorted(unhandled_, split);
+
+        if (active->IsLowInterval() || active->IsHighInterval()) {
+          LiveInterval* other_half = active->IsLowInterval()
+              ? active->GetHighInterval()
+              : active->GetLowInterval();
+          // We also need to remove the other half from the list of actives.
+          bool found = false;
+          for (size_t j = 0; j < active_.Size(); ++j) {
+            if (active_.Get(j) == other_half) {
+              found = true;
+              active_.DeleteAt(j);
+              handled_.Add(other_half);
+              break;
+            }
+          }
+          DCHECK(found);
+        }
         break;
       }
     }
 
-    for (size_t i = 0; i < inactive_.Size(); ++i) {
+    for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
       LiveInterval* inactive = inactive_.Get(i);
       if (inactive->GetRegister() == reg) {
+        if (!current->IsSplit() && !inactive->IsFixed()) {
+          // Neither current nor inactive are fixed.
+          // Thanks to SSA, a non-split interval starting in a hole of an
+          // inactive interval should never intersect with that inactive interval.
+          // Only if it's not fixed though, because fixed intervals don't come from SSA.
+          DCHECK_EQ(inactive->FirstIntersectionWith(current), kNoLifetime);
+          continue;
+        }
         size_t next_intersection = inactive->FirstIntersectionWith(current);
         if (next_intersection != kNoLifetime) {
           if (inactive->IsFixed()) {
             LiveInterval* split = Split(current, next_intersection);
+            DCHECK_NE(split, current);
             AddSorted(unhandled_, split);
           } else {
+            // Split at the start of `current`, which will lead to splitting
+            // at the end of the lifetime hole of `inactive`.
             LiveInterval* split = Split(inactive, current->GetStart());
+            // If it's inactive, it must start before the current interval.
+            DCHECK_NE(split, inactive);
             inactive_.DeleteAt(i);
+            --i;
+            --e;
             handled_.Add(inactive);
             AddSorted(unhandled_, split);
-            --i;
+
+            if (inactive->IsLowInterval() || inactive->IsHighInterval()) {
+              LiveInterval* other_half = inactive->IsLowInterval()
+                  ? inactive->GetHighInterval()
+                  : inactive->GetLowInterval();
+
+              // We also need to remove the other half from the list of inactives.
+              bool found = false;
+              for (size_t j = 0; j < inactive_.Size(); ++j) {
+                if (inactive_.Get(j) == other_half) {
+                  found = true;
+                  inactive_.DeleteAt(j);
+                  --e;
+                  handled_.Add(other_half);
+                  break;
+                }
+              }
+              DCHECK(found);
+            }
           }
         }
       }
@@ -630,35 +987,65 @@
 }
 
 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);
-    if (current->StartsAfter(interval)) {
+    // High intervals must be processed right after their low equivalent.
+    if (current->StartsAfter(interval) && !current->IsHighInterval()) {
+      insert_at = i;
+      break;
+    } else if ((current->GetStart() == interval->GetStart()) && current->IsSlowPathSafepoint()) {
+      // Ensure the slow path interval is the last to be processed at its location: we want the
+      // interval to know all live registers at this location.
+      DCHECK(i == 1 || array->Get(i - 2)->StartsAfter(current));
       insert_at = i;
       break;
     }
   }
+
   array->InsertAt(insert_at, interval);
+  // Insert the high interval before the low, to ensure the low is processed before.
+  if (interval->HasHighInterval()) {
+    array->InsertAt(insert_at, interval->GetHighInterval());
+  } else if (interval->HasLowInterval()) {
+    array->InsertAt(insert_at + 1, interval->GetLowInterval());
+  }
 }
 
 LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
-  DCHECK(position >= interval->GetStart());
+  DCHECK_GE(position, interval->GetStart());
   DCHECK(!interval->IsDeadAt(position));
   if (position == interval->GetStart()) {
     // Spill slot will be allocated when handling `interval` again.
     interval->ClearRegister();
+    if (interval->HasHighInterval()) {
+      interval->GetHighInterval()->ClearRegister();
+    } else if (interval->HasLowInterval()) {
+      interval->GetLowInterval()->ClearRegister();
+    }
     return interval;
   } else {
     LiveInterval* new_interval = interval->SplitAt(position);
+    if (interval->HasHighInterval()) {
+      LiveInterval* high = interval->GetHighInterval()->SplitAt(position);
+      new_interval->SetHighInterval(high);
+      high->SetLowInterval(new_interval);
+    } else if (interval->HasLowInterval()) {
+      LiveInterval* low = interval->GetLowInterval()->SplitAt(position);
+      new_interval->SetLowInterval(low);
+      low->SetHighInterval(new_interval);
+    }
     return new_interval;
   }
 }
 
-static bool NeedTwoSpillSlot(Primitive::Type type) {
-  return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
-}
-
 void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) {
+  if (interval->IsHighInterval()) {
+    // The low interval will contain the spill slot.
+    return;
+  }
+
   LiveInterval* parent = interval->GetParent();
 
   // An instruction gets a spill slot for its entire lifetime. If the parent
@@ -698,7 +1085,7 @@
     }
   }
 
-  if (NeedTwoSpillSlot(parent->GetType())) {
+  if (parent->NeedsTwoSpillSlots()) {
     if (slot == spill_slots_.Size()) {
       // We need a new spill slot.
       spill_slots_.Add(end);
@@ -722,80 +1109,82 @@
   parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
 }
 
-static Location ConvertToLocation(LiveInterval* interval) {
-  if (interval->HasRegister()) {
-    return Location::RegisterLocation(ManagedRegister(interval->GetRegister()));
-  } else {
-    HInstruction* defined_by = interval->GetParent()->GetDefinedBy();
-    if (defined_by->IsConstant()) {
-      return defined_by->GetLocations()->Out();
-    } else {
-      DCHECK(interval->GetParent()->HasSpillSlot());
-      if (NeedTwoSpillSlot(interval->GetType())) {
-        return Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot());
-      } else {
-        return Location::StackSlot(interval->GetParent()->GetSpillSlot());
-      }
-    }
-  }
-}
-
-// 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.IsRegisterPair()
+      || destination.IsFpuRegister()
+      || destination.IsFpuRegisterPair()
+      || destination.IsStackSlot()
+      || destination.IsDoubleStackSlot();
 }
 
 void RegisterAllocator::AddInputMoveFor(HInstruction* user,
                                         Location source,
                                         Location destination) const {
-  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));
-  move->AddMove(new (allocator_) MoveOperands(source, destination, nullptr));
+  DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition());
+  move->AddMove(source, destination, nullptr);
+}
+
+static bool IsInstructionStart(size_t position) {
+  return (position & 1) == 0;
+}
+
+static bool IsInstructionEnd(size_t position) {
+  return (position & 1) == 1;
 }
 
 void RegisterAllocator::InsertParallelMoveAt(size_t position,
                                              HInstruction* instruction,
                                              Location source,
                                              Location destination) const {
-  DCHECK(IsValidDestination(destination));
+  DCHECK(IsValidDestination(destination)) << destination;
   if (source.Equals(destination)) return;
 
   HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
-  if (at == nullptr) {
-    // Block boundary, don't no anything the connection of split siblings will handle it.
-    return;
-  }
   HParallelMove* move;
-  if ((position & 1) == 1) {
+  if (at == nullptr) {
+    if (IsInstructionStart(position)) {
+      // Block boundary, don't do anything the connection of split siblings will handle it.
+      return;
+    } else {
+      // Move must happen before the first instruction of the block.
+      at = liveness_.GetInstructionFromPosition((position + 1) / 2);
+      // Note that parallel moves may have already been inserted, so we explicitly
+      // ask for the first instruction of the block: `GetInstructionFromPosition` does
+      // not contain the moves.
+      at = at->GetBlock()->GetFirstInstruction();
+      if (at->GetLifetimePosition() != position) {
+        DCHECK_GT(at->GetLifetimePosition(), position);
+        move = new (allocator_) HParallelMove(allocator_);
+        move->SetLifetimePosition(position);
+        at->GetBlock()->InsertInstructionBefore(move, at);
+      } else {
+        DCHECK(at->IsParallelMove());
+        move = at->AsParallelMove();
+      }
+    }
+  } else if (IsInstructionEnd(position)) {
     // Move must happen after the instruction.
     DCHECK(!at->IsControlFlow());
     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 || move->GetLifetimePosition() != position) {
+    if (move == nullptr || move->GetLifetimePosition() > position) {
       move = new (allocator_) HParallelMove(allocator_);
       move->SetLifetimePosition(position);
       at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
@@ -803,17 +1192,6 @@
   } else {
     // Move must happen before the instruction.
     HInstruction* previous = at->GetPrevious();
-    if (previous != nullptr && previous->IsParallelMove()) {
-      // 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 (previous->GetLifetimePosition() != position) {
-        // If the previous instruction of the previous instruction is not a parallel
-        // move, we have to insert the new parallel move before the input or connecting
-        // block moves.
-        at = previous;
-        previous = previous->GetPrevious();
-      }
-    }
     if (previous == nullptr
         || !previous->IsParallelMove()
         || previous->GetLifetimePosition() != position) {
@@ -830,38 +1208,45 @@
       move = previous->AsParallelMove();
     }
   }
-  move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
+  DCHECK_EQ(move->GetLifetimePosition(), position);
+  move->AddMove(source, destination, instruction);
 }
 
 void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
                                                    HInstruction* instruction,
                                                    Location source,
                                                    Location destination) const {
-  DCHECK(IsValidDestination(destination));
+  DCHECK(IsValidDestination(destination)) << destination;
   if (source.Equals(destination)) return;
 
   DCHECK_EQ(block->GetSuccessors().Size(), 1u);
   HInstruction* last = block->GetLastInstruction();
+  // We insert moves at exit for phi predecessors and connecting blocks.
+  // A block ending with an if cannot branch to a block with phis because
+  // we do not allow critical edges. It can also not connect
+  // a split interval between two blocks: the move has to happen in the successor.
+  DCHECK(!last->IsIf());
   HInstruction* previous = last->GetPrevious();
   HParallelMove* move;
   // This is a parallel move for connecting blocks. We need to differentiate
   // it with moves for connecting siblings in a same block, and output moves.
+  size_t position = last->GetLifetimePosition();
   if (previous == nullptr || !previous->IsParallelMove()
-      || previous->AsParallelMove()->GetLifetimePosition() != block->GetLifetimeEnd()) {
+      || previous->AsParallelMove()->GetLifetimePosition() != position) {
     move = new (allocator_) HParallelMove(allocator_);
-    move->SetLifetimePosition(block->GetLifetimeEnd());
+    move->SetLifetimePosition(position);
     block->InsertInstructionBefore(move, last);
   } else {
     move = previous->AsParallelMove();
   }
-  move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
+  move->AddMove(source, destination, instruction);
 }
 
 void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
                                                     HInstruction* instruction,
                                                     Location source,
                                                     Location destination) const {
-  DCHECK(IsValidDestination(destination));
+  DCHECK(IsValidDestination(destination)) << destination;
   if (source.Equals(destination)) return;
 
   HInstruction* first = block->GetFirstInstruction();
@@ -873,16 +1258,16 @@
     move->SetLifetimePosition(block->GetLifetimeStart());
     block->InsertInstructionBefore(move, first);
   }
-  move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
+  move->AddMove(source, destination, instruction);
 }
 
 void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
                                         Location source,
                                         Location destination) const {
-  DCHECK(IsValidDestination(destination));
+  DCHECK(IsValidDestination(destination)) << destination;
   if (source.Equals(destination)) return;
 
-  if (instruction->AsPhi() != nullptr) {
+  if (instruction->IsPhi()) {
     InsertParallelMoveAtEntryOf(instruction->GetBlock(), instruction, source, destination);
     return;
   }
@@ -897,7 +1282,7 @@
     move->SetLifetimePosition(position);
     instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
   }
-  move->AddMove(new (allocator_) MoveOperands(source, destination, instruction));
+  move->AddMove(source, destination, instruction);
 }
 
 void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
@@ -905,8 +1290,8 @@
   if (current->HasSpillSlot() && current->HasRegister()) {
     // We spill eagerly, so move must be at definition.
     InsertMoveAfter(interval->GetDefinedBy(),
-                    Location::RegisterLocation(ManagedRegister(interval->GetRegister())),
-                    NeedTwoSpillSlot(interval->GetType())
+                    interval->ToLocation(),
+                    interval->NeedsTwoSpillSlots()
                         ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
                         : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
   }
@@ -915,7 +1300,7 @@
   // Walk over all siblings, updating locations of use positions, and
   // connecting them when they are adjacent.
   do {
-    Location source = ConvertToLocation(current);
+    Location source = current->ToLocation();
 
     // Walk over all uses covered by this interval, and update the location
     // information.
@@ -925,10 +1310,17 @@
         locations->SetEnvironmentAt(use->GetInputIndex(), source);
       } else {
         Location expected_location = locations->InAt(use->GetInputIndex());
-        if (expected_location.IsUnallocated()) {
-          locations->SetInAt(use->GetInputIndex(), source);
-        } else if (!expected_location.IsConstant()) {
-          AddInputMoveFor(use->GetUser(), source, expected_location);
+        // The expected (actual) location may be invalid in case the input is unused. Currently
+        // this only happens for intrinsics.
+        if (expected_location.IsValid()) {
+          if (expected_location.IsUnallocated()) {
+            locations->SetInAt(use->GetInputIndex(), source);
+          } else if (!expected_location.IsConstant()) {
+            AddInputMoveFor(use->GetUser(), source, expected_location);
+          }
+        } else {
+          DCHECK(use->GetUser()->IsInvoke());
+          DCHECK(use->GetUser()->AsInvoke()->GetIntrinsic() != Intrinsics::kNone);
         }
       }
       use = use->GetNext();
@@ -940,7 +1332,7 @@
     if (next_sibling != nullptr
         && next_sibling->HasRegister()
         && current->GetEnd() == next_sibling->GetStart()) {
-      Location destination = ConvertToLocation(next_sibling);
+      Location destination = next_sibling->ToLocation();
       InsertParallelMoveAt(current->GetEnd(), interval->GetDefinedBy(), source, destination);
     }
 
@@ -949,7 +1341,14 @@
       HInstruction* safepoint = safepoints_.Get(i);
       size_t position = safepoint->GetLifetimePosition();
       LocationSummary* locations = safepoint->GetLocations();
-      if (!current->Covers(position)) continue;
+      if (!current->Covers(position)) {
+        continue;
+      }
+      if (interval->GetStart() == position) {
+        // The safepoint is for this instruction, so the location of the instruction
+        // does not need to be saved.
+        continue;
+      }
 
       if ((current->GetType() == Primitive::kPrimNot) && current->GetParent()->HasSpillSlot()) {
         locations->SetStackBit(current->GetParent()->GetSpillSlot() / kVRegSize);
@@ -958,11 +1357,25 @@
       switch (source.GetKind()) {
         case Location::kRegister: {
           locations->AddLiveRegister(source);
+          DCHECK_LE(locations->GetNumberOfLiveRegisters(),
+                    maximum_number_of_live_core_registers_ +
+                    maximum_number_of_live_fp_registers_);
           if (current->GetType() == Primitive::kPrimNot) {
-            locations->SetRegisterBit(source.reg().RegId());
+            locations->SetRegisterBit(source.reg());
           }
           break;
         }
+        case Location::kFpuRegister: {
+          locations->AddLiveRegister(source);
+          break;
+        }
+
+        case Location::kRegisterPair:
+        case Location::kFpuRegisterPair: {
+          locations->AddLiveRegister(source.ToLow());
+          locations->AddLiveRegister(source.ToHigh());
+          break;
+        }
         case Location::kStackSlot:  // Fall-through
         case Location::kDoubleStackSlot:  // Fall-through
         case Location::kConstant: {
@@ -987,12 +1400,10 @@
     return;
   }
 
+  // Intervals end at the lifetime end of a block. The decrement by one
+  // ensures the `Cover` call will return true.
   size_t from_position = from->GetLifetimeEnd() - 1;
-  // When an instructions dies at entry of another, and the latter is the beginning
-  // of a block, the register allocator ensures the former has a register
-  // at block->GetLifetimeStart() + 1. Since this is at a block boundary, it must
-  // must be handled in this method.
-  size_t to_position = to->GetLifetimeStart() + 1;
+  size_t to_position = to->GetLifetimeStart();
 
   LiveInterval* destination = nullptr;
   LiveInterval* source = nullptr;
@@ -1030,30 +1441,21 @@
   if (from->GetSuccessors().Size() == 1) {
     InsertParallelMoveAtExitOf(from,
                                interval->GetParent()->GetDefinedBy(),
-                               ConvertToLocation(source),
-                               ConvertToLocation(destination));
+                               source->ToLocation(),
+                               destination->ToLocation());
   } else {
     DCHECK_EQ(to->GetPredecessors().Size(), 1u);
     InsertParallelMoveAtEntryOf(to,
                                 interval->GetParent()->GetDefinedBy(),
-                                ConvertToLocation(source),
-                                ConvertToLocation(destination));
+                                source->ToLocation(),
+                                destination->ToLocation());
   }
 }
 
-// Returns the location of `interval`, or siblings of `interval`, at `position`.
-static Location FindLocationAt(LiveInterval* interval, size_t position) {
-  LiveInterval* current = interval;
-  while (!current->Covers(position)) {
-    current = current->GetNextSibling();
-    DCHECK(current != nullptr);
-  }
-  return ConvertToLocation(current);
-}
-
 void RegisterAllocator::Resolve() {
   codegen_->ComputeFrameSize(
-      spill_slots_.Size(), maximum_number_of_live_registers_, reserved_out_slots_);
+      spill_slots_.Size(), maximum_number_of_live_core_registers_,
+      maximum_number_of_live_fp_registers_, reserved_out_slots_);
 
   // Adjust the Out Location of instructions.
   // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
@@ -1062,26 +1464,30 @@
     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());
         current->SetSpillSlot(location.GetStackIndex());
-        locations->SetOut(location);
+        locations->UpdateOut(location);
       } else if (location.IsDoubleStackSlot()) {
         location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
         current->SetSpillSlot(location.GetStackIndex());
-        locations->SetOut(location);
+        locations->UpdateOut(location);
       } else if (current->HasSpillSlot()) {
         current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
       }
     }
 
-    Location source = ConvertToLocation(current);
+    Location source = current->ToLocation();
 
     if (location.IsUnallocated()) {
       if (location.GetPolicy() == Location::kSameAsFirstInput) {
-        locations->SetInAt(0, source);
+        if (locations->InAt(0).IsUnallocated()) {
+          locations->SetInAt(0, source);
+        } else {
+          DCHECK(locations->InAt(0).Equals(source));
+        }
       }
       locations->SetOut(source);
     } else {
@@ -1111,15 +1517,15 @@
   // Resolve phi inputs. Order does not matter.
   for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
     HBasicBlock* current = it.Current();
-    for (HInstructionIterator it(current->GetPhis()); !it.Done(); it.Advance()) {
-      HInstruction* phi = it.Current();
+    for (HInstructionIterator inst_it(current->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+      HInstruction* phi = inst_it.Current();
       for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
         HBasicBlock* predecessor = current->GetPredecessors().Get(i);
         DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
         HInstruction* input = phi->InputAt(i);
-        Location source = FindLocationAt(input->GetLiveInterval(),
-                                         predecessor->GetLastInstruction()->GetLifetimePosition());
-        Location destination = ConvertToLocation(phi->GetLiveInterval());
+        Location source = input->GetLiveInterval()->GetLocationAt(
+            predecessor->GetLifetimeEnd() - 1);
+        Location destination = phi->GetLiveInterval()->ToLocation();
         InsertParallelMoveAtExitOf(predecessor, nullptr, source, destination);
       }
     }
@@ -1130,13 +1536,37 @@
   size_t temp_index = 0;
   for (size_t i = 0; i < temp_intervals_.Size(); ++i) {
     LiveInterval* temp = temp_intervals_.Get(i);
-    if (temp->GetDefinedBy() != current) {
-      temp_index = 0;
-      current = temp->GetDefinedBy();
+    if (temp->IsHighInterval()) {
+      // High intervals can be skipped, they are already handled by the low interval.
+      continue;
     }
-    LocationSummary* locations = current->GetLocations();
-    locations->SetTempAt(
-        temp_index++, Location::RegisterLocation(ManagedRegister(temp->GetRegister())));
+    HInstruction* at = liveness_.GetTempUser(temp);
+    if (at != current) {
+      temp_index = 0;
+      current = at;
+    }
+    LocationSummary* locations = at->GetLocations();
+    switch (temp->GetType()) {
+      case Primitive::kPrimInt:
+        locations->SetTempAt(
+            temp_index++, Location::RegisterLocation(temp->GetRegister()));
+        break;
+
+      case Primitive::kPrimDouble:
+        if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
+          Location location = Location::FpuRegisterPairLocation(
+              temp->GetRegister(), temp->GetHighInterval()->GetRegister());
+          locations->SetTempAt(temp_index++, location);
+        } else {
+          locations->SetTempAt(
+              temp_index++, Location::FpuRegisterLocation(temp->GetRegister()));
+        }
+        break;
+
+      default:
+        LOG(FATAL) << "Unexpected type for temporary location "
+                   << temp->GetType();
+    }
   }
 }
 
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index d4c233a..b8f70bd 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;
@@ -69,10 +67,11 @@
 
   static bool CanAllocateRegistersFor(const HGraph& graph, InstructionSet instruction_set);
   static bool Supports(InstructionSet instruction_set) {
-    return instruction_set == kX86
-        || instruction_set == kArm
-        || instruction_set == kX86_64
-        || instruction_set == kThumb2;
+    return instruction_set == kArm
+        || instruction_set == kArm64
+        || instruction_set == kThumb2
+        || instruction_set == kX86
+        || instruction_set == kX86_64;
   }
 
   size_t GetNumberOfSpillSlots() const {
@@ -96,7 +95,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);
@@ -128,6 +127,13 @@
   void ProcessInstruction(HInstruction* instruction);
   bool ValidateInternal(bool log_fatal_on_failure) const;
   void DumpInterval(std::ostream& stream, LiveInterval* interval) const;
+  void DumpAllIntervals(std::ostream& stream) const;
+  int FindAvailableRegisterPair(size_t* next_use, size_t starting_at) const;
+  int FindAvailableRegister(size_t* next_use) const;
+
+  // Try splitting an active non-pair interval at the given `position`.
+  // Returns whether it was successful at finding such an interval.
+  bool TrySplitNonPairIntervalAt(size_t position, size_t first_register_use, size_t* next_use);
 
   ArenaAllocator* const allocator_;
   CodeGenerator* const codegen_;
@@ -158,7 +164,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,15 +188,20 @@
   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_;
 
-  // The maximum live registers at safepoints.
-  size_t maximum_number_of_live_registers_;
+  // The maximum live core registers at safepoints.
+  size_t maximum_number_of_live_core_registers_;
 
-  FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
+  // The maximum live FP registers at safepoints.
+  size_t maximum_number_of_live_fp_registers_;
+
+  ART_FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
+  ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
 
   DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
 };
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 535a768..cb5010a 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -19,6 +19,7 @@
 #include "code_generator_x86.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
+#include "driver/compiler_options.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
 #include "register_allocator.h"
@@ -39,10 +40,8 @@
   HGraphBuilder builder(&allocator);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
-  x86::CodeGeneratorX86 codegen(graph);
+  graph->TryBuildingSsa();
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
   RegisterAllocator register_allocator(&allocator, &codegen, liveness);
@@ -58,7 +57,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   GrowableArray<LiveInterval*> intervals(&allocator, 0);
 
   // Test with two intervals of the same range.
@@ -253,9 +252,7 @@
   HGraphBuilder builder(allocator);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  graph->FindNaturalLoops();
+  graph->TryBuildingSsa();
   return graph;
 }
 
@@ -299,7 +296,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildSSAGraph(data, &allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
   RegisterAllocator register_allocator(&allocator, &codegen, liveness);
@@ -331,7 +328,7 @@
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildSSAGraph(data, &allocator);
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
 
@@ -348,14 +345,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) {
@@ -384,7 +381,7 @@
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildSSAGraph(data, &allocator);
   SsaDeadPhiElimination(graph).Run();
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
   RegisterAllocator register_allocator(&allocator, &codegen, liveness);
@@ -406,7 +403,7 @@
   ArenaAllocator allocator(&pool);
   HGraph* graph = BuildSSAGraph(data, &allocator);
   SsaDeadPhiElimination(graph).Run();
-  x86::CodeGeneratorX86 codegen(graph);
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
   liveness.Analyze();
   RegisterAllocator register_allocator(&allocator, &codegen, liveness);
@@ -414,21 +411,24 @@
   // Add an artifical range to cover the temps that will be put in the unhandled list.
   LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
   unhandled->AddLoopRange(0, 60);
+  // For SSA value intervals, only an interval resulted from a split may intersect
+  // with inactive intervals.
+  unhandled = register_allocator.Split(unhandled, 5);
 
   // Add three temps holding the same register, and starting at different positions.
   // Put the one that should be picked in the middle of the inactive list to ensure
   // we do not depend on an order.
-  LiveInterval* interval = LiveInterval::MakeTempInterval(&allocator, nullptr, Primitive::kPrimInt);
+  LiveInterval* interval = LiveInterval::MakeInterval(&allocator, Primitive::kPrimInt);
   interval->SetRegister(0);
   interval->AddRange(40, 50);
   register_allocator.inactive_.Add(interval);
 
-  interval = LiveInterval::MakeTempInterval(&allocator, nullptr, Primitive::kPrimInt);
+  interval = LiveInterval::MakeInterval(&allocator, Primitive::kPrimInt);
   interval->SetRegister(0);
   interval->AddRange(20, 30);
   register_allocator.inactive_.Add(interval);
 
-  interval = LiveInterval::MakeTempInterval(&allocator, nullptr, Primitive::kPrimInt);
+  interval = LiveInterval::MakeInterval(&allocator, Primitive::kPrimInt);
   interval->SetRegister(0);
   interval->AddRange(60, 70);
   register_allocator.inactive_.Add(interval);
@@ -438,7 +438,7 @@
   register_allocator.processing_core_registers_ = true;
   register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
 
-  register_allocator.TryAllocateFreeReg(unhandled);
+  ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
 
   // Check that we have split the interval.
   ASSERT_EQ(1u, register_allocator.unhandled_->Size());
@@ -447,4 +447,398 @@
   ASSERT_EQ(20u, register_allocator.unhandled_->Get(0)->GetStart());
 }
 
+static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
+                                  HPhi** phi,
+                                  HInstruction** input1,
+                                  HInstruction** input2) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+  entry->AddInstruction(parameter);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+
+  HInstruction* test = new (allocator) HInstanceFieldGet(
+      parameter, Primitive::kPrimBoolean, MemberOffset(22), false);
+  block->AddInstruction(test);
+  block->AddInstruction(new (allocator) HIf(test));
+  HBasicBlock* then = new (allocator) HBasicBlock(graph);
+  HBasicBlock* else_ = new (allocator) HBasicBlock(graph);
+  HBasicBlock* join = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(then);
+  graph->AddBlock(else_);
+  graph->AddBlock(join);
+
+  block->AddSuccessor(then);
+  block->AddSuccessor(else_);
+  then->AddSuccessor(join);
+  else_->AddSuccessor(join);
+  then->AddInstruction(new (allocator) HGoto());
+  else_->AddInstruction(new (allocator) HGoto());
+
+  *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
+  join->AddPhi(*phi);
+  *input1 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
+                                              MemberOffset(42), false);
+  *input2 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
+                                              MemberOffset(42), false);
+  then->AddInstruction(*input1);
+  else_->AddInstruction(*input2);
+  join->AddInstruction(new (allocator) HExit());
+  (*phi)->AddInput(*input1);
+  (*phi)->AddInput(*input2);
+
+  graph->BuildDominatorTree();
+  graph->AnalyzeNaturalLoops();
+  return graph;
+}
+
+TEST(RegisterAllocatorTest, PhiHint) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HPhi *phi;
+  HInstruction *input1, *input2;
+
+  {
+    HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    // Check that the register allocator is deterministic.
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
+    ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
+    ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
+  }
+
+  {
+    HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    // Set the phi to a specific register, and check that the inputs get allocated
+    // the same register.
+    phi->GetLocations()->SetOut(Location::RegisterLocation(2));
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
+  }
+
+  {
+    HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    // Set input1 to a specific register, and check that the phi and other input get allocated
+    // the same register.
+    input1->GetLocations()->SetOut(Location::RegisterLocation(2));
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
+  }
+
+  {
+    HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    // Set input2 to a specific register, and check that the phi and other input get allocated
+    // the same register.
+    input2->GetLocations()->SetOut(Location::RegisterLocation(2));
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
+  }
+}
+
+static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
+                                HInstruction** field,
+                                HInstruction** ret) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+  entry->AddInstruction(parameter);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+
+  *field = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
+                                             MemberOffset(42), false);
+  block->AddInstruction(*field);
+  *ret = new (allocator) HReturn(*field);
+  block->AddInstruction(*ret);
+
+  HBasicBlock* exit = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(exit);
+  block->AddSuccessor(exit);
+  exit->AddInstruction(new (allocator) HExit());
+  return graph;
+}
+
+TEST(RegisterAllocatorTest, ExpectedInRegisterHint) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HInstruction *field, *ret;
+
+  {
+    HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
+    ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
+  }
+
+  {
+    HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    // Check that the field gets put in the register expected by its use.
+    // Don't use SetInAt because we are overriding an already allocated location.
+    ret->GetLocations()->inputs_.Put(0, Location::RegisterLocation(2));
+
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
+  }
+}
+
+static HGraph* BuildTwoAdds(ArenaAllocator* allocator,
+                            HInstruction** first_add,
+                            HInstruction** second_add) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+  HInstruction* constant1 = new (allocator) HIntConstant(0);
+  HInstruction* constant2 = new (allocator) HIntConstant(0);
+  entry->AddInstruction(parameter);
+  entry->AddInstruction(constant1);
+  entry->AddInstruction(constant2);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+
+  *first_add = new (allocator) HAdd(Primitive::kPrimInt, parameter, constant1);
+  block->AddInstruction(*first_add);
+  *second_add = new (allocator) HAdd(Primitive::kPrimInt, *first_add, constant2);
+  block->AddInstruction(*second_add);
+
+  block->AddInstruction(new (allocator) HExit());
+  return graph;
+}
+
+TEST(RegisterAllocatorTest, SameAsFirstInputHint) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HInstruction *first_add, *second_add;
+
+  {
+    HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    // Sanity check that in normal conditions, the registers are the same.
+    ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 1);
+    ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 1);
+  }
+
+  {
+    HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    // check that both adds get the same register.
+    // Don't use SetOutput because output is already allocated.
+    first_add->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
+    ASSERT_EQ(first_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
+    ASSERT_EQ(second_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
+
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 2);
+    ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 2);
+  }
+}
+
+static HGraph* BuildDiv(ArenaAllocator* allocator,
+                        HInstruction** div) {
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* first = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+  HInstruction* second = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+  entry->AddInstruction(first);
+  entry->AddInstruction(second);
+
+  HBasicBlock* block = new (allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+
+  *div = new (allocator) HDiv(Primitive::kPrimInt, first, second, 0);  // don't care about dex_pc.
+  block->AddInstruction(*div);
+
+  block->AddInstruction(new (allocator) HExit());
+  return graph;
+}
+
+TEST(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HInstruction *div;
+
+  {
+    HGraph* graph = BuildDiv(&allocator, &div);
+    x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+    SsaLivenessAnalysis liveness(*graph, &codegen);
+    liveness.Analyze();
+
+    RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    // div on x86 requires its first input in eax and the output be the same as the first input.
+    ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
+  }
+}
+
+// Test a bug in the register allocator, where allocating a blocked
+// register would lead to spilling an inactive interval at the wrong
+// position.
+TEST(RegisterAllocatorTest, SpillInactive) {
+  ArenaPool pool;
+
+  // Create a synthesized graph to please the register_allocator and
+  // ssa_liveness_analysis code.
+  ArenaAllocator allocator(&pool);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(entry);
+  graph->SetEntryBlock(entry);
+  HInstruction* one = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
+  HInstruction* two = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
+  HInstruction* three = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
+  HInstruction* four = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
+  entry->AddInstruction(one);
+  entry->AddInstruction(two);
+  entry->AddInstruction(three);
+  entry->AddInstruction(four);
+
+  HBasicBlock* block = new (&allocator) HBasicBlock(graph);
+  graph->AddBlock(block);
+  entry->AddSuccessor(block);
+  block->AddInstruction(new (&allocator) HExit());
+
+  // We create a synthesized user requesting a register, to avoid just spilling the
+  // intervals.
+  HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, Primitive::kPrimInt);
+  user->AddInput(one);
+  user->SetBlock(block);
+  LocationSummary* locations = new (&allocator) LocationSummary(user, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  static constexpr size_t phi_ranges[][2] = {{20, 30}};
+  BuildInterval(phi_ranges, arraysize(phi_ranges), &allocator, -1, user);
+
+  // Create an interval with lifetime holes.
+  static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
+  LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), &allocator, -1, one);
+  first->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, first->first_use_);
+  first->first_use_ = new(&allocator) UsePosition(user, 0, false, 7, first->first_use_);
+  first->first_use_ = new(&allocator) UsePosition(user, 0, false, 6, first->first_use_);
+
+  locations = new (&allocator) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+  first = first->SplitAt(1);
+
+  // Create an interval that conflicts with the next interval, to force the next
+  // interval to call `AllocateBlockedReg`.
+  static constexpr size_t ranges2[][2] = {{2, 4}};
+  LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), &allocator, -1, two);
+  locations = new (&allocator) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+
+  // Create an interval that will lead to splitting the first interval. The bug occured
+  // by splitting at a wrong position, in this case at the next intersection between
+  // this interval and the first interval. We would have then put the interval with ranges
+  // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
+  // before lifetime position 6 yet.
+  static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
+  LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), &allocator, -1, three);
+  third->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, third->first_use_);
+  third->first_use_ = new(&allocator) UsePosition(user, 0, false, 4, third->first_use_);
+  third->first_use_ = new(&allocator) UsePosition(user, 0, false, 3, third->first_use_);
+  locations = new (&allocator) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+  third = third->SplitAt(3);
+
+  // Because the first part of the split interval was considered handled, this interval
+  // was free to allocate the same register, even though it conflicts with it.
+  static constexpr size_t ranges4[][2] = {{4, 6}};
+  LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), &allocator, -1, four);
+  locations = new (&allocator) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+
+  x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
+  SsaLivenessAnalysis liveness(*graph, &codegen);
+
+  RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+  register_allocator.unhandled_core_intervals_.Add(fourth);
+  register_allocator.unhandled_core_intervals_.Add(third);
+  register_allocator.unhandled_core_intervals_.Add(second);
+  register_allocator.unhandled_core_intervals_.Add(first);
+
+  // Set just one register available to make all intervals compete for the same.
+  register_allocator.number_of_registers_ = 1;
+  register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
+  register_allocator.processing_core_registers_ = true;
+  register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
+  register_allocator.LinearScan();
+
+  // Test that there is no conflicts between intervals.
+  GrowableArray<LiveInterval*> intervals(&allocator, 0);
+  intervals.Add(first);
+  intervals.Add(second);
+  intervals.Add(third);
+  intervals.Add(fourth);
+  ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
+      intervals, 0, 0, codegen, &allocator, true, false));
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 471307e..edfafcd 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -18,6 +18,7 @@
 
 #include "nodes.h"
 #include "ssa_type_propagation.h"
+#include "ssa_phi_elimination.h"
 
 namespace art {
 
@@ -41,17 +42,26 @@
     }
   }
 
-  // 3) Propagate types of phis.
+  // 3) Remove dead phis. This will remove phis that are only used by environments:
+  // at the DEX level, the type of these phis does not need to be consistent, but
+  // our code generator will complain if the inputs of a phi do not have the same
+  // type (modulo the special case of `null`).
+  SsaDeadPhiElimination dead_phis(GetGraph());
+  dead_phis.Run();
+
+  // 4) Propagate types of phis. At this point, phis are typed void in the general
+  // case, or float or double when we created a floating-point equivalent. So we
+  // need to propagate the types across phis to give them a correct type.
   SsaTypePropagation type_propagation(GetGraph());
   type_propagation.Run();
 
-  // 4) Clear locals.
+  // 5) Clear locals.
   // TODO: Move this to a dead code eliminator phase.
   for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
        !it.Done();
        it.Advance()) {
     HInstruction* current = it.Current();
-    if (current->AsLocal() != nullptr) {
+    if (current->IsLocal()) {
       current->GetBlock()->RemoveInstruction(current);
     }
   }
@@ -109,8 +119,8 @@
         HPhi* phi = new (GetGraph()->GetArena()) HPhi(
             GetGraph()->GetArena(), local, block->GetPredecessors().Size(), Primitive::kPrimVoid);
         for (size_t i = 0; i < block->GetPredecessors().Size(); i++) {
-          HInstruction* value = ValueOfLocal(block->GetPredecessors().Get(i), local);
-          phi->SetRawInputAt(i, value);
+          HInstruction* pred_value = ValueOfLocal(block->GetPredecessors().Get(i), local);
+          phi->SetRawInputAt(i, pred_value);
         }
         block->AddPhi(phi);
         value = phi;
@@ -129,8 +139,109 @@
   }
 }
 
+/**
+ * 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->AsPhi()->GetRegNumber() != phi->GetRegNumber())) {
+    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 {
+    DCHECK_EQ(next->GetType(), type);
+    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);
 }
 
@@ -149,4 +260,9 @@
   instruction->SetEnvironment(environment);
 }
 
+void SsaBuilder::VisitTemporary(HTemporary* temp) {
+  // Temporaries are only used by the baseline register allocator.
+  temp->GetBlock()->RemoveInstruction(temp);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 9d8c072..2cbd51a 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_
 
 #include "nodes.h"
+#include "optimization.h"
 
 namespace art {
 
@@ -51,6 +52,11 @@
   void VisitLoadLocal(HLoadLocal* load);
   void VisitStoreLocal(HStoreLocal* store);
   void VisitInstruction(HInstruction* instruction);
+  void VisitTemporary(HTemporary* instruction);
+
+  static HInstruction* GetFloatOrDoubleEquivalent(HInstruction* user,
+                                                  HInstruction* instruction,
+                                                  Primitive::Type type);
 
  private:
   // Locals for the current block being visited.
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index cd13d81..d41157b 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -28,11 +28,6 @@
   ComputeLiveness();
 }
 
-static bool IsLoopExit(HLoopInformation* current, HLoopInformation* to) {
-  // `to` is either not part of a loop, or `current` is an inner loop of `to`.
-  return to == nullptr || (current != to && current->IsIn(*to));
-}
-
 static bool IsLoop(HLoopInformation* info) {
   return info != nullptr;
 }
@@ -48,46 +43,64 @@
       && inner->IsIn(*outer);
 }
 
-static void VisitBlockForLinearization(HBasicBlock* block,
-                                       GrowableArray<HBasicBlock*>* order,
-                                       ArenaBitVector* visited) {
-  if (visited->IsBitSet(block->GetBlockId())) {
-    return;
-  }
-  visited->SetBit(block->GetBlockId());
-  size_t number_of_successors = block->GetSuccessors().Size();
-  if (number_of_successors == 0) {
-    // Nothing to do.
-  } else if (number_of_successors == 1) {
-    VisitBlockForLinearization(block->GetSuccessors().Get(0), order, visited);
-  } else {
-    DCHECK_EQ(number_of_successors, 2u);
-    HBasicBlock* first_successor = block->GetSuccessors().Get(0);
-    HBasicBlock* second_successor = block->GetSuccessors().Get(1);
-    HLoopInformation* my_loop = block->GetLoopInformation();
-    HLoopInformation* first_loop = first_successor->GetLoopInformation();
-    HLoopInformation* second_loop = second_successor->GetLoopInformation();
-
-    if (!IsLoop(my_loop)) {
-      // Nothing to do. Current order is fine.
-    } else if (IsLoopExit(my_loop, second_loop) && InSameLoop(my_loop, first_loop)) {
-      // Visit the loop exit first in post order.
-      std::swap(first_successor, second_successor);
-    } else if (IsInnerLoop(my_loop, first_loop) && !IsInnerLoop(my_loop, second_loop)) {
-      // Visit the inner loop last in post order.
-      std::swap(first_successor, second_successor);
+static void AddToListForLinearization(GrowableArray<HBasicBlock*>* worklist, HBasicBlock* block) {
+  size_t insert_at = worklist->Size();
+  HLoopInformation* block_loop = block->GetLoopInformation();
+  for (; insert_at > 0; --insert_at) {
+    HBasicBlock* current = worklist->Get(insert_at - 1);
+    HLoopInformation* current_loop = current->GetLoopInformation();
+    if (InSameLoop(block_loop, current_loop)
+        || !IsLoop(current_loop)
+        || IsInnerLoop(current_loop, block_loop)) {
+      // The block can be processed immediately.
+      break;
     }
-    VisitBlockForLinearization(first_successor, order, visited);
-    VisitBlockForLinearization(second_successor, order, visited);
   }
-  order->Add(block);
+  worklist->InsertAt(insert_at, block);
 }
 
 void SsaLivenessAnalysis::LinearizeGraph() {
-  // For simplicity of the implementation, we create post linear order. The order for
-  // computing live ranges is the reverse of that order.
-  ArenaBitVector visited(graph_.GetArena(), graph_.GetBlocks().Size(), false);
-  VisitBlockForLinearization(graph_.GetEntryBlock(), &linear_post_order_, &visited);
+  // Create a reverse post ordering with the following properties:
+  // - Blocks in a loop are consecutive,
+  // - Back-edge is the last block before loop exits.
+
+  // (1): Record the number of forward predecessors for each block. This is to
+  //      ensure the resulting order is reverse post order. We could use the
+  //      current reverse post order in the graph, but it would require making
+  //      order queries to a GrowableArray, which is not the best data structure
+  //      for it.
+  GrowableArray<uint32_t> forward_predecessors(graph_.GetArena(), graph_.GetBlocks().Size());
+  forward_predecessors.SetSize(graph_.GetBlocks().Size());
+  for (size_t i = 0, e = graph_.GetBlocks().Size(); i < e; ++i) {
+    HBasicBlock* block = graph_.GetBlocks().Get(i);
+    size_t number_of_forward_predecessors = block->GetPredecessors().Size();
+    if (block->IsLoopHeader()) {
+      // We rely on having simplified the CFG.
+      DCHECK_EQ(1u, block->GetLoopInformation()->NumberOfBackEdges());
+      number_of_forward_predecessors--;
+    }
+    forward_predecessors.Put(block->GetBlockId(), number_of_forward_predecessors);
+  }
+
+  // (2): Following a worklist approach, first start with the entry block, and
+  //      iterate over the successors. When all non-back edge predecessors of a
+  //      successor block are visited, the successor block is added in the worklist
+  //      following an order that satisfies the requirements to build our linear graph.
+  GrowableArray<HBasicBlock*> worklist(graph_.GetArena(), 1);
+  worklist.Add(graph_.GetEntryBlock());
+  do {
+    HBasicBlock* current = worklist.Pop();
+    linear_order_.Add(current);
+    for (size_t i = 0, e = current->GetSuccessors().Size(); i < e; ++i) {
+      HBasicBlock* successor = current->GetSuccessors().Get(i);
+      int block_id = successor->GetBlockId();
+      size_t number_of_remaining_predecessors = forward_predecessors.Get(block_id);
+      if (number_of_remaining_predecessors == 1) {
+        AddToListForLinearization(&worklist, successor);
+      }
+      forward_predecessors.Put(block_id, number_of_remaining_predecessors - 1);
+    }
+  } while (!worklist.IsEmpty());
 }
 
 void SsaLivenessAnalysis::NumberInstructions() {
@@ -107,15 +120,15 @@
     HBasicBlock* block = it.Current();
     block->SetLifetimeStart(lifetime_position);
 
-    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-      HInstruction* current = it.Current();
+    for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+      HInstruction* current = inst_it.Current();
       current->Accept(location_builder);
       LocationSummary* locations = current->GetLocations();
       if (locations != nullptr && locations->Out().IsValid()) {
         instructions_from_ssa_index_.Add(current);
         current->SetSsaIndex(ssa_index++);
         current->SetLiveInterval(
-            new (graph_.GetArena()) LiveInterval(graph_.GetArena(), current->GetType(), current));
+            LiveInterval::MakeInterval(graph_.GetArena(), current->GetType(), current));
       }
       current->SetLifetimePosition(lifetime_position);
     }
@@ -124,15 +137,16 @@
     // Add a null marker to notify we are starting a block.
     instructions_from_lifetime_position_.Add(nullptr);
 
-    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-      HInstruction* current = it.Current();
+    for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
+         inst_it.Advance()) {
+      HInstruction* current = inst_it.Current();
       current->Accept(codegen_->GetLocationBuilder());
       LocationSummary* locations = current->GetLocations();
       if (locations != nullptr && locations->Out().IsValid()) {
         instructions_from_ssa_index_.Add(current);
         current->SetSsaIndex(ssa_index++);
         current->SetLiveInterval(
-            new (graph_.GetArena()) LiveInterval(graph_.GetArena(), current->GetType(), current));
+            LiveInterval::MakeInterval(graph_.GetArena(), current->GetType(), current));
       }
       instructions_from_lifetime_position_.Add(current);
       current->SetLifetimePosition(lifetime_position);
@@ -178,8 +192,8 @@
       HBasicBlock* successor = block->GetSuccessors().Get(i);
       live_in->Union(GetLiveInSet(*successor));
       size_t phi_input_index = successor->GetPredecessorIndexOf(block);
-      for (HInstructionIterator it(successor->GetPhis()); !it.Done(); it.Advance()) {
-        HInstruction* phi = it.Current();
+      for (HInstructionIterator inst_it(successor->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+        HInstruction* phi = inst_it.Current();
         HInstruction* input = phi->InputAt(phi_input_index);
         input->GetLiveInterval()->AddPhiUse(phi, phi_input_index, block);
         // A phi input whose last user is the phi dies at the end of the predecessor block,
@@ -195,8 +209,9 @@
       current->GetLiveInterval()->AddRange(block->GetLifetimeStart(), block->GetLifetimeEnd());
     }
 
-    for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-      HInstruction* current = it.Current();
+    for (HBackwardInstructionIterator back_it(block->GetInstructions()); !back_it.Done();
+         back_it.Advance()) {
+      HInstruction* current = back_it.Current();
       if (current->HasSsaIndex()) {
         // Kill the instruction and shorten its interval.
         kill->SetBit(current->GetSsaIndex());
@@ -230,8 +245,8 @@
     }
 
     // Kill phis defined in this block.
-    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-      HInstruction* current = it.Current();
+    for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+      HInstruction* current = inst_it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
         live_in->ClearBit(current->GetSsaIndex());
@@ -297,4 +312,155 @@
   return live_in->UnionIfNotIn(live_out, kill);
 }
 
+int LiveInterval::FindFirstRegisterHint(size_t* free_until) const {
+  if (GetParent() == this && defined_by_ != nullptr) {
+    // This is the first interval for the instruction. Try to find
+    // a register based on its definition.
+    DCHECK_EQ(defined_by_->GetLiveInterval(), this);
+    int hint = FindHintAtDefinition();
+    if (hint != kNoRegister && free_until[hint] > GetStart()) {
+      return hint;
+    }
+  }
+
+  UsePosition* use = first_use_;
+  size_t start = GetStart();
+  size_t end = GetEnd();
+  while (use != nullptr && use->GetPosition() <= end) {
+    size_t use_position = use->GetPosition();
+    if (use_position >= start && !use->GetIsEnvironment()) {
+      HInstruction* user = use->GetUser();
+      size_t input_index = use->GetInputIndex();
+      if (user->IsPhi()) {
+        // If the phi has a register, try to use the same.
+        Location phi_location = user->GetLiveInterval()->ToLocation();
+        if (SameRegisterKind(phi_location) && free_until[phi_location.reg()] >= use_position) {
+          return phi_location.reg();
+        }
+        const GrowableArray<HBasicBlock*>& predecessors = user->GetBlock()->GetPredecessors();
+        // If the instruction dies at the phi assignment, we can try having the
+        // same register.
+        if (end == predecessors.Get(input_index)->GetLifetimeEnd()) {
+          for (size_t i = 0, e = user->InputCount(); i < e; ++i) {
+            if (i == input_index) {
+              continue;
+            }
+            HInstruction* input = user->InputAt(i);
+            Location location = input->GetLiveInterval()->GetLocationAt(
+                predecessors.Get(i)->GetLifetimeEnd() - 1);
+            if (location.IsRegister() && free_until[location.reg()] >= use_position) {
+              return location.reg();
+            }
+          }
+        }
+      } else {
+        // If the instruction is expected in a register, try to use it.
+        LocationSummary* locations = user->GetLocations();
+        Location expected = locations->InAt(use->GetInputIndex());
+        // 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 (SameRegisterKind(expected) && free_until[expected.reg()] >= position) {
+          return expected.reg();
+        }
+      }
+    }
+    use = use->GetNext();
+  }
+
+  return kNoRegister;
+}
+
+int LiveInterval::FindHintAtDefinition() const {
+  if (defined_by_->IsPhi()) {
+    // Try to use the same register as one of the inputs.
+    const GrowableArray<HBasicBlock*>& predecessors = defined_by_->GetBlock()->GetPredecessors();
+    for (size_t i = 0, e = defined_by_->InputCount(); i < e; ++i) {
+      HInstruction* input = defined_by_->InputAt(i);
+      size_t end = predecessors.Get(i)->GetLifetimeEnd();
+      const LiveInterval& input_interval = input->GetLiveInterval()->GetIntervalAt(end - 1);
+      if (input_interval.GetEnd() == end) {
+        // If the input dies at the end of the predecessor, we know its register can
+        // be reused.
+        Location input_location = input_interval.ToLocation();
+        if (SameRegisterKind(input_location)) {
+          return input_location.reg();
+        }
+      }
+    }
+  } else {
+    LocationSummary* locations = GetDefinedBy()->GetLocations();
+    Location out = locations->Out();
+    if (out.IsUnallocated() && out.GetPolicy() == Location::kSameAsFirstInput) {
+      // Try to use the same register as the first input.
+      const LiveInterval& input_interval =
+          GetDefinedBy()->InputAt(0)->GetLiveInterval()->GetIntervalAt(GetStart() - 1);
+      if (input_interval.GetEnd() == GetStart()) {
+        // If the input dies at the start of this instruction, we know its register can
+        // be reused.
+        Location location = input_interval.ToLocation();
+        if (SameRegisterKind(location)) {
+          return location.reg();
+        }
+      }
+    }
+  }
+  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 {
+  DCHECK(!IsHighInterval());
+  if (HasRegister()) {
+    if (IsFloatingPoint()) {
+      if (HasHighInterval()) {
+        return Location::FpuRegisterPairLocation(GetRegister(), GetHighInterval()->GetRegister());
+      } else {
+        return Location::FpuRegisterLocation(GetRegister());
+      }
+    } else {
+      if (HasHighInterval()) {
+        return Location::RegisterPairLocation(GetRegister(), GetHighInterval()->GetRegister());
+      } else {
+        return Location::RegisterLocation(GetRegister());
+      }
+    }
+  } else {
+    HInstruction* defined_by = GetParent()->GetDefinedBy();
+    if (defined_by->IsConstant()) {
+      return defined_by->GetLocations()->Out();
+    } else if (GetParent()->HasSpillSlot()) {
+      if (NeedsTwoSpillSlots()) {
+        return Location::DoubleStackSlot(GetParent()->GetSpillSlot());
+      } else {
+        return Location::StackSlot(GetParent()->GetSpillSlot());
+      }
+    } else {
+      return Location();
+    }
+  }
+}
+
+Location LiveInterval::GetLocationAt(size_t position) const {
+  return GetIntervalAt(position).ToLocation();
+}
+
+const LiveInterval& LiveInterval::GetIntervalAt(size_t position) const {
+  const LiveInterval* current = this;
+  while (!current->Covers(position)) {
+    current = current->GetNextSibling();
+    DCHECK(current != nullptr);
+  }
+  return *current;
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index c62e61b..a123313 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -23,13 +23,16 @@
 
 class CodeGenerator;
 
-class BlockInfo : public ArenaObject {
+static constexpr int kNoRegister = -1;
+
+class BlockInfo : public ArenaObject<kArenaAllocMisc> {
  public:
   BlockInfo(ArenaAllocator* allocator, const HBasicBlock& block, size_t number_of_ssa_values)
       : block_(block),
         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();
@@ -50,7 +53,7 @@
  * A live range contains the start and end of a range where an instruction or a temporary
  * is live.
  */
-class LiveRange : public ArenaObject {
+class LiveRange FINAL : public ArenaObject<kArenaAllocMisc> {
  public:
   LiveRange(size_t start, size_t end, LiveRange* next) : start_(start), end_(end), next_(next) {
     DCHECK_LT(start, end);
@@ -61,19 +64,28 @@
   size_t GetEnd() const { return end_; }
   LiveRange* GetNext() const { return next_; }
 
-  bool IntersectsWith(const LiveRange& other) {
+  bool IntersectsWith(const LiveRange& other) const {
     return (start_ >= other.start_ && start_ < other.end_)
         || (other.start_ >= start_ && other.start_ < end_);
   }
 
-  bool IsBefore(const LiveRange& other) {
+  bool IsBefore(const LiveRange& other) const {
     return end_ <= other.start_;
   }
 
-  void Dump(std::ostream& stream) {
+  void Dump(std::ostream& stream) const {
     stream << "[" << start_ << ", " << end_ << ")";
   }
 
+  LiveRange* Dup(ArenaAllocator* allocator) const {
+    return new (allocator) LiveRange(
+        start_, end_, next_ == nullptr ? nullptr : next_->Dup(allocator));
+  }
+
+  LiveRange* GetLastRange() {
+    return next_ == nullptr ? this : next_->GetLastRange();
+  }
+
  private:
   size_t start_;
   size_t end_;
@@ -87,7 +99,7 @@
 /**
  * A use position represents a live interval use at a given position.
  */
-class UsePosition : public ArenaObject {
+class UsePosition : public ArenaObject<kArenaAllocMisc> {
  public:
   UsePosition(HInstruction* user,
               size_t input_index,
@@ -120,6 +132,12 @@
     stream << position_;
   }
 
+  UsePosition* Dup(ArenaAllocator* allocator) const {
+    return new (allocator) UsePosition(
+        user_, input_index_, is_environment_, position_,
+        next_ == nullptr ? nullptr : next_->Dup(allocator));
+  }
+
  private:
   HInstruction* const user_;
   const size_t input_index_;
@@ -134,28 +152,13 @@
  * An interval is a list of disjoint live ranges where an instruction is live.
  * Each instruction that has uses gets an interval.
  */
-class LiveInterval : public ArenaObject {
+class LiveInterval : public ArenaObject<kArenaAllocMisc> {
  public:
-  LiveInterval(ArenaAllocator* allocator,
-               Primitive::Type type,
-               HInstruction* defined_by = nullptr,
-               bool is_fixed = false,
-               int reg = kNoRegister,
-               bool is_temp = false,
-               bool is_slow_path_safepoint = false)
-      : allocator_(allocator),
-        first_range_(nullptr),
-        last_range_(nullptr),
-        first_use_(nullptr),
-        type_(type),
-        next_sibling_(nullptr),
-        parent_(this),
-        register_(reg),
-        spill_slot_(kNoSpillSlot),
-        is_fixed_(is_fixed),
-        is_temp_(is_temp),
-        is_slow_path_safepoint_(is_slow_path_safepoint),
-        defined_by_(defined_by) {}
+  static LiveInterval* MakeInterval(ArenaAllocator* allocator,
+                                    Primitive::Type type,
+                                    HInstruction* instruction = nullptr) {
+    return new (allocator) LiveInterval(allocator, type, instruction);
+  }
 
   static LiveInterval* MakeSlowPathInterval(ArenaAllocator* allocator, HInstruction* instruction) {
     return new (allocator) LiveInterval(
@@ -166,14 +169,15 @@
     return new (allocator) LiveInterval(allocator, type, nullptr, true, reg, false);
   }
 
-  static LiveInterval* MakeTempInterval(ArenaAllocator* allocator,
-                                        HInstruction* defined_by,
-                                        Primitive::Type type) {
-    return new (allocator) LiveInterval(allocator, type, defined_by, false, kNoRegister, true);
+  static LiveInterval* MakeTempInterval(ArenaAllocator* allocator, Primitive::Type type) {
+    return new (allocator) LiveInterval(allocator, type, nullptr, false, kNoRegister, true);
   }
 
   bool IsFixed() const { return is_fixed_; }
+  bool IsTemp() const { return is_temp_; }
   bool IsSlowPathSafepoint() const { return is_slow_path_safepoint_; }
+  // This interval is the result of a split.
+  bool IsSplit() const { return parent_ != this; }
 
   void AddUse(HInstruction* instruction, size_t input_index, bool is_environment) {
     // Set the use within the instruction.
@@ -188,10 +192,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 +362,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 +374,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();
@@ -417,7 +429,7 @@
     LiveRange* current = first_range_;
     LiveRange* previous = nullptr;
     // Iterate over the ranges, and either find a range that covers this position, or
-    // a two ranges in between this position (that is, the position is in a lifetime hole).
+    // two ranges in between this position (that is, the position is in a lifetime hole).
     do {
       if (position >= current->GetEnd()) {
         // Move to next range.
@@ -480,11 +492,120 @@
       } while ((use = use->GetNext()) != nullptr);
     }
     stream << "}";
+    stream << " is_fixed: " << is_fixed_ << ", is_split: " << IsSplit();
+    stream << " is_high: " << IsHighInterval();
+    stream << " is_low: " << IsLowInterval();
   }
 
   LiveInterval* GetNextSibling() const { return next_sibling_; }
 
+  // Returns the first register hint that is at least free before
+  // the value contained in `free_until`. If none is found, returns
+  // `kNoRegister`.
+  int FindFirstRegisterHint(size_t* free_until) const;
+
+  // If there is enough at the definition site to find a register (for example
+  // it uses the same input as the first input), returns the register as a hint.
+  // Returns kNoRegister otherwise.
+  int FindHintAtDefinition() const;
+
+  // Returns whether the interval needs two (Dex virtual register size `kVRegSize`)
+  // 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;
+
+  // Returns the location of the interval following its siblings at `position`.
+  Location GetLocationAt(size_t position) const;
+
+  // Finds the interval that covers `position`.
+  const LiveInterval& GetIntervalAt(size_t position) const;
+
+  // Returns whether `other` and `this` share the same kind of register.
+  bool SameRegisterKind(Location other) const;
+
+  bool HasHighInterval() const {
+    return IsLowInterval();
+  }
+
+  bool HasLowInterval() const {
+    return IsHighInterval();
+  }
+
+  LiveInterval* GetLowInterval() const {
+    DCHECK(HasLowInterval());
+    return high_or_low_interval_;
+  }
+
+  LiveInterval* GetHighInterval() const {
+    DCHECK(HasHighInterval());
+    return high_or_low_interval_;
+  }
+
+  bool IsHighInterval() const {
+    return GetParent()->is_high_interval_;
+  }
+
+  bool IsLowInterval() const {
+    return !IsHighInterval() && (GetParent()->high_or_low_interval_ != nullptr);
+  }
+
+  void SetLowInterval(LiveInterval* low) {
+    DCHECK(IsHighInterval());
+    high_or_low_interval_ = low;
+  }
+
+  void SetHighInterval(LiveInterval* high) {
+    DCHECK(IsLowInterval());
+    high_or_low_interval_ = high;
+  }
+
+  void AddHighInterval(bool is_temp = false) {
+    DCHECK_EQ(GetParent(), this);
+    DCHECK(!HasHighInterval());
+    DCHECK(!HasLowInterval());
+    high_or_low_interval_ = new (allocator_) LiveInterval(
+        allocator_, type_, defined_by_, false, kNoRegister, is_temp, false, true);
+    high_or_low_interval_->high_or_low_interval_ = this;
+    if (first_range_ != nullptr) {
+      high_or_low_interval_->first_range_ = first_range_->Dup(allocator_);
+      high_or_low_interval_->last_range_ = first_range_->GetLastRange();
+    }
+    if (first_use_ != nullptr) {
+      high_or_low_interval_->first_use_ = first_use_->Dup(allocator_);
+    }
+  }
+
  private:
+  LiveInterval(ArenaAllocator* allocator,
+               Primitive::Type type,
+               HInstruction* defined_by = nullptr,
+               bool is_fixed = false,
+               int reg = kNoRegister,
+               bool is_temp = false,
+               bool is_slow_path_safepoint = false,
+               bool is_high_interval = false)
+      : allocator_(allocator),
+        first_range_(nullptr),
+        last_range_(nullptr),
+        first_use_(nullptr),
+        type_(type),
+        next_sibling_(nullptr),
+        parent_(this),
+        register_(reg),
+        spill_slot_(kNoSpillSlot),
+        is_fixed_(is_fixed),
+        is_temp_(is_temp),
+        is_slow_path_safepoint_(is_slow_path_safepoint),
+        is_high_interval_(is_high_interval),
+        high_or_low_interval_(nullptr),
+        defined_by_(defined_by) {}
+
   ArenaAllocator* const allocator_;
 
   // Ranges of this interval. We need a quick access to the last range to test
@@ -519,12 +640,21 @@
   // Whether the interval is for a safepoint that calls on slow path.
   const bool is_slow_path_safepoint_;
 
+  // Whether this interval is a synthesized interval for register pair.
+  const bool is_high_interval_;
+
+  // If this interval needs a register pair, the high or low equivalent.
+  // `is_high_interval_` tells whether this holds the low or the high.
+  LiveInterval* high_or_low_interval_;
+
   // The instruction represented by this interval.
   HInstruction* const defined_by_;
 
   static constexpr int kNoRegister = -1;
   static constexpr int kNoSpillSlot = -1;
 
+  ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
+
   DISALLOW_COPY_AND_ASSIGN(LiveInterval);
 };
 
@@ -533,7 +663,7 @@
   SsaLivenessAnalysis(const HGraph& graph, CodeGenerator* codegen)
       : graph_(graph),
         codegen_(codegen),
-        linear_post_order_(graph.GetArena(), graph.GetBlocks().Size()),
+        linear_order_(graph.GetArena(), graph.GetBlocks().Size()),
         block_infos_(graph.GetArena(), graph.GetBlocks().Size()),
         instructions_from_ssa_index_(graph.GetArena(), 0),
         instructions_from_lifetime_position_(graph.GetArena(), 0),
@@ -555,8 +685,8 @@
     return &block_infos_.Get(block.GetBlockId())->kill_;
   }
 
-  const GrowableArray<HBasicBlock*>& GetLinearPostOrder() const {
-    return linear_post_order_;
+  const GrowableArray<HBasicBlock*>& GetLinearOrder() const {
+    return linear_order_;
   }
 
   HInstruction* GetInstructionFromSsaIndex(size_t index) const {
@@ -567,6 +697,12 @@
     return instructions_from_lifetime_position_.Get(index);
   }
 
+  HInstruction* GetTempUser(LiveInterval* temp) const {
+    // A temporary shares the same lifetime start as the instruction that requires it.
+    DCHECK(temp->IsTemp());
+    return GetInstructionFromPosition(temp->GetStart() / 2);
+  }
+
   size_t GetMaxLifetimePosition() const {
     return instructions_from_lifetime_position_.Size() * 2 - 1;
   }
@@ -606,7 +742,7 @@
 
   const HGraph& graph_;
   CodeGenerator* const codegen_;
-  GrowableArray<HBasicBlock*> linear_post_order_;
+  GrowableArray<HBasicBlock*> linear_order_;
   GrowableArray<BlockInfo*> block_infos_;
 
   // Temporary array used when computing live_in, live_out, and kill sets.
@@ -619,38 +755,43 @@
   DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
 };
 
-class HLinearOrderIterator : public ValueObject {
- public:
-  explicit HLinearOrderIterator(const SsaLivenessAnalysis& liveness)
-      : post_order_(liveness.GetLinearPostOrder()), index_(liveness.GetLinearPostOrder().Size()) {}
-
-  bool Done() const { return index_ == 0; }
-  HBasicBlock* Current() const { return post_order_.Get(index_ -1); }
-  void Advance() { --index_; DCHECK_GE(index_, 0U); }
-
- private:
-  const GrowableArray<HBasicBlock*>& post_order_;
-  size_t index_;
-
-  DISALLOW_COPY_AND_ASSIGN(HLinearOrderIterator);
-};
-
 class HLinearPostOrderIterator : public ValueObject {
  public:
   explicit HLinearPostOrderIterator(const SsaLivenessAnalysis& liveness)
-      : post_order_(liveness.GetLinearPostOrder()), index_(0) {}
+      : order_(liveness.GetLinearOrder()), index_(liveness.GetLinearOrder().Size()) {}
 
-  bool Done() const { return index_ == post_order_.Size(); }
-  HBasicBlock* Current() const { return post_order_.Get(index_); }
-  void Advance() { ++index_; }
+  bool Done() const { return index_ == 0; }
+
+  HBasicBlock* Current() const { return order_.Get(index_ -1); }
+
+  void Advance() {
+    --index_;
+    DCHECK_GE(index_, 0U);
+  }
 
  private:
-  const GrowableArray<HBasicBlock*>& post_order_;
+  const GrowableArray<HBasicBlock*>& order_;
   size_t index_;
 
   DISALLOW_COPY_AND_ASSIGN(HLinearPostOrderIterator);
 };
 
+class HLinearOrderIterator : public ValueObject {
+ public:
+  explicit HLinearOrderIterator(const SsaLivenessAnalysis& liveness)
+      : order_(liveness.GetLinearOrder()), index_(0) {}
+
+  bool Done() const { return index_ == order_.Size(); }
+  HBasicBlock* Current() const { return order_.Get(index_); }
+  void Advance() { ++index_; }
+
+ private:
+  const GrowableArray<HBasicBlock*>& order_;
+  size_t index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HLinearOrderIterator);
+};
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_SSA_LIVENESS_ANALYSIS_H_
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index e02a182..58cea77 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -22,22 +22,17 @@
   // Add to the worklist phis referenced by non-phi instructions.
   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
     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();
+    for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+      HPhi* phi = inst_it.Current()->AsPhi();
+      // Set dead ahead of running through uses. The phi may have no use.
+      phi->SetDead();
+      for (HUseIterator<HInstruction> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) {
+        HUseListNode<HInstruction>* current = use_it.Current();
         HInstruction* user = current->GetUser();
         if (!user->IsPhi()) {
           worklist_.Add(phi);
           phi->SetLive();
-        } else {
-          phi->SetDead();
+          break;
         }
       }
     }
@@ -66,16 +61,26 @@
       next = current->GetNext();
       if (current->AsPhi()->IsDead()) {
         if (current->HasUses()) {
-          for (HUseIterator<HInstruction> it(current->GetUses()); !it.Done(); it.Advance()) {
-            HUseListNode<HInstruction>* user_node = it.Current();
+          for (HUseIterator<HInstruction> use_it(current->GetUses()); !use_it.Done();
+               use_it.Advance()) {
+            HUseListNode<HInstruction>* user_node = use_it.Current();
             HInstruction* user = user_node->GetUser();
-            DCHECK(user->IsLoopHeaderPhi());
-            DCHECK(user->AsPhi()->IsDead());
+            DCHECK(user->IsLoopHeaderPhi()) << user->GetId();
+            DCHECK(user->AsPhi()->IsDead()) << user->GetId();
             // Just put itself as an input. The phi will be removed in this loop anyway.
             user->SetRawInputAt(user_node->GetIndex(), user);
             current->RemoveUser(user, user_node->GetIndex());
           }
         }
+        if (current->HasEnvironmentUses()) {
+          for (HUseIterator<HEnvironment> use_it(current->GetEnvUses()); !use_it.Done();
+               use_it.Advance()) {
+            HUseListNode<HEnvironment>* user_node = use_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;
@@ -87,8 +92,8 @@
   // Add all phis in the worklist.
   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
-    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-      worklist_.Add(it.Current()->AsPhi());
+    for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
+      worklist_.Add(inst_it.Current()->AsPhi());
     }
   }
 
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index 5274f09..b789971 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_
 
 #include "nodes.h"
+#include "optimization.h"
 
 namespace art {
 
@@ -25,15 +26,15 @@
  * Optimization phase that removes dead phis from the graph. Dead phis are unused
  * phis, or phis only used by other phis.
  */
-class SsaDeadPhiElimination : public ValueObject {
+class SsaDeadPhiElimination : public HOptimization {
  public:
   explicit SsaDeadPhiElimination(HGraph* graph)
-      : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
+      : HOptimization(graph, true, "dead_phi_elimination"),
+        worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
-  void Run();
+  void Run() OVERRIDE;
 
  private:
-  HGraph* const graph_;
   GrowableArray<HPhi*> worklist_;
 
   static constexpr size_t kDefaultWorklistSize = 8;
@@ -47,15 +48,15 @@
  * registers might be updated with the same value, or not updated at all. We can just
  * replace the phi with the value when entering the loop.
  */
-class SsaRedundantPhiElimination : public ValueObject {
+class SsaRedundantPhiElimination : public HOptimization {
  public:
   explicit SsaRedundantPhiElimination(HGraph* graph)
-      : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
+      : HOptimization(graph, true, "redundant_phi_elimination"),
+        worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
-  void Run();
+  void Run() OVERRIDE;
 
  private:
-  HGraph* const graph_;
   GrowableArray<HPhi*> worklist_;
 
   static constexpr size_t kDefaultWorklistSize = 8;
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index fffe5c2..6b6bf05 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -87,7 +87,7 @@
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
   RemoveSuspendChecks(graph);
-  graph->TransformToSSA();
+  graph->TransformToSsa();
   ReNumberInstructions(graph);
 
   // Test that phis had their type set.
@@ -199,29 +199,31 @@
   // Test that we create a phi for an initialized local at entry of a loop.
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  0: IntConstant 0 [6, 4, 2, 2]\n"
-    "  1: Goto\n"
-    "BasicBlock 1, pred: 0, succ: 5, 6\n"
-    "  2: Equal(0, 0) [3]\n"
-    "  3: If(2)\n"
-    "BasicBlock 2, pred: 3, 6, succ: 3\n"
-    "  4: Phi(6, 0) [6]\n"
+    "  0: IntConstant 0 [6, 3, 3]\n"
+    "  1: IntConstant 4 [6]\n"
+    "  2: Goto\n"
+    "BasicBlock 1, pred: 0, succ: 4, 2\n"
+    "  3: Equal(0, 0) [4]\n"
+    "  4: If(3)\n"
+    "BasicBlock 2, pred: 1, succ: 3\n"
     "  5: Goto\n"
-    "BasicBlock 3, pred: 5, 2, succ: 2\n"
-    "  6: Phi(0, 4) [4]\n"
+    "BasicBlock 3, pred: 2, 4, succ: 5\n"
+    "  6: Phi(1, 0) [9]\n"
     "  7: Goto\n"
-    "BasicBlock 4\n"
-    // Synthesized blocks to avoid critical edge.
-    "BasicBlock 5, pred: 1, succ: 3\n"
+    "BasicBlock 4, pred: 1, succ: 3\n"
     "  8: Goto\n"
-    "BasicBlock 6, pred: 1, succ: 2\n"
-    "  9: Goto\n";
+    "BasicBlock 5, pred: 3, succ: 6\n"
+    "  9: Return(6)\n"
+    "BasicBlock 6, pred: 5\n"
+    "  10: Exit\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
-    Instruction::IF_EQ, 3,
-    Instruction::GOTO | 0x100,
-    Instruction::GOTO | 0xFF00);
+    Instruction::IF_EQ, 4,
+    Instruction::CONST_4 | 4 << 12 | 0,
+    Instruction::GOTO | 0x200,
+    Instruction::GOTO | 0xFF00,
+    Instruction::RETURN | 0 << 8);
 
   TestCode(data, expected);
 }
diff --git a/compiler/optimizing/ssa_type_propagation.cc b/compiler/optimizing/ssa_type_propagation.cc
index a860cb7..cb5ce20 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,15 +80,22 @@
       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 {
     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
-      HPhi* phi = it.Current()->AsPhi();
-      if (UpdateType(phi)) {
-        AddDependentInstructionsToWorklist(phi);
-      }
+      // Eagerly compute the type of the phi, for quicker convergence. Note
+      // that we don't need to add users to the worklist because we are
+      // doing a reverse post-order visit, therefore either the phi users are
+      // non-loop phi and will be visited later in the visit, or are loop-phis,
+      // and they are already in the work list.
+      UpdateType(it.Current()->AsPhi());
     }
   }
 }
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/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 0ea11ad..3974e53 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -18,9 +18,9 @@
 #define ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_
 
 #include "base/bit_vector.h"
+#include "base/value_object.h"
 #include "memory_region.h"
 #include "stack_map.h"
-#include "utils/allocation.h"
 #include "utils/growable_array.h"
 
 namespace art {
@@ -111,7 +111,7 @@
   }
 
   size_t ComputeStackMapSize() const {
-    return stack_maps_.Size() * (StackMap::kFixedSize + StackMaskEncodingSize(stack_mask_max_));
+    return stack_maps_.Size() * StackMap::ComputeAlignedStackMapSize(stack_mask_max_);
   }
 
   size_t ComputeDexRegisterMapSize() const {
@@ -167,33 +167,33 @@
       }
 
       // Set the register map.
-      MemoryRegion region = dex_register_maps_region.Subregion(
+      MemoryRegion register_region = dex_register_maps_region.Subregion(
           next_dex_register_map_offset,
           DexRegisterMap::kFixedSize + entry.num_dex_registers * DexRegisterMap::SingleEntrySize());
-      next_dex_register_map_offset += region.size();
-      DexRegisterMap dex_register_map(region);
-      stack_map.SetDexRegisterMapOffset(region.start() - memory_start);
+      next_dex_register_map_offset += register_region.size();
+      DexRegisterMap dex_register_map(register_region);
+      stack_map.SetDexRegisterMapOffset(register_region.start() - memory_start);
 
-      for (size_t i = 0; i < entry.num_dex_registers; ++i) {
+      for (size_t j = 0; j < entry.num_dex_registers; ++j) {
         DexRegisterEntry register_entry =
-            dex_register_maps_.Get(i + entry.dex_register_maps_start_index);
-        dex_register_map.SetRegisterInfo(i, register_entry.kind, register_entry.value);
+            dex_register_maps_.Get(j + entry.dex_register_maps_start_index);
+        dex_register_map.SetRegisterInfo(j, register_entry.kind, register_entry.value);
       }
 
       // Set the inlining info.
       if (entry.inlining_depth != 0) {
-        MemoryRegion region = inline_infos_region.Subregion(
+        MemoryRegion inline_region = inline_infos_region.Subregion(
             next_inline_info_offset,
             InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
-        next_inline_info_offset += region.size();
-        InlineInfo inline_info(region);
+        next_inline_info_offset += inline_region.size();
+        InlineInfo inline_info(inline_region);
 
-        stack_map.SetInlineDescriptorOffset(region.start() - memory_start);
+        stack_map.SetInlineDescriptorOffset(inline_region.start() - memory_start);
 
         inline_info.SetDepth(entry.inlining_depth);
-        for (size_t i = 0; i < entry.inlining_depth; ++i) {
-          InlineInfoEntry inline_entry = inline_infos_.Get(i + entry.inline_infos_start_index);
-          inline_info.SetMethodReferenceIndexAtDepth(i, inline_entry.method_index);
+        for (size_t j = 0; j < entry.inlining_depth; ++j) {
+          InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
+          inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
         }
       } else {
         stack_map.SetInlineDescriptorOffset(InlineInfo::kNoInlineInfo);
diff --git a/compiler/output_stream.cc b/compiler/output_stream.cc
new file mode 100644
index 0000000..a8b64ca
--- /dev/null
+++ b/compiler/output_stream.cc
@@ -0,0 +1,31 @@
+/*
+ * 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 "output_stream.h"
+
+namespace art {
+
+std::ostream& operator<<(std::ostream& os, const Whence& rhs) {
+  switch (rhs) {
+    case kSeekSet:     os << "SEEK_SET"; break;
+    case kSeekCurrent: os << "SEEK_CUR"; break;
+    case kSeekEnd:     os << "SEEK_END"; break;
+    default: UNREACHABLE();
+  }
+  return os;
+}
+
+}  // namespace art
diff --git a/compiler/output_stream.h b/compiler/output_stream.h
index 97ccc2c..4d30b83 100644
--- a/compiler/output_stream.h
+++ b/compiler/output_stream.h
@@ -17,9 +17,7 @@
 #ifndef ART_COMPILER_OUTPUT_STREAM_H_
 #define ART_COMPILER_OUTPUT_STREAM_H_
 
-#include <stdint.h>
-#include <sys/types.h>
-
+#include <ostream>
 #include <string>
 
 #include "base/macros.h"
@@ -31,6 +29,7 @@
   kSeekCurrent = SEEK_CUR,
   kSeekEnd = SEEK_END,
 };
+std::ostream& operator<<(std::ostream& os, const Whence& rhs);
 
 class OutputStream {
  public:
diff --git a/compiler/output_stream_test.cc b/compiler/output_stream_test.cc
index 315ca09..bba9892 100644
--- a/compiler/output_stream_test.cc
+++ b/compiler/output_stream_test.cc
@@ -90,7 +90,7 @@
 
 TEST_F(OutputStreamTest, Vector) {
   std::vector<uint8_t> output;
-  VectorOutputStream output_stream("test vector output", output);
+  VectorOutputStream output_stream("test vector output", &output);
   SetOutputStream(output_stream);
   GenerateTestOutput();
   CheckTestOutput(output);
diff --git a/compiler/sea_ir/code_gen/code_gen.cc b/compiler/sea_ir/code_gen/code_gen.cc
deleted file mode 100644
index 8d79c41..0000000
--- a/compiler/sea_ir/code_gen/code_gen.cc
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <llvm/Support/raw_ostream.h>
-
-#include "base/logging.h"
-#include "utils.h"
-
-#include "sea_ir/ir/sea.h"
-#include "sea_ir/code_gen/code_gen.h"
-#include "sea_ir/types/type_inference.h"
-#include "sea_ir/types/types.h"
-
-namespace sea_ir {
-
-void CodeGenPrepassVisitor::Visit(PhiInstructionNode* phi) {
-  Region* r = phi->GetRegion();
-  const std::vector<Region*>* predecessors = r->GetPredecessors();
-  DCHECK(NULL != predecessors);
-  DCHECK_GT(predecessors->size(), 0u);
-  llvm::PHINode *llvm_phi  = llvm_data_->builder_.CreatePHI(
-      llvm::Type::getInt32Ty(*llvm_data_->context_), predecessors->size(), phi->StringId());
-  llvm_data_->AddValue(phi, llvm_phi);
-}
-
-void CodeGenPassVisitor::Initialize(SeaGraph* graph) {
-  Region* root_region;
-  ordered_regions_.clear();
-  for (std::vector<Region*>::const_iterator cit = graph->GetRegions()->begin();
-        cit != graph->GetRegions()->end(); cit++ ) {
-    if ((*cit)->GetIDominator() == (*cit)) {
-      root_region = *cit;
-    }
-  }
-  ordered_regions_.push_back(root_region);
-  for (unsigned int id = 0; id < ordered_regions_.size(); id++) {
-    Region* current_region = ordered_regions_.at(id);
-    const std::set<Region*>* dominated_regions = current_region->GetIDominatedSet();
-    for (std::set<Region*>::const_iterator cit = dominated_regions->begin();
-            cit != dominated_regions->end(); cit++ ) {
-      ordered_regions_.push_back(*cit);
-    }
-  }
-}
-
-void CodeGenPostpassVisitor::Visit(SeaGraph* graph) { }
-void CodeGenVisitor::Visit(SeaGraph* graph) { }
-void CodeGenPrepassVisitor::Visit(SeaGraph* graph) {
-  std::vector<SignatureNode*>* parameters = graph->GetParameterNodes();
-  // TODO: It may be better to extract correct types from dex
-  //       instead than from type inference.
-  DCHECK(parameters != NULL);
-  std::vector<llvm::Type*> parameter_types;
-  for (std::vector<SignatureNode*>::const_iterator param_iterator = parameters->begin();
-      param_iterator!= parameters->end(); param_iterator++) {
-    const Type* param_type = graph->ti_->type_data_.FindTypeOf((*param_iterator)->Id());
-    DCHECK(param_type->Equals(graph->ti_->type_cache_->Integer()))
-      << "Code generation for types other than integer not implemented.";
-    parameter_types.push_back(llvm::Type::getInt32Ty(*llvm_data_->context_));
-  }
-
-  // TODO: Get correct function return type.
-  const Type* return_type = graph->ti_->type_data_.FindTypeOf(-1);
-  DCHECK(return_type->Equals(graph->ti_->type_cache_->Integer()))
-    << "Code generation for types other than integer not implemented.";
-  llvm::FunctionType *function_type = llvm::FunctionType::get(
-      llvm::Type::getInt32Ty(*llvm_data_->context_),
-      parameter_types, false);
-
-  llvm_data_->function_ = llvm::Function::Create(function_type,
-      llvm::Function::ExternalLinkage, function_name_, &llvm_data_->module_);
-  unsigned param_id = 0;
-  for (llvm::Function::arg_iterator arg_it = llvm_data_->function_->arg_begin();
-      param_id != llvm_data_->function_->arg_size(); ++arg_it, ++param_id) {
-    // TODO: The "+1" is because of the Method parameter on position 0.
-    DCHECK(parameters->size() > param_id) << "Insufficient parameters for function signature";
-    // Build parameter register name for LLVM IR clarity.
-    std::string arg_name = art::StringPrintf("r%d", parameters->at(param_id)->GetResultRegister());
-    arg_it->setName(arg_name);
-    SignatureNode* parameter = parameters->at(param_id);
-    llvm_data_->AddValue(parameter, arg_it);
-  }
-
-  std::vector<Region*>* regions = &ordered_regions_;
-  DCHECK_GT(regions->size(), 0u);
-  // Then create all other basic blocks.
-  for (std::vector<Region*>::const_iterator cit = regions->begin(); cit != regions->end(); cit++) {
-    llvm::BasicBlock* new_basic_block = llvm::BasicBlock::Create(*llvm_data_->context_,
-        (*cit)->StringId(), llvm_data_->function_);
-    llvm_data_->AddBlock((*cit), new_basic_block);
-  }
-}
-
-void CodeGenPrepassVisitor::Visit(Region* region) {
-  llvm_data_->builder_.SetInsertPoint(llvm_data_->GetBlock(region));
-}
-void CodeGenPostpassVisitor::Visit(Region* region) {
-  llvm_data_->builder_.SetInsertPoint(llvm_data_->GetBlock(region));
-}
-void CodeGenVisitor::Visit(Region* region) {
-  llvm_data_->builder_.SetInsertPoint(llvm_data_->GetBlock(region));
-}
-
-
-void CodeGenVisitor::Visit(InstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  DCHECK(0);  // This whole function is useful only during development.
-}
-
-void CodeGenVisitor::Visit(UnnamedConstInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "1.Instruction: " << instr << std::endl;
-  llvm_data_->AddValue(instruction,
-      llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt(32, instruction->GetConstValue())));
-}
-
-void CodeGenVisitor::Visit(ConstInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "1.Instruction: " << instr << std::endl;
-  llvm_data_->AddValue(instruction,
-      llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt(32, instruction->GetConstValue())));
-}
-void CodeGenVisitor::Visit(ReturnInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "2.Instruction: " << instr << std::endl;
-  DCHECK_GT(instruction->GetSSAProducers().size(), 0u);
-  llvm::Value* return_value = llvm_data_->GetValue(instruction->GetSSAProducers().at(0));
-  llvm_data_->builder_.CreateRet(return_value);
-}
-void CodeGenVisitor::Visit(IfNeInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "3.Instruction: " << instr << std::endl;
-  std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers();
-  DCHECK_GT(ssa_uses.size(), 1u);
-  InstructionNode* use_l = ssa_uses.at(0);
-  llvm::Value* left = llvm_data_->GetValue(use_l);
-
-  InstructionNode* use_r = ssa_uses.at(1);
-  llvm::Value* right = llvm_data_->GetValue(use_r);
-  llvm::Value* ifne = llvm_data_->builder_.CreateICmpNE(left, right, instruction->StringId());
-  DCHECK(instruction->GetRegion() != NULL);
-  std::vector<Region*>* successors = instruction->GetRegion()->GetSuccessors();
-  DCHECK_GT(successors->size(), 0u);
-  llvm::BasicBlock* then_block = llvm_data_->GetBlock(successors->at(0));
-  llvm::BasicBlock* else_block = llvm_data_->GetBlock(successors->at(1));
-
-  llvm_data_->builder_.CreateCondBr(ifne, then_block, else_block);
-}
-
-/*
-void CodeGenVisitor::Visit(AddIntLitInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "4.Instruction: " << instr << std::endl;
-  std::vector<InstructionNode*> ssa_uses = instruction->GetSSAUses();
-  InstructionNode* use_l = ssa_uses.at(0);
-  llvm::Value* left = llvm_data->GetValue(use_l);
-  llvm::Value* right = llvm::ConstantInt::get(*llvm_data->context_,
-      llvm::APInt(32, instruction->GetConstValue()));
-  llvm::Value* result = llvm_data->builder_.CreateAdd(left, right);
-  llvm_data->AddValue(instruction, result);
-}
-*/
-void CodeGenVisitor::Visit(MoveResultInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "5.Instruction: " << instr << std::endl;
-  // TODO: Currently, this "mov" instruction is simulated by "res = return_register + 0".
-  // This is inefficient, but should be optimized out by the coalescing phase of the reg alloc.
-  // The TODO is to either ensure that this happens, or to
-  // remove the move-result instructions completely from the IR
-  // by merging them with the invoke-* instructions,
-  // since their purpose of minimizing the number of opcodes in dex is
-  // not relevant for the IR. (Will need to have different
-  // instruction subclasses for functions and procedures.)
-  std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers();
-  InstructionNode* use_l = ssa_uses.at(0);
-  llvm::Value* left = llvm_data_->GetValue(use_l);
-  llvm::Value* right = llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt(32, 0));
-  llvm::Value* result = llvm_data_->builder_.CreateAdd(left, right);
-  llvm_data_->AddValue(instruction, result);
-}
-void CodeGenVisitor::Visit(InvokeStaticInstructionNode* invoke) {
-  std::string instr = invoke->GetInstruction()->DumpString(NULL);
-  std::cout << "6.Instruction: " << instr << std::endl;
-  // TODO: Build callee LLVM function name.
-  std::string symbol = "dex_";
-  symbol += art::MangleForJni(PrettyMethod(invoke->GetCalledMethodIndex(), dex_file_));
-  std::string function_name = "dex_int_00020Main_fibonacci_00028int_00029";
-  llvm::Function *callee = llvm_data_->module_.getFunction(function_name);
-  // TODO: Add proper checking of the matching between formal and actual signature.
-  DCHECK(NULL != callee);
-  std::vector<llvm::Value*> parameter_values;
-  std::vector<InstructionNode*> parameter_sources = invoke->GetSSAProducers();
-  // TODO: Replace first parameter with Method argument instead of 0.
-  parameter_values.push_back(llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt(32, 0)));
-  for (std::vector<InstructionNode*>::const_iterator cit = parameter_sources.begin();
-      cit != parameter_sources.end(); ++cit) {
-    llvm::Value* parameter_value = llvm_data_->GetValue((*cit));
-    DCHECK(NULL != parameter_value);
-    parameter_values.push_back(parameter_value);
-  }
-  llvm::Value* return_value = llvm_data_->builder_.CreateCall(callee,
-      parameter_values, invoke->StringId());
-  llvm_data_->AddValue(invoke, return_value);
-}
-void CodeGenVisitor::Visit(AddIntInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "7.Instruction: " << instr << std::endl;
-  std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers();
-  DCHECK_GT(ssa_uses.size(), 1u);
-  InstructionNode* use_l = ssa_uses.at(0);
-  InstructionNode* use_r = ssa_uses.at(1);
-  llvm::Value* left = llvm_data_->GetValue(use_l);
-  llvm::Value* right = llvm_data_->GetValue(use_r);
-  llvm::Value* result = llvm_data_->builder_.CreateAdd(left, right);
-  llvm_data_->AddValue(instruction, result);
-}
-void CodeGenVisitor::Visit(GotoInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "8.Instruction: " << instr << std::endl;
-  std::vector<sea_ir::Region*>* targets = instruction->GetRegion()->GetSuccessors();
-  DCHECK_EQ(targets->size(), 1u);
-  llvm::BasicBlock* target_block = llvm_data_->GetBlock(targets->at(0));
-  llvm_data_->builder_.CreateBr(target_block);
-}
-void CodeGenVisitor::Visit(IfEqzInstructionNode* instruction) {
-  std::string instr = instruction->GetInstruction()->DumpString(NULL);
-  std::cout << "9. Instruction: " << instr << "; Id: " <<instruction << std::endl;
-  std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers();
-  DCHECK_GT(ssa_uses.size(), 0u);
-  InstructionNode* use_l = ssa_uses.at(0);
-  llvm::Value* left = llvm_data_->GetValue(use_l);
-  llvm::Value* ifeqz = llvm_data_->builder_.CreateICmpEQ(left,
-      llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt::getNullValue(32)),
-      instruction->StringId());
-  DCHECK(instruction->GetRegion() != NULL);
-  std::vector<Region*>* successors = instruction->GetRegion()->GetSuccessors();
-  DCHECK_GT(successors->size(), 0u);
-  llvm::BasicBlock* then_block = llvm_data_->GetBlock(successors->at(0));
-  llvm::BasicBlock* else_block = llvm_data_->GetBlock(successors->at(1));
-  llvm_data_->builder_.CreateCondBr(ifeqz, then_block, else_block);
-}
-
-void CodeGenPostpassVisitor::Visit(PhiInstructionNode* phi) {
-  std::cout << "10. Instruction: Phi(" << phi->GetRegisterNumber() << ")" << std::endl;
-  Region* r = phi->GetRegion();
-  const std::vector<Region*>* predecessors = r->GetPredecessors();
-  DCHECK(NULL != predecessors);
-  DCHECK_GT(predecessors->size(), 0u);
-  // Prepass (CodeGenPrepassVisitor) should create the phi function value.
-  llvm::PHINode* llvm_phi = (llvm::PHINode*) llvm_data_->GetValue(phi);
-  int predecessor_pos = 0;
-  for (std::vector<Region*>::const_iterator cit = predecessors->begin();
-      cit != predecessors->end(); ++cit) {
-    std::vector<InstructionNode*>* defining_instructions = phi->GetSSAUses(predecessor_pos++);
-    DCHECK_EQ(defining_instructions->size(), 1u);
-    InstructionNode* defining_instruction = defining_instructions->at(0);
-    DCHECK(NULL != defining_instruction);
-    Region* incoming_region = *cit;
-    llvm::BasicBlock* incoming_basic_block = llvm_data_->GetBlock(incoming_region);
-    llvm::Value* incoming_value = llvm_data_->GetValue(defining_instruction);
-    llvm_phi->addIncoming(incoming_value, incoming_basic_block);
-  }
-}
-
-void CodeGenVisitor::Visit(SignatureNode* signature) {
-  DCHECK_EQ(signature->GetDefinitions().size(), 1u) <<
-      "Signature nodes must correspond to a single parameter register.";
-}
-void CodeGenPrepassVisitor::Visit(SignatureNode* signature) {
-  DCHECK_EQ(signature->GetDefinitions().size(), 1u) <<
-      "Signature nodes must correspond to a single parameter register.";
-}
-void CodeGenPostpassVisitor::Visit(SignatureNode* signature) {
-  DCHECK_EQ(signature->GetDefinitions().size(), 1u) <<
-      "Signature nodes must correspond to a single parameter register.";
-}
-
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/code_gen/code_gen.h b/compiler/sea_ir/code_gen/code_gen.h
deleted file mode 100644
index 544e9f0..0000000
--- a/compiler/sea_ir/code_gen/code_gen.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_SEA_IR_CODE_GEN_CODE_GEN_H_
-#define ART_COMPILER_SEA_IR_CODE_GEN_CODE_GEN_H_
-
-#include "instruction_set.h"
-#include "llvm/Analysis/Verifier.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Analysis/Verifier.h"
-#include "sea_ir/ir/visitor.h"
-
-namespace sea_ir {
-// Abstracts away the containers we use to map SEA IR objects to LLVM IR objects.
-class CodeGenData {
- public:
-  explicit CodeGenData(): context_(&llvm::getGlobalContext()), module_("sea_ir", *context_),
-      builder_(*context_), function_(), blocks_(), values_() { }
-  // Returns the llvm::BasicBlock* corresponding to the sea_ir::Region with id @region_id.
-  llvm::BasicBlock* GetBlock(int region_id) {
-    std::map<int, llvm::BasicBlock*>::iterator block_it = blocks_.find(region_id);
-    DCHECK(block_it != blocks_.end());
-    return block_it->second;
-  }
-  // Returns the llvm::BasicBlock* corresponding top the sea_ir::Region @region.
-  llvm::BasicBlock* GetBlock(Region* region) {
-    return GetBlock(region->Id());
-  }
-  // Records @block as corresponding to the sea_ir::Region with id @region_id.
-  void AddBlock(int region_id, llvm::BasicBlock* block) {
-    blocks_.insert(std::pair<int, llvm::BasicBlock*>(region_id, block));
-  }
-  // Records @block as corresponding to the sea_ir::Region with @region.
-  void AddBlock(Region* region, llvm::BasicBlock* block) {
-    AddBlock(region->Id(), block);
-  }
-
-  llvm::Value* GetValue(int instruction_id) {
-    std::map<int, llvm::Value*>::iterator value_it = values_.find(instruction_id);
-    DCHECK(value_it != values_.end());
-    return value_it->second;
-  }
-  // Returns the llvm::Value* corresponding to the output of @instruction.
-  llvm::Value* GetValue(InstructionNode* instruction) {
-    return GetValue(instruction->Id());
-  }
-  // Records @value as corresponding to the sea_ir::InstructionNode with id @instruction_id.
-  void AddValue(int instruction_id, llvm::Value* value) {
-    values_.insert(std::pair<int, llvm::Value*>(instruction_id, value));
-  }
-  // Records @value as corresponding to the sea_ir::InstructionNode  @instruction.
-  void AddValue(InstructionNode* instruction, llvm::Value* value) {
-      AddValue(instruction->Id(), value);
-  }
-  // Generates and returns in @elf the executable code corresponding to the llvm module
-  //
-  std::string GetElf(art::InstructionSet instruction_set);
-
-  llvm::LLVMContext* const context_;
-  llvm::Module module_;
-  llvm::IRBuilder<> builder_;
-  llvm::Function* function_;
-
- private:
-  std::map<int, llvm::BasicBlock*> blocks_;
-  std::map<int, llvm::Value*> values_;
-};
-
-class CodeGenPassVisitor: public IRVisitor {
- public:
-  explicit CodeGenPassVisitor(CodeGenData* cgd): llvm_data_(cgd) { }
-  CodeGenPassVisitor(): llvm_data_(new CodeGenData()) { }
-  // Initialize any data structure needed before the start of visiting.
-  virtual void Initialize(SeaGraph* graph);
-  CodeGenData* GetData() {
-    return llvm_data_;
-  }
-  void Write(std::string file) {
-      llvm_data_->module_.dump();
-      llvm::verifyFunction(*llvm_data_->function_);
-    }
-
- protected:
-  CodeGenData* const llvm_data_;
-};
-
-class CodeGenPrepassVisitor: public CodeGenPassVisitor {
- public:
-  explicit CodeGenPrepassVisitor(const std::string& function_name):
-    function_name_(function_name) { }
-  void Visit(SeaGraph* graph);
-  void Visit(SignatureNode* region);
-  void Visit(Region* region);
-  void Visit(InstructionNode* instruction) { }
-
-  void Visit(UnnamedConstInstructionNode* instruction) { }
-  void Visit(ConstInstructionNode* instruction) { }
-  void Visit(ReturnInstructionNode* instruction) { }
-  void Visit(IfNeInstructionNode* instruction) { }
-  // void Visit(AddIntLitInstructionNode* instruction) { }
-  void Visit(MoveResultInstructionNode* instruction) { }
-  void Visit(InvokeStaticInstructionNode* instruction) { }
-  void Visit(AddIntInstructionNode* instruction) { }
-  void Visit(GotoInstructionNode* instruction) { }
-  void Visit(IfEqzInstructionNode* instruction) { }
-  void Visit(PhiInstructionNode* region);
-
- private:
-  std::string function_name_;
-};
-
-class CodeGenPostpassVisitor: public CodeGenPassVisitor {
- public:
-  explicit CodeGenPostpassVisitor(CodeGenData* code_gen_data): CodeGenPassVisitor(code_gen_data) { }
-  void Visit(SeaGraph* graph);
-  void Visit(SignatureNode* region);
-  void Visit(Region* region);
-  void Visit(InstructionNode* region) { }
-  void Visit(UnnamedConstInstructionNode* instruction) { }
-  void Visit(ConstInstructionNode* instruction) { }
-  void Visit(ReturnInstructionNode* instruction) { }
-  void Visit(IfNeInstructionNode* instruction) { }
-  // void Visit(AddIntLitInstructionNode* instruction) { }
-  void Visit(MoveResultInstructionNode* instruction) { }
-  void Visit(InvokeStaticInstructionNode* instruction) { }
-  void Visit(AddIntInstructionNode* instruction) { }
-  void Visit(GotoInstructionNode* instruction) { }
-  void Visit(IfEqzInstructionNode* instruction) { }
-  void Visit(PhiInstructionNode* region);
-};
-
-class CodeGenVisitor: public CodeGenPassVisitor {
- public:
-  explicit CodeGenVisitor(CodeGenData* code_gen_data,
-      const art::DexFile& dex_file): CodeGenPassVisitor(code_gen_data), dex_file_(dex_file) { }
-  void Visit(SeaGraph* graph);
-  void Visit(SignatureNode* region);
-  void Visit(Region* region);
-  void Visit(InstructionNode* region);
-  void Visit(UnnamedConstInstructionNode* instruction);
-  void Visit(ConstInstructionNode* instruction);
-  void Visit(ReturnInstructionNode* instruction);
-  void Visit(IfNeInstructionNode* instruction);
-  void Visit(MoveResultInstructionNode* instruction);
-  void Visit(InvokeStaticInstructionNode* instruction);
-  void Visit(AddIntInstructionNode* instruction);
-  void Visit(GotoInstructionNode* instruction);
-  void Visit(IfEqzInstructionNode* instruction);
-  void Visit(PhiInstructionNode* region) { }
-
- private:
-  std::string function_name_;
-  const art::DexFile& dex_file_;
-};
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_CODE_GEN_CODE_GEN_H_
diff --git a/compiler/sea_ir/code_gen/code_gen_data.cc b/compiler/sea_ir/code_gen/code_gen_data.cc
deleted file mode 100644
index 17f64db..0000000
--- a/compiler/sea_ir/code_gen/code_gen_data.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-#include <llvm/PassManager.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/FormattedStream.h>
-#include <llvm/Target/TargetMachine.h>
-#include <llvm/Transforms/IPO.h>
-#include <llvm/Transforms/IPO/PassManagerBuilder.h>
-
-#include "base/logging.h"
-#include "driver/compiler_driver.h"
-#include "sea_ir/ir/sea.h"
-#include "sea_ir/code_gen/code_gen.h"
-
-
-namespace sea_ir {
-std::string CodeGenData::GetElf(art::InstructionSet instruction_set) {
-  std::string elf;
-  ::llvm::raw_string_ostream out_stream(elf);
-  // Lookup the LLVM target
-  std::string target_triple;
-  std::string target_cpu;
-  std::string target_attr;
-  art::CompilerDriver::InstructionSetToLLVMTarget(instruction_set,
-      target_triple, target_cpu, target_attr);
-
-  std::string errmsg;
-  const ::llvm::Target* target =
-    ::llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
-
-  CHECK(target != NULL) << errmsg;
-
-  // Target options
-  ::llvm::TargetOptions target_options;
-  target_options.FloatABIType = ::llvm::FloatABI::Soft;
-  target_options.NoFramePointerElim = true;
-  target_options.NoFramePointerElimNonLeaf = true;
-  target_options.UseSoftFloat = false;
-  target_options.EnableFastISel = false;
-
-  // Create the ::llvm::TargetMachine
-  ::llvm::OwningPtr< ::llvm::TargetMachine> target_machine(
-    target->createTargetMachine(target_triple, target_cpu, target_attr, target_options,
-                                ::llvm::Reloc::Static, ::llvm::CodeModel::Small,
-                                ::llvm::CodeGenOpt::Aggressive));
-
-  CHECK(target_machine.get() != NULL) << "Failed to create target machine";
-
-  // Add target data
-  const ::llvm::DataLayout* data_layout = target_machine->getDataLayout();
-
-  // PassManager for code generation passes
-  ::llvm::PassManager pm;
-  pm.add(new ::llvm::DataLayout(*data_layout));
-
-  // FunctionPassManager for optimization pass
-  ::llvm::FunctionPassManager fpm(&module_);
-  fpm.add(new ::llvm::DataLayout(*data_layout));
-
-  // Add optimization pass
-  ::llvm::PassManagerBuilder pm_builder;
-  // TODO: Use inliner after we can do IPO.
-  pm_builder.Inliner = NULL;
-  // pm_builder.Inliner = ::llvm::createFunctionInliningPass();
-  // pm_builder.Inliner = ::llvm::createAlwaysInlinerPass();
-  // pm_builder.Inliner = ::llvm::createPartialInliningPass();
-  pm_builder.OptLevel = 3;
-  pm_builder.DisableSimplifyLibCalls = 1;
-  pm_builder.DisableUnitAtATime = 1;
-  pm_builder.populateFunctionPassManager(fpm);
-  pm_builder.populateModulePassManager(pm);
-  pm.add(::llvm::createStripDeadPrototypesPass());
-  // Add passes to emit ELF image
-  {
-    ::llvm::formatted_raw_ostream formatted_os(out_stream, false);
-    // Ask the target to add backend passes as necessary.
-    if (target_machine->addPassesToEmitFile(pm,
-                                            formatted_os,
-                                            ::llvm::TargetMachine::CGFT_ObjectFile,
-                                            true)) {
-      LOG(FATAL) << "Unable to generate ELF for this target";
-    }
-
-    // Run the code generation passes
-    pm.run(module_);
-  }
-  return elf;
-}
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/debug/dot_gen.cc b/compiler/sea_ir/debug/dot_gen.cc
deleted file mode 100644
index 9442684..0000000
--- a/compiler/sea_ir/debug/dot_gen.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "scoped_thread_state_change.h"
-#include "sea_ir/debug/dot_gen.h"
-
-namespace sea_ir {
-
-void DotGenerationVisitor::Initialize(SeaGraph* graph) {
-  graph_ = graph;
-  Region* root_region;
-  ordered_regions_.clear();
-  for (std::vector<Region*>::const_iterator cit = graph->GetRegions()->begin();
-      cit != graph->GetRegions()->end(); cit++ ) {
-    if ((*cit)->GetIDominator() == (*cit)) {
-      root_region = *cit;
-    }
-  }
-  ordered_regions_.push_back(root_region);
-  for (unsigned int id = 0; id < ordered_regions_.size(); id++) {
-    Region* current_region = ordered_regions_.at(id);
-    const std::set<Region*>* dominated_regions = current_region->GetIDominatedSet();
-    for (std::set<Region*>::const_iterator cit = dominated_regions->begin();
-        cit != dominated_regions->end(); cit++ ) {
-      ordered_regions_.push_back(*cit);
-    }
-  }
-}
-
-void DotGenerationVisitor::ToDotSSAEdges(InstructionNode* instruction) {
-  std::map<int, InstructionNode*>* definition_edges = instruction->GetSSAProducersMap();
-  // SSA definitions:
-  for (std::map<int, InstructionNode*>::const_iterator
-      def_it = definition_edges->begin();
-      def_it != definition_edges->end(); def_it++) {
-    if (NULL != def_it->second) {
-      dot_text_ += def_it->second->StringId() + " -> ";
-      dot_text_ += instruction->StringId() + "[color=gray,label=\"";
-      dot_text_ += art::StringPrintf("vR = %d", def_it->first);
-      art::SafeMap<int, const Type*>::const_iterator type_it = types_->find(def_it->second->Id());
-      if (type_it != types_->end()) {
-        art::ScopedObjectAccess soa(art::Thread::Current());
-        dot_text_ += "(" + type_it->second->Dump() + ")";
-      } else {
-        dot_text_ += "()";
-      }
-      dot_text_ += "\"] ; // SSA edge\n";
-    }
-  }
-
-  // SSA used-by:
-  if (options_->WillSaveUseEdges()) {
-    std::vector<InstructionNode*>* used_in = instruction->GetSSAConsumers();
-    for (std::vector<InstructionNode*>::const_iterator cit = used_in->begin();
-        cit != used_in->end(); cit++) {
-      dot_text_ += (*cit)->StringId() + " -> " + instruction->StringId() + "[color=gray,label=\"";
-      dot_text_ += "\"] ; // SSA used-by edge\n";
-    }
-  }
-}
-
-void DotGenerationVisitor::ToDotSSAEdges(PhiInstructionNode* instruction) {
-  std::vector<InstructionNode*> definition_edges = instruction->GetSSAProducers();
-  // SSA definitions:
-  for (std::vector<InstructionNode*>::const_iterator
-      def_it = definition_edges.begin();
-      def_it != definition_edges.end(); def_it++) {
-    if (NULL != *def_it) {
-      dot_text_ += (*def_it)->StringId() + " -> ";
-      dot_text_ += instruction->StringId() + "[color=gray,label=\"";
-      dot_text_ += art::StringPrintf("vR = %d", instruction->GetRegisterNumber());
-      art::SafeMap<int, const Type*>::const_iterator type_it = types_->find((*def_it)->Id());
-      if (type_it != types_->end()) {
-        art::ScopedObjectAccess soa(art::Thread::Current());
-        dot_text_ += "(" + type_it->second->Dump() + ")";
-      } else {
-        dot_text_ += "()";
-      }
-      dot_text_ += "\"] ; // SSA edge\n";
-    }
-  }
-
-  // SSA used-by:
-  if (options_->WillSaveUseEdges()) {
-    std::vector<InstructionNode*>* used_in = instruction->GetSSAConsumers();
-    for (std::vector<InstructionNode*>::const_iterator cit = used_in->begin();
-        cit != used_in->end(); cit++) {
-      dot_text_ += (*cit)->StringId() + " -> " + instruction->StringId() + "[color=gray,label=\"";
-      dot_text_ += "\"] ; // SSA used-by edge\n";
-    }
-  }
-}
-
-void DotGenerationVisitor::Visit(SignatureNode* parameter) {
-  dot_text_ += parameter->StringId() +" [label=\"[" + parameter->StringId() + "] signature:";
-  dot_text_ += art::StringPrintf("r%d", parameter->GetResultRegister());
-  dot_text_ += "\"] // signature node\n";
-  ToDotSSAEdges(parameter);
-}
-
-// Appends to @result a dot language formatted string representing the node and
-//    (by convention) outgoing edges, so that the composition of theToDot() of all nodes
-//    builds a complete dot graph (without prolog and epilog though).
-void DotGenerationVisitor::Visit(Region* region) {
-  dot_text_ += "\n// Region: \nsubgraph " + region->StringId();
-  dot_text_ += " { label=\"region " + region->StringId() + "(rpo=";
-  dot_text_ += art::StringPrintf("%d", region->GetRPO());
-  if (NULL != region->GetIDominator()) {
-    dot_text_ += " dom=" + region->GetIDominator()->StringId();
-  }
-  dot_text_ += ")\";\n";
-
-  std::vector<PhiInstructionNode*>* phi_instructions = region->GetPhiNodes();
-  for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions->begin();
-        cit != phi_instructions->end(); cit++) {
-    dot_text_ += (*cit)->StringId() +";\n";
-  }
-  std::vector<InstructionNode*>* instructions = region->GetInstructions();
-  for (std::vector<InstructionNode*>::const_iterator cit = instructions->begin();
-        cit != instructions->end(); cit++) {
-      dot_text_ += (*cit)->StringId() +";\n";
-    }
-
-  dot_text_ += "} // End Region.\n";
-  std::vector<Region*>* successors =  region->GetSuccessors();
-  for (std::vector<Region*>::const_iterator cit = successors->begin(); cit != successors->end();
-      cit++) {
-    DCHECK(NULL != *cit) << "Null successor found for SeaNode" <<
-        region->GetLastChild()->StringId() << ".";
-    dot_text_ += region->GetLastChild()->StringId() + " -> " +
-        (*cit)->GetLastChild()->StringId() +
-        "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + region->StringId() + "];\n\n";
-  }
-}
-void DotGenerationVisitor::Visit(InstructionNode* instruction) {
-  dot_text_ += "// Instruction ("+instruction->StringId()+"): \n" + instruction->StringId() +
-      " [label=\"[" + instruction->StringId() + "] " +
-      instruction->GetInstruction()->DumpString(graph_->GetDexFile()) + "\"";
-  dot_text_ += "];\n";
-  ToDotSSAEdges(instruction);
-}
-
-void DotGenerationVisitor::Visit(UnnamedConstInstructionNode* instruction) {
-  dot_text_ += "// Instruction ("+instruction->StringId()+"): \n" + instruction->StringId() +
-        " [label=\"[" + instruction->StringId() + "] const/x v-3, #" +
-        art::StringPrintf("%d", instruction->GetConstValue()) + "\"";
-  dot_text_ += "];\n";
-  ToDotSSAEdges(instruction);
-}
-
-void DotGenerationVisitor::Visit(PhiInstructionNode* phi) {
-  dot_text_ += "// PhiInstruction: \n" + phi->StringId() +
-      " [label=\"[" + phi->StringId() + "] PHI(";
-  dot_text_ += art::StringPrintf("%d", phi->GetRegisterNumber());
-  dot_text_ += ")\"";
-  dot_text_ += "];\n";
-  ToDotSSAEdges(phi);
-}
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/debug/dot_gen.h b/compiler/sea_ir/debug/dot_gen.h
deleted file mode 100644
index a5d6819..0000000
--- a/compiler/sea_ir/debug/dot_gen.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_
-#define ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_
-
-#include "safe_map.h"
-#include "base/stringprintf.h"
-#include "file_output_stream.h"
-#include "os.h"
-#include "sea_ir/ir/sea.h"
-#include "sea_ir/types/type_inference.h"
-
-namespace sea_ir {
-
-class DotConversionOptions {
- public:
-  DotConversionOptions(): save_use_edges_(false) { }
-  bool WillSaveUseEdges() const {
-    return save_use_edges_;
-  }
- private:
-  bool save_use_edges_;
-};
-
-class DotGenerationVisitor: public IRVisitor {
- public:
-  explicit DotGenerationVisitor(const DotConversionOptions* const options,
-      art::SafeMap<int, const Type*>* types): graph_(), types_(types), options_(options) { }
-
-  virtual void Initialize(SeaGraph* graph);
-  // Saves the ssa def->use edges corresponding to @instruction.
-  void ToDotSSAEdges(InstructionNode* instruction);
-  void ToDotSSAEdges(PhiInstructionNode* instruction);
-  void Visit(SeaGraph* graph) {
-    dot_text_ += "digraph seaOfNodes {\ncompound=true\n";
-  }
-  void Visit(SignatureNode* parameter);
-
-  // Appends to @result a dot language formatted string representing the node and
-  //    (by convention) outgoing edges, so that the composition of theToDot() of all nodes
-  //    builds a complete dot graph (without prolog and epilog though).
-  void Visit(Region* region);
-  void Visit(InstructionNode* instruction);
-  void Visit(PhiInstructionNode* phi);
-  void Visit(UnnamedConstInstructionNode* instruction);
-
-  void Visit(ConstInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(ReturnInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(IfNeInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(MoveResultInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(InvokeStaticInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(AddIntInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(GotoInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-  void Visit(IfEqzInstructionNode* instruction) {
-    Visit(reinterpret_cast<InstructionNode*>(instruction));
-  }
-
-  std::string GetResult() const {
-    return dot_text_;
-  }
-
- private:
-  std::string dot_text_;
-  SeaGraph* graph_;
-  art::SafeMap<int, const Type*>* types_;
-  const DotConversionOptions* const options_;
-};
-
-// Stores options for turning a SEA IR graph to a .dot file.
-class DotConversion {
- public:
-  DotConversion(): options_() { }
-  // Saves to @filename the .dot representation of @graph with the options @options.
-  void DumpSea(SeaGraph* graph, std::string filename,
-      art::SafeMap<int, const Type*>* types) const {
-    LOG(INFO) << "Starting to write SEA string to file " << filename << std::endl;
-    DotGenerationVisitor dgv = DotGenerationVisitor(&options_, types);
-    graph->Accept(&dgv);
-    // TODO: std::unique_ptr to close file properly. Switch to BufferedOutputStream.
-    art::File* file = art::OS::CreateEmptyFile(filename.c_str());
-    art::FileOutputStream fos(file);
-    std::string graph_as_string = dgv.GetResult();
-    graph_as_string += "}";
-    fos.WriteFully(graph_as_string.c_str(), graph_as_string.size());
-    LOG(INFO) << "Written SEA string to file.";
-  }
-
- private:
-  DotConversionOptions options_;
-};
-
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_
diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc
deleted file mode 100644
index b57007b..0000000
--- a/compiler/sea_ir/frontend.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef ART_SEA_IR_MODE
-#include <llvm/Support/Threading.h>
-#include <llvm/Support/raw_ostream.h>
-#include <llvm/Bitcode/ReaderWriter.h>
-
-#include "base/logging.h"
-#include "llvm/llvm_compilation_unit.h"
-#include "dex/portable/mir_to_gbc.h"
-#include "driver/compiler_driver.h"
-#include "verifier/method_verifier.h"
-#include "mirror/object.h"
-#include "utils.h"
-
-#include "runtime.h"
-#include "safe_map.h"
-
-#include "sea_ir/ir/sea.h"
-#include "sea_ir/debug/dot_gen.h"
-#include "sea_ir/types/types.h"
-#include "sea_ir/code_gen/code_gen.h"
-
-namespace art {
-
-static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler,
-                                     CompilerBackend* compiler_backend,
-                                     const DexFile::CodeItem* code_item,
-                                     uint32_t method_access_flags, InvokeType invoke_type,
-                                     uint16_t class_def_idx, uint32_t method_idx,
-                                     jobject class_loader, const DexFile& dex_file,
-                                     void* llvm_compilation_unit) {
-  LOG(INFO) << "Compiling " << PrettyMethod(method_idx, dex_file) << ".";
-  sea_ir::SeaGraph* ir_graph = sea_ir::SeaGraph::GetGraph(dex_file);
-  std::string symbol = "dex_" + MangleForJni(PrettyMethod(method_idx, dex_file));
-  sea_ir::CodeGenData* llvm_data = ir_graph->CompileMethod(symbol,
-          code_item, class_def_idx, method_idx, method_access_flags, dex_file);
-  sea_ir::DotConversion dc;
-  SafeMap<int, const sea_ir::Type*>*  types = ir_graph->ti_->GetTypeMap();
-  dc.DumpSea(ir_graph, "/tmp/temp.dot", types);
-  MethodReference mref(&dex_file, method_idx);
-  std::string llvm_code = llvm_data->GetElf(compiler.GetInstructionSet());
-  CompiledMethod* compiled_method =
-      new CompiledMethod(compiler, compiler.GetInstructionSet(), llvm_code,
-                         *compiler.GetVerifiedMethodsData()->GetDexGcMap(mref), symbol);
-  LOG(INFO) << "Compiled SEA IR method " << PrettyMethod(method_idx, dex_file) << ".";
-  return compiled_method;
-}
-
-CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler,
-                                 CompilerBackend* backend,
-                                 const DexFile::CodeItem* code_item,
-                                 uint32_t method_access_flags,
-                                 InvokeType invoke_type,
-                                 uint16_t class_def_idx,
-                                 uint32_t method_idx,
-                                 jobject class_loader,
-                                 const DexFile& dex_file,
-                                 void* llvm_compilation_unit) {
-  return CompileMethodWithSeaIr(compiler, backend, code_item, method_access_flags, invoke_type,
-      class_def_idx, method_idx, class_loader, dex_file, llvm_compilation_unit);
-}
-
-extern "C" art::CompiledMethod*
-    SeaIrCompileMethod(art::CompilerDriver& compiler,
-                          const art::DexFile::CodeItem* code_item,
-                          uint32_t method_access_flags, art::InvokeType invoke_type,
-                          uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
-                          const art::DexFile& dex_file) {
-  // TODO: Check method fingerprint here to determine appropriate backend type.
-  //       Until then, use build default
-  art::CompilerBackend* backend = compiler.GetCompilerBackend();
-  return art::SeaIrCompileOneMethod(compiler, backend, code_item, method_access_flags, invoke_type,
-                               class_def_idx, method_idx, class_loader, dex_file,
-                               NULL /* use thread llvm_info */);
-}
-#endif
-
-}  // namespace art
diff --git a/compiler/sea_ir/ir/instruction_nodes.h b/compiler/sea_ir/ir/instruction_nodes.h
deleted file mode 100644
index 63e89e7..0000000
--- a/compiler/sea_ir/ir/instruction_nodes.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_SEA_IR_IR_INSTRUCTION_NODES_H_
-#define ART_COMPILER_SEA_IR_IR_INSTRUCTION_NODES_H_
-#include "dex_instruction-inl.h"
-#include "sea_ir/ir/sea_node.h"
-#include "sea_ir/ir/visitor.h"
-
-
-namespace sea_ir {
-
-enum SpecialRegisters {
-  NO_REGISTER = -1,             // Usually signifies that there is no register
-                                // that respects the condition you asked for.
-  RETURN_REGISTER = -2,         // Written by the invoke* instructions, read by move-results.
-  UNNAMED_CONST_REGISTER = -3   // Written by UnnamedConst* instructions, read by *Lit* instruction.
-};
-
-class IRVisitor;
-
-// This class represents an instruction in SEA IR.
-// As we add support for specific classes of instructions,
-// the number of InstructionNode objects should dwindle, while the
-// number of subclasses and instances of subclasses will go up.
-class InstructionNode: public SeaNode {
- public:
-  static std::vector<sea_ir::InstructionNode*> Create(const art::Instruction* in);
-  // Returns the Dalvik instruction around which this InstructionNode is wrapped.
-  const art::Instruction* GetInstruction() const {
-    DCHECK(NULL != instruction_) << "Tried to access NULL instruction in an InstructionNode.";
-    return instruction_;
-  }
-  // Returns the register that is defined by the current instruction, or NO_REGISTER otherwise.
-  virtual int GetResultRegister() const;
-  // Returns the set of registers defined by the current instruction.
-  virtual std::vector<int> GetDefinitions() const;
-  // Returns the set of register numbers that are used by the instruction.
-  virtual std::vector<int> GetUses() const;
-  // Mark the current instruction as a downward exposed definition.
-  void MarkAsDEDef();
-  // Rename the use of @reg_no to refer to the instruction @definition,
-  // essentially creating SSA form.
-  void RenameToSSA(int reg_no, InstructionNode* definition) {
-    definition_edges_.insert(std::pair<int, InstructionNode*>(reg_no, definition));
-    DCHECK(NULL != definition) << "SSA definition for register " << reg_no
-        << " used in instruction " << Id() << " not found.";
-    definition->AddSSAUse(this);
-  }
-  // Returns the ordered set of Instructions that define the input operands of this instruction.
-  // Precondition: SeaGraph.ConvertToSSA().
-  virtual std::vector<InstructionNode*> GetSSAProducers() {
-    std::vector<int> uses = GetUses();
-    std::vector<InstructionNode*> ssa_uses;
-    for (std::vector<int>::const_iterator cit = uses.begin(); cit != uses.end(); cit++) {
-      ssa_uses.push_back((*definition_edges_.find(*cit)).second);
-    }
-    return ssa_uses;
-  }
-  std::map<int, InstructionNode* >* GetSSAProducersMap() {
-    return &definition_edges_;
-  }
-  std::vector<InstructionNode*>* GetSSAConsumers() {
-    return &used_in_;
-  }
-  virtual void AddSSAUse(InstructionNode* use) {
-    used_in_.push_back(use);
-  }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-  // Set the region to which this instruction belongs.
-  Region* GetRegion() {
-    DCHECK(NULL != region_);
-    return region_;
-  }
-  // Get the region to which this instruction belongs.
-  void SetRegion(Region* region) {
-    region_ = region;
-  }
-
- protected:
-  explicit InstructionNode(const art::Instruction* in):
-      SeaNode(), instruction_(in), used_in_(), de_def_(false), region_(NULL) { }
-
- protected:
-  const art::Instruction* const instruction_;
-  std::map<int, InstructionNode* > definition_edges_;  // Maps used registers to their definitions.
-  // Stores pointers to instructions that use the result of the current instruction.
-  std::vector<InstructionNode*> used_in_;
-  bool de_def_;
-  Region* region_;
-};
-
-class ConstInstructionNode: public InstructionNode {
- public:
-  explicit ConstInstructionNode(const art::Instruction* inst):
-      InstructionNode(inst) { }
-
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-
-  virtual int32_t GetConstValue() const {
-    return GetInstruction()->VRegB_11n();
-  }
-};
-
-class UnnamedConstInstructionNode: public ConstInstructionNode {
- public:
-  explicit UnnamedConstInstructionNode(const art::Instruction* inst, int32_t value):
-      ConstInstructionNode(inst), value_(value) { }
-
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-
-  int GetResultRegister() const {
-    return UNNAMED_CONST_REGISTER;
-  }
-
-  int32_t GetConstValue() const {
-    return value_;
-  }
-
- private:
-  const int32_t value_;
-};
-
-class ReturnInstructionNode: public InstructionNode {
- public:
-  explicit ReturnInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-
-class IfNeInstructionNode: public InstructionNode {
- public:
-  explicit IfNeInstructionNode(const art::Instruction* inst): InstructionNode(inst) {
-    DCHECK(InstructionTools::IsDefinition(inst) == false);
-  }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-
-
-
-class MoveResultInstructionNode: public InstructionNode {
- public:
-  explicit MoveResultInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
-  std::vector<int> GetUses() const {
-    std::vector<int> uses;  // Using vector<> instead of set<> because order matters.
-    uses.push_back(RETURN_REGISTER);
-    return uses;
-  }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-
-class InvokeStaticInstructionNode: public InstructionNode {
- public:
-  explicit InvokeStaticInstructionNode(const art::Instruction* inst): InstructionNode(inst),
-    method_index_(inst->VRegB_35c()) { }
-  int GetResultRegister() const {
-    return RETURN_REGISTER;
-  }
-
-  int GetCalledMethodIndex() const {
-    return method_index_;
-  }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-
- private:
-  const uint32_t method_index_;
-};
-
-class AddIntInstructionNode: public InstructionNode {
- public:
-  explicit AddIntInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-
-class AddIntLitInstructionNode: public AddIntInstructionNode {
- public:
-  explicit AddIntLitInstructionNode(const art::Instruction* inst):
-      AddIntInstructionNode(inst) { }
-
-  std::vector<int> GetUses() const {
-    std::vector<int> uses =  AddIntInstructionNode::GetUses();
-    uses.push_back(UNNAMED_CONST_REGISTER);
-    return uses;
-    }
-
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-
-class GotoInstructionNode: public InstructionNode {
- public:
-  explicit GotoInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-
-class IfEqzInstructionNode: public InstructionNode {
- public:
-  explicit IfEqzInstructionNode(const art::Instruction* inst): InstructionNode(inst) {
-    DCHECK(InstructionTools::IsDefinition(inst) == false);
-  }
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-};
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_IR_INSTRUCTION_NODES_H_
diff --git a/compiler/sea_ir/ir/instruction_tools.cc b/compiler/sea_ir/ir/instruction_tools.cc
deleted file mode 100644
index 143209d..0000000
--- a/compiler/sea_ir/ir/instruction_tools.cc
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "sea_ir/ir/instruction_tools.h"
-
-namespace sea_ir {
-
-bool InstructionTools::IsDefinition(const art::Instruction* const instruction) {
-  if (0 != (InstructionTools::instruction_attributes_[instruction->Opcode()] & (1 << kDA))) {
-    return true;
-  }
-  return false;
-}
-
-const int InstructionTools::instruction_attributes_[] = {
-  // 00 NOP
-  DF_NOP,
-
-  // 01 MOVE vA, vB
-  DF_DA | DF_UB | DF_IS_MOVE,
-
-  // 02 MOVE_FROM16 vAA, vBBBB
-  DF_DA | DF_UB | DF_IS_MOVE,
-
-  // 03 MOVE_16 vAAAA, vBBBB
-  DF_DA | DF_UB | DF_IS_MOVE,
-
-  // 04 MOVE_WIDE vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_IS_MOVE,
-
-  // 05 MOVE_WIDE_FROM16 vAA, vBBBB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_IS_MOVE,
-
-  // 06 MOVE_WIDE_16 vAAAA, vBBBB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_IS_MOVE,
-
-  // 07 MOVE_OBJECT vA, vB
-  DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE | DF_REF_A | DF_REF_B,
-
-  // 08 MOVE_OBJECT_FROM16 vAA, vBBBB
-  DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE | DF_REF_A | DF_REF_B,
-
-  // 09 MOVE_OBJECT_16 vAAAA, vBBBB
-  DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE | DF_REF_A | DF_REF_B,
-
-  // 0A MOVE_RESULT vAA
-  DF_DA,
-
-  // 0B MOVE_RESULT_WIDE vAA
-  DF_DA | DF_A_WIDE,
-
-  // 0C MOVE_RESULT_OBJECT vAA
-  DF_DA | DF_REF_A,
-
-  // 0D MOVE_EXCEPTION vAA
-  DF_DA | DF_REF_A | DF_NON_NULL_DST,
-
-  // 0E RETURN_VOID
-  DF_NOP,
-
-  // 0F RETURN vAA
-  DF_UA,
-
-  // 10 RETURN_WIDE vAA
-  DF_UA | DF_A_WIDE,
-
-  // 11 RETURN_OBJECT vAA
-  DF_UA | DF_REF_A,
-
-  // 12 CONST_4 vA, #+B
-  DF_DA | DF_SETS_CONST,
-
-  // 13 CONST_16 vAA, #+BBBB
-  DF_DA | DF_SETS_CONST,
-
-  // 14 CONST vAA, #+BBBBBBBB
-  DF_DA | DF_SETS_CONST,
-
-  // 15 CONST_HIGH16 VAA, #+BBBB0000
-  DF_DA | DF_SETS_CONST,
-
-  // 16 CONST_WIDE_16 vAA, #+BBBB
-  DF_DA | DF_A_WIDE | DF_SETS_CONST,
-
-  // 17 CONST_WIDE_32 vAA, #+BBBBBBBB
-  DF_DA | DF_A_WIDE | DF_SETS_CONST,
-
-  // 18 CONST_WIDE vAA, #+BBBBBBBBBBBBBBBB
-  DF_DA | DF_A_WIDE | DF_SETS_CONST,
-
-  // 19 CONST_WIDE_HIGH16 vAA, #+BBBB000000000000
-  DF_DA | DF_A_WIDE | DF_SETS_CONST,
-
-  // 1A CONST_STRING vAA, string@BBBB
-  DF_DA | DF_REF_A | DF_NON_NULL_DST,
-
-  // 1B CONST_STRING_JUMBO vAA, string@BBBBBBBB
-  DF_DA | DF_REF_A | DF_NON_NULL_DST,
-
-  // 1C CONST_CLASS vAA, type@BBBB
-  DF_DA | DF_REF_A | DF_NON_NULL_DST,
-
-  // 1D MONITOR_ENTER vAA
-  DF_UA | DF_NULL_CHK_0 | DF_REF_A,
-
-  // 1E MONITOR_EXIT vAA
-  DF_UA | DF_NULL_CHK_0 | DF_REF_A,
-
-  // 1F CHK_CAST vAA, type@BBBB
-  DF_UA | DF_REF_A | DF_UMS,
-
-  // 20 INSTANCE_OF vA, vB, type@CCCC
-  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,
-
-  // 22 NEW_INSTANCE vAA, type@BBBB
-  DF_DA | DF_NON_NULL_DST | DF_REF_A | DF_UMS,
-
-  // 23 NEW_ARRAY vA, vB, type@CCCC
-  DF_DA | DF_UB | DF_NON_NULL_DST | DF_REF_A | DF_CORE_B | DF_UMS,
-
-  // 24 FILLED_NEW_ARRAY {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_NON_NULL_RET | DF_UMS,
-
-  // 25 FILLED_NEW_ARRAY_RANGE {vCCCC .. vNNNN}, type@BBBB
-  DF_FORMAT_3RC | DF_NON_NULL_RET | DF_UMS,
-
-  // 26 FILL_ARRAY_DATA vAA, +BBBBBBBB
-  DF_UA | DF_REF_A | DF_UMS,
-
-  // 27 THROW vAA
-  DF_UA | DF_REF_A | DF_UMS,
-
-  // 28 GOTO
-  DF_NOP,
-
-  // 29 GOTO_16
-  DF_NOP,
-
-  // 2A GOTO_32
-  DF_NOP,
-
-  // 2B PACKED_SWITCH vAA, +BBBBBBBB
-  DF_UA,
-
-  // 2C SPARSE_SWITCH vAA, +BBBBBBBB
-  DF_UA,
-
-  // 2D CMPL_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C | DF_CORE_A,
-
-  // 2E CMPG_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C | DF_CORE_A,
-
-  // 2F CMPL_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_B | DF_FP_C | DF_CORE_A,
-
-  // 30 CMPG_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_B | DF_FP_C | DF_CORE_A,
-
-  // 31 CMP_LONG vAA, vBB, vCC
-  DF_DA | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 32 IF_EQ vA, vB, +CCCC
-  DF_UA | DF_UB,
-
-  // 33 IF_NE vA, vB, +CCCC
-  DF_UA | DF_UB,
-
-  // 34 IF_LT vA, vB, +CCCC
-  DF_UA | DF_UB,
-
-  // 35 IF_GE vA, vB, +CCCC
-  DF_UA | DF_UB,
-
-  // 36 IF_GT vA, vB, +CCCC
-  DF_UA | DF_UB,
-
-  // 37 IF_LE vA, vB, +CCCC
-  DF_UA | DF_UB,
-
-  // 38 IF_EQZ vAA, +BBBB
-  DF_UA,
-
-  // 39 IF_NEZ vAA, +BBBB
-  DF_UA,
-
-  // 3A IF_LTZ vAA, +BBBB
-  DF_UA,
-
-  // 3B IF_GEZ vAA, +BBBB
-  DF_UA,
-
-  // 3C IF_GTZ vAA, +BBBB
-  DF_UA,
-
-  // 3D IF_LEZ vAA, +BBBB
-  DF_UA,
-
-  // 3E UNUSED_3E
-  DF_NOP,
-
-  // 3F UNUSED_3F
-  DF_NOP,
-
-  // 40 UNUSED_40
-  DF_NOP,
-
-  // 41 UNUSED_41
-  DF_NOP,
-
-  // 42 UNUSED_42
-  DF_NOP,
-
-  // 43 UNUSED_43
-  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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 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,
-
-  // 52 IGET vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // 53 IGET_WIDE vA, vB, field@CCCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // 54 IGET_OBJECT vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B,
-
-  // 55 IGET_BOOLEAN vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // 56 IGET_BYTE vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // 57 IGET_CHAR vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // 58 IGET_SHORT vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // 59 IPUT vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
-
-  // 5A IPUT_WIDE vA, vB, field@CCCC
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B,
-
-  // 5B IPUT_OBJECT vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B,
-
-  // 5C IPUT_BOOLEAN vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
-
-  // 5D IPUT_BYTE vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
-
-  // 5E IPUT_CHAR vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
-
-  // 5F IPUT_SHORT vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
-
-  // 60 SGET vAA, field@BBBB
-  DF_DA | DF_UMS,
-
-  // 61 SGET_WIDE vAA, field@BBBB
-  DF_DA | DF_A_WIDE | DF_UMS,
-
-  // 62 SGET_OBJECT vAA, field@BBBB
-  DF_DA | DF_REF_A | DF_UMS,
-
-  // 63 SGET_BOOLEAN vAA, field@BBBB
-  DF_DA | DF_UMS,
-
-  // 64 SGET_BYTE vAA, field@BBBB
-  DF_DA | DF_UMS,
-
-  // 65 SGET_CHAR vAA, field@BBBB
-  DF_DA | DF_UMS,
-
-  // 66 SGET_SHORT vAA, field@BBBB
-  DF_DA | DF_UMS,
-
-  // 67 SPUT vAA, field@BBBB
-  DF_UA | DF_UMS,
-
-  // 68 SPUT_WIDE vAA, field@BBBB
-  DF_UA | DF_A_WIDE | DF_UMS,
-
-  // 69 SPUT_OBJECT vAA, field@BBBB
-  DF_UA | DF_REF_A | DF_UMS,
-
-  // 6A SPUT_BOOLEAN vAA, field@BBBB
-  DF_UA | DF_UMS,
-
-  // 6B SPUT_BYTE vAA, field@BBBB
-  DF_UA | DF_UMS,
-
-  // 6C SPUT_CHAR vAA, field@BBBB
-  DF_UA | DF_UMS,
-
-  // 6D SPUT_SHORT vAA, field@BBBB
-  DF_UA | DF_UMS,
-
-  // 6E INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 6F INVOKE_SUPER {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 70 INVOKE_DIRECT {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 71 INVOKE_STATIC {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_UMS,
-
-  // 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 73 UNUSED_73
-  DF_NOP,
-
-  // 74 INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 75 INVOKE_SUPER_RANGE {vCCCC .. vNNNN}
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 76 INVOKE_DIRECT_RANGE {vCCCC .. vNNNN}
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 77 INVOKE_STATIC_RANGE {vCCCC .. vNNNN}
-  DF_FORMAT_3RC | DF_UMS,
-
-  // 78 INVOKE_INTERFACE_RANGE {vCCCC .. vNNNN}
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // 79 UNUSED_79
-  DF_NOP,
-
-  // 7A UNUSED_7A
-  DF_NOP,
-
-  // 7B NEG_INT vA, vB
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // 7C NOT_INT vA, vB
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // 7D NEG_LONG vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // 7E NOT_LONG vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // 7F NEG_FLOAT vA, vB
-  DF_DA | DF_UB | DF_FP_A | DF_FP_B,
-
-  // 80 NEG_DOUBLE vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // 81 INT_TO_LONG vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // 82 INT_TO_FLOAT vA, vB
-  DF_DA | DF_UB | DF_FP_A | DF_CORE_B,
-
-  // 83 INT_TO_DOUBLE vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_FP_A | DF_CORE_B,
-
-  // 84 LONG_TO_INT vA, vB
-  DF_DA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // 85 LONG_TO_FLOAT vA, vB
-  DF_DA | DF_UB | DF_B_WIDE | DF_FP_A | DF_CORE_B,
-
-  // 86 LONG_TO_DOUBLE vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_A | DF_CORE_B,
-
-  // 87 FLOAT_TO_INT vA, vB
-  DF_DA | DF_UB | DF_FP_B | DF_CORE_A,
-
-  // 88 FLOAT_TO_LONG vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_FP_B | DF_CORE_A,
-
-  // 89 FLOAT_TO_DOUBLE vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_FP_A | DF_FP_B,
-
-  // 8A DOUBLE_TO_INT vA, vB
-  DF_DA | DF_UB | DF_B_WIDE | DF_FP_B | DF_CORE_A,
-
-  // 8B DOUBLE_TO_LONG vA, vB
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_FP_B | DF_CORE_A,
-
-  // 8C DOUBLE_TO_FLOAT vA, vB
-  DF_DA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // 8D INT_TO_BYTE vA, vB
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // 8E INT_TO_CHAR vA, vB
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // 8F INT_TO_SHORT vA, vB
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // 90 ADD_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 91 SUB_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 92 MUL_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 93 DIV_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 94 REM_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 95 AND_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 96 OR_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 97 XOR_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 98 SHL_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 99 SHR_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 9A USHR_INT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 9B ADD_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 9C SUB_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 9D MUL_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 9E DIV_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // 9F REM_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A0 AND_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A1 OR_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A2 XOR_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A3 SHL_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A4 SHR_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A5 USHR_LONG vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_CORE_A | DF_CORE_B | DF_CORE_C,
-
-  // A6 ADD_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // A7 SUB_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // A8 MUL_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // A9 DIV_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // AA REM_FLOAT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // AB ADD_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // AC SUB_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // AD MUL_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // AE DIV_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // AF REM_DOUBLE vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_B_WIDE | DF_UC | DF_C_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
-
-  // B0 ADD_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B1 SUB_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B2 MUL_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B3 DIV_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B4 REM_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B5 AND_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B6 OR_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B7 XOR_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B8 SHL_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // B9 SHR_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // BA USHR_INT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // BB ADD_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // BC SUB_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // BD MUL_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // BE DIV_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // BF REM_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // C0 AND_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // C1 OR_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // C2 XOR_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_CORE_A | DF_CORE_B,
-
-  // C3 SHL_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // C4 SHR_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // C5 USHR_LONG_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // C6 ADD_FLOAT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
-
-  // C7 SUB_FLOAT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
-
-  // C8 MUL_FLOAT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
-
-  // C9 DIV_FLOAT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
-
-  // CA REM_FLOAT_2ADDR vA, vB
-  DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
-
-  // CB ADD_DOUBLE_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // CC SUB_DOUBLE_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // CD MUL_DOUBLE_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // CE DIV_DOUBLE_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // CF REM_DOUBLE_2ADDR vA, vB
-  DF_DA | DF_A_WIDE | DF_UA | DF_UB | DF_B_WIDE | DF_FP_A | DF_FP_B,
-
-  // D0 ADD_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D1 RSUB_INT vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D2 MUL_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D3 DIV_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D4 REM_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D5 AND_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D6 OR_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D7 XOR_INT_LIT16 vA, vB, #+CCCC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D8 ADD_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // D9 RSUB_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // DA MUL_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // DB DIV_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // DC REM_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // DD AND_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // DE OR_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // DF XOR_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // E0 SHL_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // E1 SHR_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // E2 USHR_INT_LIT8 vAA, vBB, #+CC
-  DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
-
-  // E3 IGET_VOLATILE
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // E4 IPUT_VOLATILE
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B,
-
-  // E5 SGET_VOLATILE
-  DF_DA | DF_UMS,
-
-  // E6 SPUT_VOLATILE
-  DF_UA | DF_UMS,
-
-  // E7 IGET_OBJECT_VOLATILE
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B,
-
-  // E8 IGET_WIDE_VOLATILE
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B,
-
-  // E9 IPUT_WIDE_VOLATILE
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B,
-
-  // EA SGET_WIDE_VOLATILE
-  DF_DA | DF_A_WIDE | DF_UMS,
-
-  // EB SPUT_WIDE_VOLATILE
-  DF_UA | DF_A_WIDE | DF_UMS,
-
-  // EC BREAKPOINT
-  DF_NOP,
-
-  // ED THROW_VERIFICATION_ERROR
-  DF_NOP | DF_UMS,
-
-  // EE EXECUTE_INLINE
-  DF_FORMAT_35C,
-
-  // EF EXECUTE_INLINE_RANGE
-  DF_FORMAT_3RC,
-
-  // F0 INVOKE_OBJECT_INIT_RANGE
-  DF_NOP | DF_NULL_CHK_0,
-
-  // F1 RETURN_VOID_BARRIER
-  DF_NOP,
-
-  // F2 IGET_QUICK
-  DF_DA | DF_UB | DF_NULL_CHK_0,
-
-  // F3 IGET_WIDE_QUICK
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0,
-
-  // F4 IGET_OBJECT_QUICK
-  DF_DA | DF_UB | DF_NULL_CHK_0,
-
-  // F5 IPUT_QUICK
-  DF_UA | DF_UB | DF_NULL_CHK_1,
-
-  // F6 IPUT_WIDE_QUICK
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2,
-
-  // F7 IPUT_OBJECT_QUICK
-  DF_UA | DF_UB | DF_NULL_CHK_1,
-
-  // F8 INVOKE_VIRTUAL_QUICK
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // F9 INVOKE_VIRTUAL_QUICK_RANGE
-  DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // FA INVOKE_SUPER_QUICK
-  DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
-
-  // FB INVOKE_SUPER_QUICK_RANGE
-  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,
-
-  // FD SGET_OBJECT_VOLATILE
-  DF_DA | DF_REF_A | DF_UMS,
-
-  // FE SPUT_OBJECT_VOLATILE
-  DF_UA | DF_REF_A | DF_UMS,
-
-  // FF UNUSED_FF
-  DF_NOP
-};
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/ir/instruction_tools.h b/compiler/sea_ir/ir/instruction_tools.h
deleted file mode 100644
index 895e017..0000000
--- a/compiler/sea_ir/ir/instruction_tools.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "sea.h"
-#include "dex_instruction.h"
-
-#ifndef ART_COMPILER_SEA_IR_IR_INSTRUCTION_TOOLS_H_
-#define ART_COMPILER_SEA_IR_IR_INSTRUCTION_TOOLS_H_
-
-
-// Note: This file has content cannibalized for SEA_IR from the MIR implementation,
-//       to avoid having a dependence on MIR.
-namespace sea_ir {
-
-#define DF_NOP                  0
-#define DF_UA                   (1 << kUA)
-#define DF_UB                   (1 << kUB)
-#define DF_UC                   (1 << kUC)
-#define DF_A_WIDE               (1 << kAWide)
-#define DF_B_WIDE               (1 << kBWide)
-#define DF_C_WIDE               (1 << kCWide)
-#define DF_DA                   (1 << kDA)
-#define DF_IS_MOVE              (1 << kIsMove)
-#define DF_SETS_CONST           (1 << kSetsConst)
-#define DF_FORMAT_35C           (1 << kFormat35c)
-#define DF_FORMAT_3RC           (1 << kFormat3rc)
-#define DF_NULL_CHK_0           (1 << kNullCheckSrc0)
-#define DF_NULL_CHK_1           (1 << kNullCheckSrc1)
-#define DF_NULL_CHK_2           (1 << kNullCheckSrc2)
-#define DF_NULL_CHK_OUT0        (1 << kNullCheckOut0)
-#define DF_NON_NULL_DST         (1 << kDstNonNull)
-#define DF_NON_NULL_RET         (1 << kRetNonNull)
-#define DF_NULL_TRANSFER_0      (1 << kNullTransferSrc0)
-#define DF_NULL_TRANSFER_N      (1 << kNullTransferSrcN)
-#define DF_RANGE_CHK_1          (1 << kRangeCheckSrc1)
-#define DF_RANGE_CHK_2          (1 << kRangeCheckSrc2)
-#define DF_RANGE_CHK_3          (1 << kRangeCheckSrc3)
-#define DF_FP_A                 (1 << kFPA)
-#define DF_FP_B                 (1 << kFPB)
-#define DF_FP_C                 (1 << kFPC)
-#define DF_CORE_A               (1 << kCoreA)
-#define DF_CORE_B               (1 << kCoreB)
-#define DF_CORE_C               (1 << kCoreC)
-#define DF_REF_A                (1 << kRefA)
-#define DF_REF_B                (1 << kRefB)
-#define DF_REF_C                (1 << kRefC)
-#define DF_UMS                  (1 << kUsesMethodStar)
-
-#define DF_HAS_USES             (DF_UA | DF_UB | DF_UC)
-
-#define DF_HAS_DEFS             (DF_DA)
-
-#define DF_HAS_NULL_CHKS        (DF_NULL_CHK_0 | \
-                                 DF_NULL_CHK_1 | \
-                                 DF_NULL_CHK_2 | \
-                                 DF_NULL_CHK_OUT0)
-
-#define DF_HAS_RANGE_CHKS       (DF_RANGE_CHK_1 | \
-                                 DF_RANGE_CHK_2 | \
-                                 DF_RANGE_CHK_3)
-
-#define DF_HAS_NR_CHKS          (DF_HAS_NULL_CHKS | \
-                                 DF_HAS_RANGE_CHKS)
-
-#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)
-
-enum DataFlowAttributePos {
-  kUA = 0,
-  kUB,
-  kUC,
-  kAWide,
-  kBWide,
-  kCWide,
-  kDA,
-  kIsMove,
-  kSetsConst,
-  kFormat35c,
-  kFormat3rc,
-  kNullCheckSrc0,        // Null check of uses[0].
-  kNullCheckSrc1,        // Null check of uses[1].
-  kNullCheckSrc2,        // Null check of uses[2].
-  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].
-  kFPA,
-  kFPB,
-  kFPC,
-  kCoreA,
-  kCoreB,
-  kCoreC,
-  kRefA,
-  kRefB,
-  kRefC,
-  kUsesMethodStar,       // Implicit use of Method*.
-};
-
-class InstructionTools {
- public:
-  static bool IsDefinition(const art::Instruction* instruction);
-  static const int instruction_attributes_[];
-};
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_IR_INSTRUCTION_TOOLS_H_
diff --git a/compiler/sea_ir/ir/regions_test.cc b/compiler/sea_ir/ir/regions_test.cc
deleted file mode 100644
index 95bd310..0000000
--- a/compiler/sea_ir/ir/regions_test.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "common_compiler_test.h"
-#include "sea_ir/ir/sea.h"
-
-using utils::ScopedHashtable;
-
-namespace sea_ir {
-
-class RegionsTest : public art::CommonCompilerTest {};
-
-TEST_F(RegionsTest, Basics) {
-  sea_ir::SeaGraph sg(*java_lang_dex_file_);
-  sea_ir::Region* root = sg.GetNewRegion();
-  sea_ir::Region* then_region = sg.GetNewRegion();
-  sea_ir::Region* else_region = sg.GetNewRegion();
-  std::vector<sea_ir::Region*>* regions = sg.GetRegions();
-  // Test that regions have been registered correctly as children of the graph.
-  EXPECT_TRUE(std::find(regions->begin(), regions->end(), root) != regions->end());
-  EXPECT_TRUE(std::find(regions->begin(), regions->end(), then_region) != regions->end());
-  EXPECT_TRUE(std::find(regions->begin(), regions->end(), else_region) != regions->end());
-  // Check that an edge recorded correctly in both the head and the tail.
-  sg.AddEdge(root, then_region);
-  std::vector<sea_ir::Region*>* succs = root->GetSuccessors();
-  EXPECT_EQ(1U, succs->size());
-  EXPECT_EQ(then_region, succs->at(0));
-  std::vector<sea_ir::Region*>* preds = then_region->GetPredecessors();
-  EXPECT_EQ(1U, preds->size());
-  EXPECT_EQ(root, preds->at(0));
-  // Check that two edges are recorded properly for both head and tail.
-  sg.AddEdge(root, else_region);
-  succs = root->GetSuccessors();
-  EXPECT_EQ(2U, succs->size());
-  EXPECT_TRUE(std::find(succs->begin(), succs->end(), then_region) != succs->end());
-  EXPECT_TRUE(std::find(succs->begin(), succs->end(), else_region) != succs->end());
-  preds = then_region->GetPredecessors();
-  EXPECT_EQ(1U, preds->size());
-  EXPECT_EQ(root, preds->at(0));
-  preds = else_region->GetPredecessors();
-  EXPECT_EQ(1U, preds->size());
-  EXPECT_EQ(root, preds->at(0));
-}
-
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/ir/sea.cc b/compiler/sea_ir/ir/sea.cc
deleted file mode 100644
index 2b25f56..0000000
--- a/compiler/sea_ir/ir/sea.cc
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "base/stringprintf.h"
-#include "sea_ir/ir/instruction_tools.h"
-#include "sea_ir/ir/sea.h"
-#include "sea_ir/code_gen/code_gen.h"
-#include "sea_ir/types/type_inference.h"
-
-#define MAX_REACHING_DEF_ITERERATIONS (10)
-// TODO: When development is done, this define should not
-// be needed, it is currently used as a cutoff
-// for cases where the iterative fixed point algorithm
-// does not reach a fixed point because of a bug.
-
-namespace sea_ir {
-
-int SeaNode::current_max_node_id_ = 0;
-
-void IRVisitor::Traverse(Region* region) {
-  std::vector<PhiInstructionNode*>* phis = region->GetPhiNodes();
-  for (std::vector<PhiInstructionNode*>::const_iterator cit = phis->begin();
-      cit != phis->end(); cit++) {
-    (*cit)->Accept(this);
-  }
-  std::vector<InstructionNode*>* instructions = region->GetInstructions();
-  for (std::vector<InstructionNode*>::const_iterator cit = instructions->begin();
-      cit != instructions->end(); cit++) {
-    (*cit)->Accept(this);
-  }
-}
-
-void IRVisitor::Traverse(SeaGraph* graph) {
-  for (std::vector<Region*>::const_iterator cit = ordered_regions_.begin();
-          cit != ordered_regions_.end(); cit++ ) {
-    (*cit)->Accept(this);
-  }
-}
-
-SeaGraph* SeaGraph::GetGraph(const art::DexFile& dex_file) {
-  return new SeaGraph(dex_file);
-}
-
-void SeaGraph::AddEdge(Region* src, Region* dst) const {
-  src->AddSuccessor(dst);
-  dst->AddPredecessor(src);
-}
-
-void SeaGraph::ComputeRPO(Region* current_region, int& current_rpo) {
-  current_region->SetRPO(VISITING);
-  std::vector<sea_ir::Region*>* succs = current_region->GetSuccessors();
-  for (std::vector<sea_ir::Region*>::iterator succ_it = succs->begin();
-      succ_it != succs->end(); ++succ_it) {
-    if (NOT_VISITED == (*succ_it)->GetRPO()) {
-      SeaGraph::ComputeRPO(*succ_it, current_rpo);
-    }
-  }
-  current_region->SetRPO(current_rpo--);
-}
-
-void SeaGraph::ComputeIDominators() {
-  bool changed = true;
-  while (changed) {
-    changed = false;
-    // Entry node has itself as IDOM.
-    std::vector<Region*>::iterator crt_it;
-    std::set<Region*> processedNodes;
-    // Find and mark the entry node(s).
-    for (crt_it = regions_.begin(); crt_it != regions_.end(); ++crt_it) {
-      if ((*crt_it)->GetPredecessors()->size() == 0) {
-        processedNodes.insert(*crt_it);
-        (*crt_it)->SetIDominator(*crt_it);
-      }
-    }
-    for (crt_it = regions_.begin(); crt_it != regions_.end(); ++crt_it) {
-      if ((*crt_it)->GetPredecessors()->size() == 0) {
-        continue;
-      }
-      // NewIDom = first (processed) predecessor of b.
-      Region* new_dom = NULL;
-      std::vector<Region*>* preds = (*crt_it)->GetPredecessors();
-      DCHECK(NULL != preds);
-      Region* root_pred = NULL;
-      for (std::vector<Region*>::iterator pred_it = preds->begin();
-          pred_it != preds->end(); ++pred_it) {
-        if (processedNodes.end() != processedNodes.find((*pred_it))) {
-          root_pred = *pred_it;
-          new_dom = root_pred;
-          break;
-        }
-      }
-      // For all other predecessors p of b, if idom is not set,
-      // then NewIdom = Intersect(p, NewIdom)
-      for (std::vector<Region*>::const_iterator pred_it = preds->begin();
-          pred_it != preds->end(); ++pred_it) {
-        DCHECK(NULL != *pred_it);
-        // if IDOMS[p] != UNDEFINED
-        if ((*pred_it != root_pred) && (*pred_it)->GetIDominator() != NULL) {
-          DCHECK(NULL != new_dom);
-          new_dom = SeaGraph::Intersect(*pred_it, new_dom);
-        }
-      }
-      DCHECK(NULL != *crt_it);
-      if ((*crt_it)->GetIDominator() != new_dom) {
-        (*crt_it)->SetIDominator(new_dom);
-        changed = true;
-      }
-      processedNodes.insert(*crt_it);
-    }
-  }
-
-  // For easily ordering of regions we need edges dominator->dominated.
-  for (std::vector<Region*>::iterator region_it = regions_.begin();
-      region_it != regions_.end(); region_it++) {
-    Region* idom = (*region_it)->GetIDominator();
-    if (idom != *region_it) {
-      idom->AddToIDominatedSet(*region_it);
-    }
-  }
-}
-
-Region* SeaGraph::Intersect(Region* i, Region* j) {
-  Region* finger1 = i;
-  Region* finger2 = j;
-  while (finger1 != finger2) {
-    while (finger1->GetRPO() > finger2->GetRPO()) {
-      DCHECK(NULL != finger1);
-      finger1 = finger1->GetIDominator();  // should have: finger1 != NULL
-      DCHECK(NULL != finger1);
-    }
-    while (finger1->GetRPO() < finger2->GetRPO()) {
-      DCHECK(NULL != finger2);
-      finger2 = finger2->GetIDominator();  // should have: finger1 != NULL
-      DCHECK(NULL != finger2);
-    }
-  }
-  return finger1;  // finger1 should be equal to finger2 at this point.
-}
-
-void SeaGraph::ComputeDownExposedDefs() {
-  for (std::vector<Region*>::iterator region_it = regions_.begin();
-        region_it != regions_.end(); region_it++) {
-      (*region_it)->ComputeDownExposedDefs();
-    }
-}
-
-void SeaGraph::ComputeReachingDefs() {
-  // Iterate until the reaching definitions set doesn't change anymore.
-  // (See Cooper & Torczon, "Engineering a Compiler", second edition, page 487)
-  bool changed = true;
-  int iteration = 0;
-  while (changed && (iteration < MAX_REACHING_DEF_ITERERATIONS)) {
-    iteration++;
-    changed = false;
-    // TODO: optimize the ordering if this becomes performance bottleneck.
-    for (std::vector<Region*>::iterator regions_it = regions_.begin();
-        regions_it != regions_.end();
-        regions_it++) {
-      changed |= (*regions_it)->UpdateReachingDefs();
-    }
-  }
-  DCHECK(!changed) << "Reaching definitions computation did not reach a fixed point.";
-}
-
-void SeaGraph::InsertSignatureNodes(const art::DexFile::CodeItem* code_item, Region* r) {
-  // Insert a fake SignatureNode for the first parameter.
-  // TODO: Provide a register enum value for the fake parameter.
-  SignatureNode* parameter_def_node = new sea_ir::SignatureNode(0, 0);
-  AddParameterNode(parameter_def_node);
-  r->AddChild(parameter_def_node);
-  // Insert SignatureNodes for each Dalvik register parameter.
-  for (unsigned int crt_offset = 0; crt_offset < code_item->ins_size_; crt_offset++) {
-    int register_no = code_item->registers_size_ - crt_offset - 1;
-    int position = crt_offset + 1;
-    SignatureNode* parameter_def_node = new sea_ir::SignatureNode(register_no, position);
-    AddParameterNode(parameter_def_node);
-    r->AddChild(parameter_def_node);
-  }
-}
-
-void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item,
-    const art::DexFile& dex_file, uint16_t class_def_idx,
-    uint32_t method_idx, uint32_t method_access_flags) {
-  code_item_ = code_item;
-  class_def_idx_ = class_def_idx;
-  method_idx_ = method_idx;
-  method_access_flags_ = method_access_flags;
-  const uint16_t* code = code_item->insns_;
-  const size_t size_in_code_units = code_item->insns_size_in_code_units_;
-  // This maps target instruction pointers to their corresponding region objects.
-  std::map<const uint16_t*, Region*> target_regions;
-  size_t i = 0;
-  // Pass: Find the start instruction of basic blocks
-  //         by locating targets and flow-though instructions of branches.
-  while (i < size_in_code_units) {
-    const art::Instruction* inst = art::Instruction::At(&code[i]);
-    if (inst->IsBranch() || inst->IsUnconditional()) {
-      int32_t offset = inst->GetTargetOffset();
-      if (target_regions.end() == target_regions.find(&code[i + offset])) {
-        Region* region = GetNewRegion();
-        target_regions.insert(std::pair<const uint16_t*, Region*>(&code[i + offset], region));
-      }
-      if (inst->CanFlowThrough()
-          && (target_regions.end() == target_regions.find(&code[i + inst->SizeInCodeUnits()]))) {
-        Region* region = GetNewRegion();
-        target_regions.insert(
-            std::pair<const uint16_t*, Region*>(&code[i + inst->SizeInCodeUnits()], region));
-      }
-    }
-    i += inst->SizeInCodeUnits();
-  }
-
-
-  Region* r = GetNewRegion();
-
-  InsertSignatureNodes(code_item, r);
-  // Pass: Assign instructions to region nodes and
-  //         assign branches their control flow successors.
-  i = 0;
-  sea_ir::InstructionNode* last_node = NULL;
-  sea_ir::InstructionNode* node = NULL;
-  while (i < size_in_code_units) {
-    const art::Instruction* inst = art::Instruction::At(&code[i]);
-    std::vector<InstructionNode*> sea_instructions_for_dalvik =
-        sea_ir::InstructionNode::Create(inst);
-    for (std::vector<InstructionNode*>::const_iterator cit = sea_instructions_for_dalvik.begin();
-        sea_instructions_for_dalvik.end() != cit; ++cit) {
-      last_node = node;
-      node = *cit;
-
-      if (inst->IsBranch() || inst->IsUnconditional()) {
-        int32_t offset = inst->GetTargetOffset();
-        std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i + offset]);
-        DCHECK(it != target_regions.end());
-        AddEdge(r, it->second);  // Add edge to branch target.
-      }
-      std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i]);
-      if (target_regions.end() != it) {
-        // Get the already created region because this is a branch target.
-        Region* nextRegion = it->second;
-        if (last_node->GetInstruction()->IsBranch()
-            && last_node->GetInstruction()->CanFlowThrough()) {
-          AddEdge(r, it->second);  // Add flow-through edge.
-        }
-        r = nextRegion;
-      }
-      r->AddChild(node);
-    }
-    i += inst->SizeInCodeUnits();
-  }
-}
-
-void SeaGraph::ComputeRPO() {
-  int rpo_id = regions_.size() - 1;
-  for (std::vector<Region*>::const_iterator crt_it = regions_.begin(); crt_it != regions_.end();
-      ++crt_it) {
-    if ((*crt_it)->GetPredecessors()->size() == 0) {
-      ComputeRPO(*crt_it, rpo_id);
-    }
-  }
-}
-
-// Performs the renaming phase in traditional SSA transformations.
-// See: Cooper & Torczon, "Engineering a Compiler", second edition, page 505.)
-void SeaGraph::RenameAsSSA() {
-  utils::ScopedHashtable<int, InstructionNode*> scoped_table;
-  scoped_table.OpenScope();
-  for (std::vector<Region*>::iterator region_it = regions_.begin(); region_it != regions_.end();
-      region_it++) {
-    if ((*region_it)->GetIDominator() == *region_it) {
-      RenameAsSSA(*region_it, &scoped_table);
-    }
-  }
-  scoped_table.CloseScope();
-}
-
-void SeaGraph::ConvertToSSA() {
-  // Pass: find global names.
-  // The map @block maps registers to the blocks in which they are defined.
-  std::map<int, std::set<Region*>> blocks;
-  // The set @globals records registers whose use
-  // is in a different block than the corresponding definition.
-  std::set<int> globals;
-  for (std::vector<Region*>::iterator region_it = regions_.begin(); region_it != regions_.end();
-      region_it++) {
-    std::set<int> var_kill;
-    std::vector<InstructionNode*>* instructions = (*region_it)->GetInstructions();
-    for (std::vector<InstructionNode*>::iterator inst_it = instructions->begin();
-        inst_it != instructions->end(); inst_it++) {
-      std::vector<int> used_regs = (*inst_it)->GetUses();
-      for (std::size_t i = 0; i < used_regs.size(); i++) {
-        int used_reg = used_regs[i];
-        if (var_kill.find(used_reg) == var_kill.end()) {
-          globals.insert(used_reg);
-        }
-      }
-      const int reg_def = (*inst_it)->GetResultRegister();
-      if (reg_def != NO_REGISTER) {
-        var_kill.insert(reg_def);
-      }
-
-      blocks.insert(std::pair<int, std::set<Region*>>(reg_def, std::set<Region*>()));
-      std::set<Region*>* reg_def_blocks = &(blocks.find(reg_def)->second);
-      reg_def_blocks->insert(*region_it);
-    }
-  }
-
-  // Pass: Actually add phi-nodes to regions.
-  for (std::set<int>::const_iterator globals_it = globals.begin();
-      globals_it != globals.end(); globals_it++) {
-    int global = *globals_it;
-    // Copy the set, because we will modify the worklist as we go.
-    std::set<Region*> worklist((*(blocks.find(global))).second);
-    for (std::set<Region*>::const_iterator b_it = worklist.begin();
-        b_it != worklist.end(); b_it++) {
-      std::set<Region*>* df = (*b_it)->GetDominanceFrontier();
-      for (std::set<Region*>::const_iterator df_it = df->begin(); df_it != df->end(); df_it++) {
-        if ((*df_it)->InsertPhiFor(global)) {
-          // Check that the dominance frontier element is in the worklist already
-          // because we only want to break if the element is actually not there yet.
-          if (worklist.find(*df_it) == worklist.end()) {
-            worklist.insert(*df_it);
-            b_it = worklist.begin();
-            break;
-          }
-        }
-      }
-    }
-  }
-  // Pass: Build edges to the definition corresponding to each use.
-  // (This corresponds to the renaming phase in traditional SSA transformations.
-  // See: Cooper & Torczon, "Engineering a Compiler", second edition, page 505.)
-  RenameAsSSA();
-}
-
-void SeaGraph::RenameAsSSA(Region* crt_region,
-    utils::ScopedHashtable<int, InstructionNode*>* scoped_table) {
-  scoped_table->OpenScope();
-  // Rename phi nodes defined in the current region.
-  std::vector<PhiInstructionNode*>* phis = crt_region->GetPhiNodes();
-  for (std::vector<PhiInstructionNode*>::iterator phi_it = phis->begin();
-      phi_it != phis->end(); phi_it++) {
-    int reg_no = (*phi_it)->GetRegisterNumber();
-    scoped_table->Add(reg_no, (*phi_it));
-  }
-  // Rename operands of instructions from the current region.
-  std::vector<InstructionNode*>* instructions = crt_region->GetInstructions();
-  for (std::vector<InstructionNode*>::const_iterator instructions_it = instructions->begin();
-      instructions_it != instructions->end(); instructions_it++) {
-    InstructionNode* current_instruction = (*instructions_it);
-    // Rename uses.
-    std::vector<int> used_regs = current_instruction->GetUses();
-    for (std::vector<int>::const_iterator reg_it = used_regs.begin();
-        reg_it != used_regs.end(); reg_it++) {
-      int current_used_reg = (*reg_it);
-      InstructionNode* definition = scoped_table->Lookup(current_used_reg);
-      current_instruction->RenameToSSA(current_used_reg, definition);
-    }
-    // Update scope table with latest definitions.
-    std::vector<int> def_regs = current_instruction->GetDefinitions();
-    for (std::vector<int>::const_iterator reg_it = def_regs.begin();
-            reg_it != def_regs.end(); reg_it++) {
-      int current_defined_reg = (*reg_it);
-      scoped_table->Add(current_defined_reg, current_instruction);
-    }
-  }
-  // Fill in uses of phi functions in CFG successor regions.
-  const std::vector<Region*>* successors = crt_region->GetSuccessors();
-  for (std::vector<Region*>::const_iterator successors_it = successors->begin();
-      successors_it != successors->end(); successors_it++) {
-    Region* successor = (*successors_it);
-    successor->SetPhiDefinitionsForUses(scoped_table, crt_region);
-  }
-
-  // Rename all successors in the dominators tree.
-  const std::set<Region*>* dominated_nodes = crt_region->GetIDominatedSet();
-  for (std::set<Region*>::const_iterator dominated_nodes_it = dominated_nodes->begin();
-      dominated_nodes_it != dominated_nodes->end(); dominated_nodes_it++) {
-    Region* dominated_node = (*dominated_nodes_it);
-    RenameAsSSA(dominated_node, scoped_table);
-  }
-  scoped_table->CloseScope();
-}
-
-CodeGenData* SeaGraph::GenerateLLVM(const std::string& function_name,
-    const art::DexFile& dex_file) {
-  // Pass: Generate LLVM IR.
-  CodeGenPrepassVisitor code_gen_prepass_visitor(function_name);
-  std::cout << "Generating code..." << std::endl;
-  Accept(&code_gen_prepass_visitor);
-  CodeGenVisitor code_gen_visitor(code_gen_prepass_visitor.GetData(),  dex_file);
-  Accept(&code_gen_visitor);
-  CodeGenPostpassVisitor code_gen_postpass_visitor(code_gen_visitor.GetData());
-  Accept(&code_gen_postpass_visitor);
-  return code_gen_postpass_visitor.GetData();
-}
-
-CodeGenData* SeaGraph::CompileMethod(
-    const std::string& function_name,
-    const art::DexFile::CodeItem* code_item, uint16_t class_def_idx,
-    uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file) {
-  // Two passes: Builds the intermediate structure (non-SSA) of the sea-ir for the function.
-  BuildMethodSeaGraph(code_item, dex_file, class_def_idx, method_idx, method_access_flags);
-  // Pass: Compute reverse post-order of regions.
-  ComputeRPO();
-  // Multiple passes: compute immediate dominators.
-  ComputeIDominators();
-  // Pass: compute downward-exposed definitions.
-  ComputeDownExposedDefs();
-  // Multiple Passes (iterative fixed-point algorithm): Compute reaching definitions
-  ComputeReachingDefs();
-  // Pass (O(nlogN)): Compute the dominance frontier for region nodes.
-  ComputeDominanceFrontier();
-  // Two Passes: Phi node insertion.
-  ConvertToSSA();
-  // Pass: type inference
-  ti_->ComputeTypes(this);
-  // Pass: Generate LLVM IR.
-  CodeGenData* cgd = GenerateLLVM(function_name, dex_file);
-  return cgd;
-}
-
-void SeaGraph::ComputeDominanceFrontier() {
-  for (std::vector<Region*>::iterator region_it = regions_.begin();
-      region_it != regions_.end(); region_it++) {
-    std::vector<Region*>* preds = (*region_it)->GetPredecessors();
-    if (preds->size() > 1) {
-      for (std::vector<Region*>::iterator pred_it = preds->begin();
-          pred_it != preds->end(); pred_it++) {
-        Region* runner = *pred_it;
-        while (runner != (*region_it)->GetIDominator()) {
-          runner->AddToDominanceFrontier(*region_it);
-          runner = runner->GetIDominator();
-        }
-      }
-    }
-  }
-}
-
-Region* SeaGraph::GetNewRegion() {
-  Region* new_region = new Region();
-  AddRegion(new_region);
-  return new_region;
-}
-
-void SeaGraph::AddRegion(Region* r) {
-  DCHECK(r) << "Tried to add NULL region to SEA graph.";
-  regions_.push_back(r);
-}
-
-SeaGraph::SeaGraph(const art::DexFile& df)
-    :ti_(new TypeInference()), class_def_idx_(0), method_idx_(0),  method_access_flags_(),
-     regions_(), parameters_(), dex_file_(df), code_item_(NULL) { }
-
-void Region::AddChild(sea_ir::InstructionNode* instruction) {
-  DCHECK(instruction) << "Tried to add NULL instruction to region node.";
-  instructions_.push_back(instruction);
-  instruction->SetRegion(this);
-}
-
-SeaNode* Region::GetLastChild() const {
-  if (instructions_.size() > 0) {
-    return instructions_.back();
-  }
-  return NULL;
-}
-
-void Region::ComputeDownExposedDefs() {
-  for (std::vector<InstructionNode*>::const_iterator inst_it = instructions_.begin();
-      inst_it != instructions_.end(); inst_it++) {
-    int reg_no = (*inst_it)->GetResultRegister();
-    std::map<int, InstructionNode*>::iterator res = de_defs_.find(reg_no);
-    if ((reg_no != NO_REGISTER) && (res == de_defs_.end())) {
-      de_defs_.insert(std::pair<int, InstructionNode*>(reg_no, *inst_it));
-    } else {
-      res->second = *inst_it;
-    }
-  }
-  for (std::map<int, sea_ir::InstructionNode*>::const_iterator cit = de_defs_.begin();
-      cit != de_defs_.end(); cit++) {
-    (*cit).second->MarkAsDEDef();
-  }
-}
-
-const std::map<int, sea_ir::InstructionNode*>* Region::GetDownExposedDefs() const {
-  return &de_defs_;
-}
-
-std::map<int, std::set<sea_ir::InstructionNode*>* >* Region::GetReachingDefs() {
-  return &reaching_defs_;
-}
-
-bool Region::UpdateReachingDefs() {
-  std::map<int, std::set<sea_ir::InstructionNode*>* > new_reaching;
-  for (std::vector<Region*>::const_iterator pred_it = predecessors_.begin();
-      pred_it != predecessors_.end(); pred_it++) {
-    // The reaching_defs variable will contain reaching defs __for current predecessor only__
-    std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs;
-    std::map<int, std::set<sea_ir::InstructionNode*>* >* pred_reaching =
-        (*pred_it)->GetReachingDefs();
-    const std::map<int, InstructionNode*>* de_defs = (*pred_it)->GetDownExposedDefs();
-
-    // The definitions from the reaching set of the predecessor
-    // may be shadowed by downward exposed definitions from the predecessor,
-    // otherwise the defs from the reaching set are still good.
-    for (std::map<int, InstructionNode*>::const_iterator de_def = de_defs->begin();
-        de_def != de_defs->end(); de_def++) {
-      std::set<InstructionNode*>* solo_def;
-      solo_def = new std::set<InstructionNode*>();
-      solo_def->insert(de_def->second);
-      reaching_defs.insert(
-          std::pair<int const, std::set<InstructionNode*>*>(de_def->first, solo_def));
-    }
-    reaching_defs.insert(pred_reaching->begin(), pred_reaching->end());
-
-    // Now we combine the reaching map coming from the current predecessor (reaching_defs)
-    // with the accumulated set from all predecessors so far (from new_reaching).
-    std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it =
-        reaching_defs.begin();
-    for (; reaching_it != reaching_defs.end(); reaching_it++) {
-      std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator crt_entry =
-          new_reaching.find(reaching_it->first);
-      if (new_reaching.end() != crt_entry) {
-        crt_entry->second->insert(reaching_it->second->begin(), reaching_it->second->end());
-      } else {
-        new_reaching.insert(
-            std::pair<int, std::set<sea_ir::InstructionNode*>*>(
-                reaching_it->first,
-                reaching_it->second) );
-      }
-    }
-  }
-  bool changed = false;
-  // Because the sets are monotonically increasing,
-  // we can compare sizes instead of using set comparison.
-  // TODO: Find formal proof.
-  int old_size = 0;
-  if (-1 == reaching_defs_size_) {
-    std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it =
-        reaching_defs_.begin();
-    for (; reaching_it != reaching_defs_.end(); reaching_it++) {
-      old_size += (*reaching_it).second->size();
-    }
-  } else {
-    old_size = reaching_defs_size_;
-  }
-  int new_size = 0;
-  std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = new_reaching.begin();
-  for (; reaching_it != new_reaching.end(); reaching_it++) {
-    new_size += (*reaching_it).second->size();
-  }
-  if (old_size != new_size) {
-    changed = true;
-  }
-  if (changed) {
-    reaching_defs_ = new_reaching;
-    reaching_defs_size_ = new_size;
-  }
-  return changed;
-}
-
-bool Region::InsertPhiFor(int reg_no) {
-  if (!ContainsPhiFor(reg_no)) {
-    phi_set_.insert(reg_no);
-    PhiInstructionNode* new_phi = new PhiInstructionNode(reg_no);
-    new_phi->SetRegion(this);
-    phi_instructions_.push_back(new_phi);
-    return true;
-  }
-  return false;
-}
-
-void Region::SetPhiDefinitionsForUses(
-    const utils::ScopedHashtable<int, InstructionNode*>* scoped_table, Region* predecessor) {
-  int predecessor_id = -1;
-  for (unsigned int crt_pred_id = 0; crt_pred_id < predecessors_.size(); crt_pred_id++) {
-    if (predecessors_.at(crt_pred_id) == predecessor) {
-      predecessor_id = crt_pred_id;
-    }
-  }
-  DCHECK_NE(-1, predecessor_id);
-  for (std::vector<PhiInstructionNode*>::iterator phi_it = phi_instructions_.begin();
-      phi_it != phi_instructions_.end(); phi_it++) {
-    PhiInstructionNode* phi = (*phi_it);
-    int reg_no = phi->GetRegisterNumber();
-    InstructionNode* definition = scoped_table->Lookup(reg_no);
-    phi->RenameToSSA(reg_no, definition, predecessor_id);
-  }
-}
-
-std::vector<InstructionNode*> InstructionNode::Create(const art::Instruction* in) {
-  std::vector<InstructionNode*> sea_instructions;
-  switch (in->Opcode()) {
-    case art::Instruction::CONST_4:
-      sea_instructions.push_back(new ConstInstructionNode(in));
-      break;
-    case art::Instruction::RETURN:
-      sea_instructions.push_back(new ReturnInstructionNode(in));
-      break;
-    case art::Instruction::IF_NE:
-      sea_instructions.push_back(new IfNeInstructionNode(in));
-      break;
-    case art::Instruction::ADD_INT_LIT8:
-      sea_instructions.push_back(new UnnamedConstInstructionNode(in, in->VRegC_22b()));
-      sea_instructions.push_back(new AddIntLitInstructionNode(in));
-      break;
-    case art::Instruction::MOVE_RESULT:
-      sea_instructions.push_back(new MoveResultInstructionNode(in));
-      break;
-    case art::Instruction::INVOKE_STATIC:
-      sea_instructions.push_back(new InvokeStaticInstructionNode(in));
-      break;
-    case art::Instruction::ADD_INT:
-      sea_instructions.push_back(new AddIntInstructionNode(in));
-      break;
-    case art::Instruction::GOTO:
-      sea_instructions.push_back(new GotoInstructionNode(in));
-      break;
-    case art::Instruction::IF_EQZ:
-      sea_instructions.push_back(new IfEqzInstructionNode(in));
-      break;
-    default:
-      // Default, generic IR instruction node; default case should never be reached
-      // when support for all instructions ahs been added.
-      sea_instructions.push_back(new InstructionNode(in));
-  }
-  return sea_instructions;
-}
-
-void InstructionNode::MarkAsDEDef() {
-  de_def_ = true;
-}
-
-int InstructionNode::GetResultRegister() const {
-  if (instruction_->HasVRegA() && InstructionTools::IsDefinition(instruction_)) {
-    return instruction_->VRegA();
-  }
-  return NO_REGISTER;
-}
-
-std::vector<int> InstructionNode::GetDefinitions() const {
-  // TODO: Extend this to handle instructions defining more than one register (if any)
-  // The return value should be changed to pointer to field then; for now it is an object
-  // so that we avoid possible memory leaks from allocating objects dynamically.
-  std::vector<int> definitions;
-  int result = GetResultRegister();
-  if (NO_REGISTER != result) {
-    definitions.push_back(result);
-  }
-  return definitions;
-}
-
-std::vector<int> InstructionNode::GetUses() const {
-  std::vector<int> uses;  // Using vector<> instead of set<> because order matters.
-  if (!InstructionTools::IsDefinition(instruction_) && (instruction_->HasVRegA())) {
-    int vA = instruction_->VRegA();
-    uses.push_back(vA);
-  }
-  if (instruction_->HasVRegB()) {
-    int vB = instruction_->VRegB();
-    uses.push_back(vB);
-  }
-  if (instruction_->HasVRegC()) {
-    int vC = instruction_->VRegC();
-    uses.push_back(vC);
-  }
-  return uses;
-}
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/ir/sea.h b/compiler/sea_ir/ir/sea.h
deleted file mode 100644
index 26b16be..0000000
--- a/compiler/sea_ir/ir/sea.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef ART_COMPILER_SEA_IR_IR_SEA_H_
-#define ART_COMPILER_SEA_IR_IR_SEA_H_
-
-#include <set>
-#include <map>
-
-#include "utils/scoped_hashtable.h"
-#include "gtest/gtest_prod.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
-#include "sea_ir/ir/instruction_tools.h"
-#include "sea_ir/ir/instruction_nodes.h"
-
-namespace sea_ir {
-
-// Reverse post-order numbering constants
-enum RegionNumbering {
-  NOT_VISITED = -1,
-  VISITING = -2
-};
-
-class TypeInference;
-class CodeGenData;
-
-class Region;
-class InstructionNode;
-class PhiInstructionNode;
-class SignatureNode;
-
-// A SignatureNode is a declaration of one parameter in the function signature.
-// This class is used to provide place-holder definitions to which instructions
-// can return from the GetSSAUses() calls, instead of having missing SSA edges.
-class SignatureNode: public InstructionNode {
- public:
-  // Creates a new signature node representing the initial definition of the
-  // register @register_no which is the @signature_position-th argument to the method.
-  explicit SignatureNode(unsigned int register_no, unsigned int signature_position):
-    InstructionNode(NULL), register_no_(register_no), position_(signature_position) { }
-
-  int GetResultRegister() const {
-    return register_no_;
-  }
-
-  unsigned int GetPositionInSignature() const {
-    return position_;
-  }
-
-  std::vector<int> GetUses() const {
-    return std::vector<int>();
-  }
-
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-
- private:
-  const unsigned int register_no_;
-  const unsigned int position_;     // The position of this parameter node is
-                                    // in the function parameter list.
-};
-
-class PhiInstructionNode: public InstructionNode {
- public:
-  explicit PhiInstructionNode(int register_no):
-    InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
-  // Returns the register on which this phi-function is used.
-  int GetRegisterNumber() const {
-    return register_no_;
-  }
-
-  // Renames the use of @reg_no to refer to the instruction @definition.
-  // Phi-functions are different than normal instructions in that they
-  // have multiple predecessor regions; this is why RenameToSSA has
-  // the additional parameter specifying that @parameter_id is the incoming
-  // edge for @definition, essentially creating SSA form.
-  void RenameToSSA(int reg_no, InstructionNode* definition, unsigned int predecessor_id) {
-    DCHECK(NULL != definition) << "Tried to rename to SSA using a NULL definition for "
-        << StringId() << " register " << reg_no;
-    if (definition_edges_.size() < predecessor_id+1) {
-      definition_edges_.resize(predecessor_id+1, NULL);
-    }
-    if (NULL == definition_edges_.at(predecessor_id)) {
-      definition_edges_[predecessor_id] = new std::vector<InstructionNode*>();
-    }
-    definition_edges_[predecessor_id]->push_back(definition);
-    definition->AddSSAUse(this);
-  }
-
-  // Returns the ordered set of Instructions that define the input operands of this instruction.
-  // Precondition: SeaGraph.ConvertToSSA().
-  std::vector<InstructionNode*> GetSSAProducers() {
-    std::vector<InstructionNode*> producers;
-    for (std::vector<std::vector<InstructionNode*>*>::const_iterator
-        cit = definition_edges_.begin(); cit != definition_edges_.end(); cit++) {
-      producers.insert(producers.end(), (*cit)->begin(), (*cit)->end());
-    }
-    return producers;
-  }
-
-  // Returns the instruction that defines the phi register from predecessor
-  // on position @predecessor_pos. Note that the return value is vector<> just
-  // for consistency with the return value of GetSSAUses() on regular instructions,
-  // The returned vector should always have a single element because the IR is SSA.
-  std::vector<InstructionNode*>* GetSSAUses(int predecessor_pos) {
-    return definition_edges_.at(predecessor_pos);
-  }
-
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-
- private:
-  int register_no_;
-  // This vector has one entry for each predecessors, each with a single
-  // element, storing the id of the instruction that defines the register
-  // corresponding to this phi function.
-  std::vector<std::vector<InstructionNode*>*> definition_edges_;
-};
-
-// This class corresponds to a basic block in traditional compiler IRs.
-// The dataflow analysis relies on this class both during execution and
-// for storing its results.
-class Region : public SeaNode {
- public:
-  explicit Region():
-    SeaNode(), successors_(), predecessors_(), reaching_defs_size_(0),
-    rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {
-    string_id_ = "cluster_" + string_id_;
-  }
-  // Adds @instruction as an instruction node child in the current region.
-  void AddChild(sea_ir::InstructionNode* instruction);
-  // Returns the last instruction node child of the current region.
-  // This child has the CFG successors pointing to the new regions.
-  SeaNode* GetLastChild() const;
-  // Returns all the child instructions of this region, in program order.
-  std::vector<InstructionNode*>* GetInstructions() {
-    return &instructions_;
-  }
-
-  // Computes Downward Exposed Definitions for the current node.
-  void ComputeDownExposedDefs();
-  const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
-  // Performs one iteration of the reaching definitions algorithm
-  // and returns true if the reaching definitions set changed.
-  bool UpdateReachingDefs();
-  // Returns the set of reaching definitions for the current region.
-  std::map<int, std::set<sea_ir::InstructionNode*>* >* GetReachingDefs();
-
-  void SetRPO(int rpo) {
-    rpo_number_ = rpo;
-  }
-
-  int GetRPO() {
-    return rpo_number_;
-  }
-
-  void SetIDominator(Region* dom) {
-    idom_ = dom;
-  }
-
-  Region* GetIDominator() const {
-    return idom_;
-  }
-
-  void AddToIDominatedSet(Region* dominated) {
-    idominated_set_.insert(dominated);
-  }
-
-  const std::set<Region*>* GetIDominatedSet() {
-    return &idominated_set_;
-  }
-  // Adds @df_reg to the dominance frontier of the current region.
-  void AddToDominanceFrontier(Region* df_reg) {
-    df_.insert(df_reg);
-  }
-  // Returns the dominance frontier of the current region.
-  // Preconditions: SeaGraph.ComputeDominanceFrontier()
-  std::set<Region*>* GetDominanceFrontier() {
-    return &df_;
-  }
-  // Returns true if the region contains a phi function for @reg_no.
-  bool ContainsPhiFor(int reg_no) {
-    return (phi_set_.end() != phi_set_.find(reg_no));
-  }
-  // Returns the phi-functions from the region.
-  std::vector<PhiInstructionNode*>* GetPhiNodes() {
-    return &phi_instructions_;
-  }
-  // Adds a phi-function for @reg_no to this region.
-  // Note: The insertion order does not matter, as phi-functions
-  //       are conceptually executed at the same time.
-  bool InsertPhiFor(int reg_no);
-  // Sets the phi-function uses to be as defined in @scoped_table for predecessor @@predecessor.
-  void SetPhiDefinitionsForUses(const utils::ScopedHashtable<int, InstructionNode*>* scoped_table,
-      Region* predecessor);
-
-  void Accept(IRVisitor* v) {
-    v->Visit(this);
-    v->Traverse(this);
-  }
-
-  void AddSuccessor(Region* successor) {
-    DCHECK(successor) << "Tried to add NULL successor to SEA node.";
-    successors_.push_back(successor);
-    return;
-  }
-  void AddPredecessor(Region* predecessor) {
-    DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node.";
-    predecessors_.push_back(predecessor);
-  }
-
-  std::vector<sea_ir::Region*>* GetSuccessors() {
-    return &successors_;
-  }
-  std::vector<sea_ir::Region*>* GetPredecessors() {
-    return &predecessors_;
-  }
-
- private:
-  std::vector<sea_ir::Region*> successors_;    // CFG successor nodes (regions)
-  std::vector<sea_ir::Region*> predecessors_;  // CFG predecessor nodes (instructions/regions)
-  std::vector<sea_ir::InstructionNode*> instructions_;
-  std::map<int, sea_ir::InstructionNode*> de_defs_;
-  std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs_;
-  int reaching_defs_size_;
-  int rpo_number_;                              // reverse postorder number of the region
-  // Immediate dominator node.
-  Region* idom_;
-  // The set of nodes immediately dominated by the region.
-  std::set<Region*> idominated_set_;
-  // Records the dominance frontier.
-  std::set<Region*> df_;
-  // Records the set of register numbers that have phi nodes in this region.
-  std::set<int> phi_set_;
-  std::vector<PhiInstructionNode*> phi_instructions_;
-};
-
-// A SeaGraph instance corresponds to a source code function.
-// Its main point is to encapsulate the SEA IR representation of it
-// and acts as starting point for visitors (ex: during code generation).
-class SeaGraph: IVisitable {
- public:
-  static SeaGraph* GetGraph(const art::DexFile&);
-
-  CodeGenData* CompileMethod(const std::string& function_name,
-      const art::DexFile::CodeItem* code_item, uint16_t class_def_idx,
-      uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file);
-  // Returns all regions corresponding to this SeaGraph.
-  std::vector<Region*>* GetRegions() {
-    return &regions_;
-  }
-  // Recursively computes the reverse postorder value for @crt_bb and successors.
-  static void ComputeRPO(Region* crt_bb, int& crt_rpo);
-  // Returns the "lowest common ancestor" of @i and @j in the dominator tree.
-  static Region* Intersect(Region* i, Region* j);
-  // Returns the vector of parameters of the function.
-  std::vector<SignatureNode*>* GetParameterNodes() {
-    return &parameters_;
-  }
-
-  const art::DexFile* GetDexFile() const {
-    return &dex_file_;
-  }
-
-  virtual void Accept(IRVisitor* visitor) {
-    visitor->Initialize(this);
-    visitor->Visit(this);
-    visitor->Traverse(this);
-  }
-
-  TypeInference* ti_;
-  uint16_t class_def_idx_;
-  uint32_t method_idx_;
-  uint32_t method_access_flags_;
-
- protected:
-  explicit SeaGraph(const art::DexFile& df);
-  virtual ~SeaGraph() { }
-
- private:
-  FRIEND_TEST(RegionsTest, Basics);
-  // Registers @childReg as a region belonging to the SeaGraph instance.
-  void AddRegion(Region* childReg);
-  // Returns new region and registers it with the  SeaGraph instance.
-  Region* GetNewRegion();
-  // Adds a (formal) parameter node to the vector of parameters of the function.
-  void AddParameterNode(SignatureNode* parameterNode) {
-    parameters_.push_back(parameterNode);
-  }
-  // Adds a CFG edge from @src node to @dst node.
-  void AddEdge(Region* src, Region* dst) const;
-  // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file
-  // with class id @class_def_idx and method id @method_idx.
-  void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item,
-      const art::DexFile& dex_file, uint16_t class_def_idx,
-      uint32_t method_idx, uint32_t method_access_flags);
-  // Computes immediate dominators for each region.
-  // Precondition: ComputeMethodSeaGraph()
-  void ComputeIDominators();
-  // Computes Downward Exposed Definitions for all regions in the graph.
-  void ComputeDownExposedDefs();
-  // Computes the reaching definitions set following the equations from
-  // Cooper & Torczon, "Engineering a Compiler", second edition, page 491.
-  // Precondition: ComputeDEDefs()
-  void ComputeReachingDefs();
-  // Computes the reverse-postorder numbering for the region nodes.
-  // Precondition: ComputeDEDefs()
-  void ComputeRPO();
-  // Computes the dominance frontier for all regions in the graph,
-  // following the algorithm from
-  // Cooper & Torczon, "Engineering a Compiler", second edition, page 499.
-  // Precondition: ComputeIDominators()
-  void ComputeDominanceFrontier();
-  // Converts the IR to semi-pruned SSA form.
-  void ConvertToSSA();
-  // Performs the renaming phase of the SSA transformation during ConvertToSSA() execution.
-  void RenameAsSSA();
-  // Identifies the definitions corresponding to uses for region @node
-  // by using the scoped hashtable of names @ scoped_table.
-  void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table);
-  // Generate LLVM IR for the method.
-  // Precondition: ConvertToSSA().
-  CodeGenData* GenerateLLVM(const std::string& function_name, const art::DexFile& dex_file);
-  // Inserts one SignatureNode for each argument of the function in
-  void InsertSignatureNodes(const art::DexFile::CodeItem* code_item, Region* r);
-
-  static SeaGraph graph_;
-  std::vector<Region*> regions_;
-  std::vector<SignatureNode*> parameters_;
-  const art::DexFile& dex_file_;
-  const art::DexFile::CodeItem* code_item_;
-};
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_IR_SEA_H_
diff --git a/compiler/sea_ir/ir/sea_node.h b/compiler/sea_ir/ir/sea_node.h
deleted file mode 100644
index 4dab5cb..0000000
--- a/compiler/sea_ir/ir/sea_node.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_SEA_IR_IR_SEA_NODE_H_
-#define ART_COMPILER_SEA_IR_IR_SEA_NODE_H_
-
-#include "base/stringprintf.h"
-
-namespace sea_ir {
-class Region;
-class IRVisitor;
-
-class IVisitable {
- public:
-  virtual void Accept(IRVisitor* visitor) = 0;
-  virtual ~IVisitable() {}
-};
-
-// This abstract class provides the essential services that
-// we want each SEA IR element to have.
-// At the moment, these are:
-// - an id and corresponding string representation.
-// - a .dot graph language representation for .dot output.
-//
-// Note that SEA IR nodes could also be Regions, Projects
-// which are not instructions.
-class SeaNode: public IVisitable {
- public:
-  explicit SeaNode():id_(GetNewId()), string_id_() {
-    string_id_ = art::StringPrintf("%d", id_);
-  }
-
-  // Adds CFG predecessors and successors to each block.
-  void AddSuccessor(Region* successor);
-  void AddPredecessor(Region* predecesor);
-
-  // Returns the id of the current block as string
-  const std::string& StringId() const {
-    return string_id_;
-  }
-  // Returns the id of this node as int. The id is supposed to be unique among
-  // all instances of all subclasses of this class.
-  int Id() const {
-    return id_;
-  }
-
-  virtual ~SeaNode() { }
-
- protected:
-  static int GetNewId() {
-    return current_max_node_id_++;
-  }
-
-  const int id_;
-  std::string string_id_;
-
- private:
-  static int current_max_node_id_;
-  // Creating new instances of sea node objects should not be done through copy or assignment
-  // operators because that would lead to duplication of their unique ids.
-  DISALLOW_COPY_AND_ASSIGN(SeaNode);
-};
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_IR_SEA_NODE_H_
diff --git a/compiler/sea_ir/ir/visitor.h b/compiler/sea_ir/ir/visitor.h
deleted file mode 100644
index cc7b5d1..0000000
--- a/compiler/sea_ir/ir/visitor.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_SEA_IR_IR_VISITOR_H_
-#define ART_COMPILER_SEA_IR_IR_VISITOR_H_
-
-namespace sea_ir {
-
-class SeaGraph;
-class Region;
-class InstructionNode;
-class PhiInstructionNode;
-class SignatureNode;
-class UnnamedConstInstructionNode;
-class ConstInstructionNode;
-class ReturnInstructionNode;
-class IfNeInstructionNode;
-class AddIntLit8InstructionNode;
-class MoveResultInstructionNode;
-class InvokeStaticInstructionNode;
-class AddIntInstructionNode;
-class AddIntLitInstructionNode;
-class GotoInstructionNode;
-class IfEqzInstructionNode;
-
-
-
-
-class IRVisitor {
- public:
-  explicit IRVisitor(): ordered_regions_() { }
-  virtual void Initialize(SeaGraph* graph) = 0;
-  virtual void Visit(SeaGraph* graph) = 0;
-  virtual void Visit(Region* region) = 0;
-  virtual void Visit(PhiInstructionNode* region) = 0;
-  virtual void Visit(SignatureNode* region) = 0;
-
-  virtual void Visit(InstructionNode* region) = 0;
-  virtual void Visit(ConstInstructionNode* instruction) = 0;
-  virtual void Visit(UnnamedConstInstructionNode* instruction) = 0;
-  virtual void Visit(ReturnInstructionNode* instruction) = 0;
-  virtual void Visit(IfNeInstructionNode* instruction) = 0;
-  virtual void Visit(MoveResultInstructionNode* instruction) = 0;
-  virtual void Visit(InvokeStaticInstructionNode* instruction) = 0;
-  virtual void Visit(AddIntInstructionNode* instruction) = 0;
-  virtual void Visit(GotoInstructionNode* instruction) = 0;
-  virtual void Visit(IfEqzInstructionNode* instruction) = 0;
-
-  // Note: This flavor of visitor separates the traversal functions from the actual visiting part
-  //       so that the Visitor subclasses don't duplicate code and can't get the traversal wrong.
-  //       The disadvantage is the increased number of functions (and calls).
-  virtual void Traverse(SeaGraph* graph);
-  virtual void Traverse(Region* region);
-  // The following functions are meant to be empty and not pure virtual,
-  // because the parameter classes have no children to traverse.
-  virtual void Traverse(InstructionNode* region) { }
-  virtual void Traverse(ConstInstructionNode* instruction) { }
-  virtual void Traverse(ReturnInstructionNode* instruction) { }
-  virtual void Traverse(IfNeInstructionNode* instruction) { }
-  virtual void Traverse(AddIntLit8InstructionNode* instruction) { }
-  virtual void Traverse(MoveResultInstructionNode* instruction) { }
-  virtual void Traverse(InvokeStaticInstructionNode* instruction) { }
-  virtual void Traverse(AddIntInstructionNode* instruction) { }
-  virtual void Traverse(GotoInstructionNode* instruction) { }
-  virtual void Traverse(IfEqzInstructionNode* instruction) { }
-  virtual void Traverse(PhiInstructionNode* phi) { }
-  virtual void Traverse(SignatureNode* sig) { }
-  virtual ~IRVisitor() { }
-
- protected:
-  std::vector<Region*> ordered_regions_;
-};
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_IR_VISITOR_H_
diff --git a/compiler/sea_ir/types/type_data_test.cc b/compiler/sea_ir/types/type_data_test.cc
deleted file mode 100644
index 42c6973..0000000
--- a/compiler/sea_ir/types/type_data_test.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "common_compiler_test.h"
-#include "sea_ir/types/types.h"
-
-namespace sea_ir {
-
-class TypeDataTest : public art::CommonCompilerTest {};
-
-TEST_F(TypeDataTest, Basics) {
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  int first_instruction_id = 1;
-  int second_instruction_id = 3;
-  EXPECT_TRUE(NULL == td.FindTypeOf(first_instruction_id));
-  const Type* int_type = &type_cache.Integer();
-  const Type* byte_type = &type_cache.Byte();
-  td.SetTypeOf(first_instruction_id, int_type);
-  EXPECT_TRUE(int_type == td.FindTypeOf(first_instruction_id));
-  EXPECT_TRUE(NULL == td.FindTypeOf(second_instruction_id));
-  td.SetTypeOf(second_instruction_id, byte_type);
-  EXPECT_TRUE(int_type == td.FindTypeOf(first_instruction_id));
-  EXPECT_TRUE(byte_type == td.FindTypeOf(second_instruction_id));
-}
-
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/types/type_inference.cc b/compiler/sea_ir/types/type_inference.cc
deleted file mode 100644
index 1731987..0000000
--- a/compiler/sea_ir/types/type_inference.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "scoped_thread_state_change.h"
-#include "sea_ir/types/type_inference.h"
-#include "sea_ir/types/type_inference_visitor.h"
-#include "sea_ir/ir/sea.h"
-
-namespace sea_ir {
-
-bool TypeInference::IsPrimitiveDescriptor(char descriptor) {
-  switch (descriptor) {
-  case 'I':
-  case 'C':
-  case 'S':
-  case 'B':
-  case 'Z':
-  case 'F':
-  case 'D':
-  case 'J':
-    return true;
-  default:
-    return false;
-  }
-}
-
-FunctionTypeInfo::FunctionTypeInfo(const SeaGraph* graph, art::verifier::RegTypeCache* types)
-    : dex_file_(graph->GetDexFile()), dex_method_idx_(graph->method_idx_), type_cache_(types),
-    method_access_flags_(graph->method_access_flags_) {
-  const art::DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
-  const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
-  declaring_class_ = &(type_cache_->FromDescriptor(NULL, descriptor, false));
-}
-
-FunctionTypeInfo::FunctionTypeInfo(const SeaGraph* graph, InstructionNode* inst,
-    art::verifier::RegTypeCache* types): dex_file_(graph->GetDexFile()),
-        dex_method_idx_(inst->GetInstruction()->VRegB_35c()), type_cache_(types),
-        method_access_flags_(0) {
-  // TODO: Test that GetDeclaredArgumentTypes() works correctly when using this constructor.
-  const art::DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
-  const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
-  declaring_class_ = &(type_cache_->FromDescriptor(NULL, descriptor, false));
-}
-
-const Type* FunctionTypeInfo::GetReturnValueType() {
-  const art::DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
-  uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
-  const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
-  art::ScopedObjectAccess soa(art::Thread::Current());
-  const Type& return_type = type_cache_->FromDescriptor(NULL, descriptor, false);
-  return &return_type;
-}
-
-
-
-std::vector<const Type*> FunctionTypeInfo::GetDeclaredArgumentTypes() {
-  art::ScopedObjectAccess soa(art::Thread::Current());
-  std::vector<const Type*> argument_types;
-  // TODO: The additional (fake) Method parameter is added on the first position,
-  //       but is represented as integer because we don't support  pointers yet.
-  argument_types.push_back(&(type_cache_->Integer()));
-  // Include the "this" pointer.
-  size_t cur_arg = 0;
-  if (!IsStatic()) {
-    // If this is a constructor for a class other than java.lang.Object, mark the first ("this")
-    // argument as uninitialized. This restricts field access until the superclass constructor is
-    // called.
-    const art::verifier::RegType& declaring_class = GetDeclaringClass();
-    if (IsConstructor() && !declaring_class.IsJavaLangObject()) {
-      argument_types.push_back(&(type_cache_->UninitializedThisArgument(declaring_class)));
-    } else {
-      argument_types.push_back(&declaring_class);
-    }
-    cur_arg++;
-  }
-  // Include the types of the parameters in the Java method signature.
-  const art::DexFile::ProtoId& proto_id =
-      dex_file_->GetMethodPrototype(dex_file_->GetMethodId(dex_method_idx_));
-  art::DexFileParameterIterator iterator(*dex_file_, proto_id);
-
-  for (; iterator.HasNext(); iterator.Next()) {
-    const char* descriptor = iterator.GetDescriptor();
-    if (descriptor == NULL) {
-      LOG(FATAL) << "Error: Encountered null type descriptor for function argument.";
-    }
-    switch (descriptor[0]) {
-      case 'L':
-      case '[':
-        // We assume that reference arguments are initialized. The only way it could be otherwise
-        // (assuming the caller was verified) is if the current method is <init>, but in that case
-        // it's effectively considered initialized the instant we reach here (in the sense that we
-        // can return without doing anything or call virtual methods).
-        {
-          const Type& reg_type = type_cache_->FromDescriptor(NULL, descriptor, false);
-          argument_types.push_back(&reg_type);
-        }
-        break;
-      case 'Z':
-        argument_types.push_back(&type_cache_->Boolean());
-        break;
-      case 'C':
-        argument_types.push_back(&type_cache_->Char());
-        break;
-      case 'B':
-        argument_types.push_back(&type_cache_->Byte());
-        break;
-      case 'I':
-        argument_types.push_back(&type_cache_->Integer());
-        break;
-      case 'S':
-        argument_types.push_back(&type_cache_->Short());
-        break;
-      case 'F':
-        argument_types.push_back(&type_cache_->Float());
-        break;
-      case 'J':
-      case 'D': {
-        // TODO: Figure out strategy for two-register operands (double, long)
-        LOG(FATAL) << "Error: Type inference for 64-bit variables has not been implemented.";
-        break;
-      }
-      default:
-        LOG(FATAL) << "Error: Unexpected signature encountered during type inference.";
-    }
-    cur_arg++;
-  }
-  return argument_types;
-}
-
-// TODO: Lock is only used for dumping types (during development). Remove this for performance.
-void TypeInference::ComputeTypes(SeaGraph* graph) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  std::vector<Region*>* regions = graph->GetRegions();
-  std::list<InstructionNode*> worklist;
-  // Fill the work-list with all instructions.
-  for (std::vector<Region*>::const_iterator region_it = regions->begin();
-      region_it != regions->end(); region_it++) {
-    std::vector<PhiInstructionNode*>* phi_instructions = (*region_it)->GetPhiNodes();
-    std::copy(phi_instructions->begin(), phi_instructions->end(), std::back_inserter(worklist));
-    std::vector<InstructionNode*>* instructions = (*region_it)->GetInstructions();
-    std::copy(instructions->begin(), instructions->end(), std::back_inserter(worklist));
-  }
-  TypeInferenceVisitor tiv(graph, &type_data_, type_cache_);
-  // Record return type of the function.
-  graph->Accept(&tiv);
-  const Type* new_type = tiv.GetType();
-  type_data_.SetTypeOf(-1, new_type);   // TODO: Record this info in a way that
-                                        //      does not need magic constants.
-                                        //      Make SeaGraph a SeaNode?
-
-  // Sparse (SSA) fixed-point algorithm that processes each instruction in the work-list,
-  // adding consumers of instructions whose result changed type back into the work-list.
-  // Note: According to [1] list iterators should not be invalidated on insertion,
-  //       which simplifies the implementation; not 100% sure other STL implementations
-  //       maintain this invariant, but they should.
-  //       [1] http://www.sgi.com/tech/stl/List.html
-  // TODO: Making this conditional (as in sparse conditional constant propagation) would be good.
-  // TODO: Remove elements as I go.
-  for (std::list<InstructionNode*>::const_iterator instruction_it = worklist.begin();
-        instruction_it != worklist.end(); instruction_it++) {
-    (*instruction_it)->Accept(&tiv);
-    const Type* old_type = type_data_.FindTypeOf((*instruction_it)->Id());
-    const Type* new_type = tiv.GetType();
-    bool type_changed = (old_type != new_type);
-    if (type_changed) {
-      type_data_.SetTypeOf((*instruction_it)->Id(), new_type);
-      // Add SSA consumers of the current instruction to the work-list.
-      std::vector<InstructionNode*>* consumers = (*instruction_it)->GetSSAConsumers();
-      for (std::vector<InstructionNode*>::iterator consumer = consumers->begin();
-          consumer != consumers->end(); consumer++) {
-        worklist.push_back(*consumer);
-      }
-    }
-  }
-}
-}   // namespace sea_ir
diff --git a/compiler/sea_ir/types/type_inference.h b/compiler/sea_ir/types/type_inference.h
deleted file mode 100644
index 7a178b2..0000000
--- a/compiler/sea_ir/types/type_inference.h
+++ /dev/null
@@ -1,91 +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.
- */
-
-#ifndef ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_
-#define ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_
-
-#include "safe_map.h"
-#include "dex_file-inl.h"
-#include "sea_ir/types/types.h"
-
-namespace sea_ir {
-
-class SeaGraph;
-class InstructionNode;
-
-// The type inference in SEA IR is different from the verifier in that it is concerned
-// with a rich type hierarchy (TODO) usable in optimization and does not perform
-// precise verification (which is the job of the verifier).
-class TypeInference {
- public:
-  TypeInference() : type_cache_(new art::verifier::RegTypeCache(false)) {
-  }
-
-  // Computes the types for the method with SEA IR representation provided by @graph.
-  void ComputeTypes(SeaGraph* graph);
-
-  art::SafeMap<int, const Type*>* GetTypeMap() {
-    return type_data_.GetTypeMap();
-  }
-  // Returns true if @descriptor corresponds to a primitive type.
-  static bool IsPrimitiveDescriptor(char descriptor);
-  TypeData type_data_;    // TODO: Make private, add accessor and not publish a SafeMap above.
-  art::verifier::RegTypeCache* const type_cache_;    // TODO: Make private.
-};
-
-// Stores information about the exact type of  a function.
-class FunctionTypeInfo {
- public:
-  // Finds method information about the method encoded by a SEA IR graph.
-  // @graph provides the input method SEA IR representation.
-  // @types provides the input cache of types from which the
-  //        parameter types of the function are found.
-  FunctionTypeInfo(const SeaGraph* graph, art::verifier::RegTypeCache* types);
-  // Finds method information about the method encoded by
-  // an invocation instruction in a SEA IR graph.
-  // @graph provides the input method SEA IR representation.
-  // @inst  is an invocation instruction for the desired method.
-  // @types provides the input cache of types from which the
-  //        parameter types of the function are found.
-  FunctionTypeInfo(const SeaGraph* graph, InstructionNode* inst,
-      art::verifier::RegTypeCache* types);
-  // Returns the ordered vector of types corresponding to the function arguments.
-  std::vector<const Type*> GetDeclaredArgumentTypes();
-  // Returns the declared return value type.
-  const Type* GetReturnValueType();
-  // Returns the type corresponding to the class that declared the method.
-  const Type& GetDeclaringClass() {
-    return *declaring_class_;
-  }
-
-  bool IsConstructor() const {
-    return (method_access_flags_ & kAccConstructor) != 0;
-  }
-
-  bool IsStatic() const {
-    return (method_access_flags_ & kAccStatic) != 0;
-  }
-
- protected:
-  const Type* declaring_class_;
-  const art::DexFile* dex_file_;
-  const uint32_t dex_method_idx_;
-  art::verifier::RegTypeCache* type_cache_;
-  const uint32_t method_access_flags_;  // Method's access flags.
-};
-}  // namespace sea_ir
-
-#endif  // ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_
diff --git a/compiler/sea_ir/types/type_inference_visitor.cc b/compiler/sea_ir/types/type_inference_visitor.cc
deleted file mode 100644
index 27bb5d8..0000000
--- a/compiler/sea_ir/types/type_inference_visitor.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "scoped_thread_state_change.h"
-#include "sea_ir/types/type_inference_visitor.h"
-#include "sea_ir/types/type_inference.h"
-#include "sea_ir/ir/sea.h"
-
-namespace sea_ir {
-
-void TypeInferenceVisitor::Visit(SeaGraph* graph) {
-  FunctionTypeInfo fti(graph_, type_cache_);
-  const Type* return_type = fti.GetReturnValueType();
-  crt_type_.push_back(return_type);
-}
-
-void TypeInferenceVisitor::Visit(SignatureNode* parameter) {
-  FunctionTypeInfo fti(graph_, type_cache_);
-  std::vector<const Type*> arguments = fti.GetDeclaredArgumentTypes();
-  DCHECK_LT(parameter->GetPositionInSignature(), arguments.size())
-    << "Signature node position not present in signature.";
-  crt_type_.push_back(arguments.at(parameter->GetPositionInSignature()));
-}
-
-void TypeInferenceVisitor::Visit(UnnamedConstInstructionNode* instruction) {
-  crt_type_.push_back(&type_cache_->Integer());
-}
-
-void TypeInferenceVisitor::Visit(PhiInstructionNode* instruction) {
-  std::vector<const Type*> types_to_merge = GetOperandTypes(instruction);
-  const Type* result_type = MergeTypes(types_to_merge);
-  crt_type_.push_back(result_type);
-}
-
-void TypeInferenceVisitor::Visit(AddIntInstructionNode* instruction) {
-  std::vector<const Type*> operand_types = GetOperandTypes(instruction);
-  for (std::vector<const Type*>::const_iterator cit = operand_types.begin();
-      cit != operand_types.end(); cit++) {
-    if (*cit != NULL) {
-      DCHECK((*cit)->IsInteger());
-    }
-  }
-  crt_type_.push_back(&type_cache_->Integer());
-}
-
-void TypeInferenceVisitor::Visit(MoveResultInstructionNode* instruction) {
-  std::vector<const Type*> operand_types = GetOperandTypes(instruction);
-  const Type* operand_type = operand_types.at(0);
-  crt_type_.push_back(operand_type);
-}
-
-void TypeInferenceVisitor::Visit(InvokeStaticInstructionNode* instruction) {
-  FunctionTypeInfo fti(graph_, instruction, type_cache_);
-  const Type* result_type = fti.GetReturnValueType();
-  crt_type_.push_back(result_type);
-}
-
-std::vector<const Type*> TypeInferenceVisitor::GetOperandTypes(
-    InstructionNode* instruction) const {
-  std::vector<InstructionNode*> sources = instruction->GetSSAProducers();
-  std::vector<const Type*> types_to_merge;
-  for (std::vector<InstructionNode*>::const_iterator cit = sources.begin(); cit != sources.end();
-      cit++) {
-    const Type* source_type = type_data_->FindTypeOf((*cit)->Id());
-    if (source_type != NULL) {
-      types_to_merge.push_back(source_type);
-    }
-  }
-  return types_to_merge;
-}
-
-const Type* TypeInferenceVisitor::MergeTypes(std::vector<const Type*>& types) const {
-  const Type* type = NULL;
-  if (types.size() > 0) {
-    type = *(types.begin());
-    if (types.size() > 1) {
-      for (std::vector<const Type*>::const_iterator cit = types.begin();
-          cit != types.end(); cit++) {
-        if (!type->Equals(**cit)) {
-          type = MergeTypes(type, *cit);
-        }
-      }
-    }
-  }
-  return type;
-}
-
-const Type* TypeInferenceVisitor::MergeTypes(const Type* t1, const Type* t2) const {
-  DCHECK(t2 != NULL);
-  DCHECK(t1 != NULL);
-  art::ScopedObjectAccess soa(art::Thread::Current());
-  const Type* result = &(t1->Merge(*t2, type_cache_));
-  return result;
-}
-
-}   // namespace sea_ir
diff --git a/compiler/sea_ir/types/type_inference_visitor.h b/compiler/sea_ir/types/type_inference_visitor.h
deleted file mode 100644
index d715151..0000000
--- a/compiler/sea_ir/types/type_inference_visitor.h
+++ /dev/null
@@ -1,81 +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.
- */
-
-#ifndef ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_
-#define ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_
-
-
-#include "dex_file-inl.h"
-#include "sea_ir/ir/visitor.h"
-#include "sea_ir/types/types.h"
-
-namespace sea_ir {
-
-// The TypeInferenceVisitor visits each instruction and computes its type taking into account
-//   the current type of the operands. The type is stored in the visitor.
-// We may be better off by using a separate visitor type hierarchy that has return values
-//   or that passes data as parameters, than to use fields to store information that should
-//   in fact be returned after visiting each element. Ideally, I would prefer to use templates
-//   to specify the returned value type, but I am not aware of a possible implementation
-//   that does not horribly duplicate the visitor infrastructure code (version 1: no return value,
-//   version 2: with template return value).
-class TypeInferenceVisitor: public IRVisitor {
- public:
-  TypeInferenceVisitor(SeaGraph* graph, TypeData* type_data,
-      art::verifier::RegTypeCache* types):
-    graph_(graph), type_data_(type_data), type_cache_(types), crt_type_() {
-  }
-  // There are no type related actions to be performed on these classes.
-  void Initialize(SeaGraph* graph) { }
-  void Visit(SeaGraph* graph);
-  void Visit(Region* region) { }
-
-  void Visit(PhiInstructionNode* instruction);
-  void Visit(SignatureNode* parameter);
-  void Visit(InstructionNode* instruction) { }
-  void Visit(UnnamedConstInstructionNode* instruction);
-  void Visit(ConstInstructionNode* instruction) { }
-  void Visit(ReturnInstructionNode* instruction) { }
-  void Visit(IfNeInstructionNode* instruction) { }
-  void Visit(MoveResultInstructionNode* instruction);
-  void Visit(InvokeStaticInstructionNode* instruction);
-  void Visit(AddIntInstructionNode* instruction);
-  void Visit(GotoInstructionNode* instruction) { }
-  void Visit(IfEqzInstructionNode* instruction) { }
-
-  const Type* MergeTypes(std::vector<const Type*>& types) const;
-  const Type* MergeTypes(const Type* t1, const Type* t2) const;
-  std::vector<const Type*> GetOperandTypes(InstructionNode* instruction) const;
-  const Type* GetType() {
-    // TODO: Currently multiple defined types are not supported.
-    if (!crt_type_.empty()) {
-      const Type* single_type = crt_type_.at(0);
-      crt_type_.clear();
-      return single_type;
-    }
-    return NULL;
-  }
-
- protected:
-  const SeaGraph* const graph_;
-  TypeData* type_data_;
-  art::verifier::RegTypeCache* type_cache_;
-  std::vector<const Type*> crt_type_;             // Stored temporarily between two calls to Visit.
-};
-
-}  // namespace sea_ir
-
-#endif  // ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_
diff --git a/compiler/sea_ir/types/type_inference_visitor_test.cc b/compiler/sea_ir/types/type_inference_visitor_test.cc
deleted file mode 100644
index ccb6991..0000000
--- a/compiler/sea_ir/types/type_inference_visitor_test.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "common_compiler_test.h"
-#include "sea_ir/types/type_inference_visitor.h"
-#include "sea_ir/ir/sea.h"
-
-namespace sea_ir {
-
-class TestInstructionNode:public InstructionNode {
- public:
-  explicit TestInstructionNode(std::vector<InstructionNode*> prods): InstructionNode(NULL),
-      producers_(prods) { }
-  std::vector<InstructionNode*> GetSSAProducers() {
-    return producers_;
-  }
- protected:
-  std::vector<InstructionNode*> producers_;
-};
-
-class TypeInferenceVisitorTest : public art::CommonCompilerTest {};
-
-TEST_F(TypeInferenceVisitorTest, MergeIntWithByte) {
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  TypeInferenceVisitor tiv(NULL, &td, &type_cache);
-  const Type* int_type = &type_cache.Integer();
-  const Type* byte_type = &type_cache.Byte();
-  const Type* ib_type = tiv.MergeTypes(int_type, byte_type);
-  const Type* bi_type = tiv.MergeTypes(byte_type, int_type);
-  EXPECT_TRUE(ib_type == int_type);
-  EXPECT_TRUE(bi_type == int_type);
-}
-
-TEST_F(TypeInferenceVisitorTest, MergeIntWithShort) {
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  TypeInferenceVisitor tiv(NULL, &td, &type_cache);
-  const Type* int_type = &type_cache.Integer();
-  const Type* short_type = &type_cache.Short();
-  const Type* is_type = tiv.MergeTypes(int_type, short_type);
-  const Type* si_type = tiv.MergeTypes(short_type, int_type);
-  EXPECT_TRUE(is_type == int_type);
-  EXPECT_TRUE(si_type == int_type);
-}
-
-TEST_F(TypeInferenceVisitorTest, MergeMultipleInts) {
-  int N = 10;  // Number of types to merge.
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  TypeInferenceVisitor tiv(NULL, &td, &type_cache);
-  std::vector<const Type*> types;
-  for (int i = 0; i < N; i++) {
-    const Type* new_type = &type_cache.Integer();
-    types.push_back(new_type);
-  }
-  const Type* merged_type = tiv.MergeTypes(types);
-  EXPECT_TRUE(merged_type == &type_cache.Integer());
-}
-
-TEST_F(TypeInferenceVisitorTest, MergeMultipleShorts) {
-  int N = 10;  // Number of types to merge.
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  TypeInferenceVisitor tiv(NULL, &td, &type_cache);
-  std::vector<const Type*> types;
-  for (int i = 0; i < N; i++) {
-    const Type* new_type = &type_cache.Short();
-    types.push_back(new_type);
-  }
-  const Type* merged_type = tiv.MergeTypes(types);
-  EXPECT_TRUE(merged_type == &type_cache.Short());
-}
-
-TEST_F(TypeInferenceVisitorTest, MergeMultipleIntsWithShorts) {
-  int N = 10;  // Number of types to merge.
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  TypeInferenceVisitor tiv(NULL, &td, &type_cache);
-  std::vector<const Type*> types;
-  for (int i = 0; i < N; i++) {
-    const Type* short_type = &type_cache.Short();
-    const Type* int_type = &type_cache.Integer();
-    types.push_back(short_type);
-    types.push_back(int_type);
-  }
-  const Type* merged_type = tiv.MergeTypes(types);
-  EXPECT_TRUE(merged_type == &type_cache.Integer());
-}
-
-TEST_F(TypeInferenceVisitorTest, GetOperandTypes) {
-  int N = 10;  // Number of types to merge.
-  TypeData td;
-  art::verifier::RegTypeCache type_cache(false);
-  TypeInferenceVisitor tiv(NULL, &td, &type_cache);
-  std::vector<const Type*> types;
-  std::vector<InstructionNode*> preds;
-  for (int i = 0; i < N; i++) {
-    const Type* short_type = &type_cache.Short();
-    const Type* int_type = &type_cache.Integer();
-    TestInstructionNode* short_inst =
-        new TestInstructionNode(std::vector<InstructionNode*>());
-    TestInstructionNode* int_inst =
-        new TestInstructionNode(std::vector<InstructionNode*>());
-    preds.push_back(short_inst);
-    preds.push_back(int_inst);
-    td.SetTypeOf(short_inst->Id(), short_type);
-    td.SetTypeOf(int_inst->Id(), int_type);
-    types.push_back(short_type);
-    types.push_back(int_type);
-  }
-  TestInstructionNode* inst_to_test = new TestInstructionNode(preds);
-  std::vector<const Type*> result = tiv.GetOperandTypes(inst_to_test);
-  EXPECT_TRUE(result.size() == types.size());
-  EXPECT_TRUE(true == std::equal(types.begin(), types.begin() + 2, result.begin()));
-}
-
-
-}  // namespace sea_ir
diff --git a/compiler/sea_ir/types/types.h b/compiler/sea_ir/types/types.h
deleted file mode 100644
index 64f2524..0000000
--- a/compiler/sea_ir/types/types.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_SEA_IR_TYPES_TYPES_H_
-#define ART_COMPILER_SEA_IR_TYPES_TYPES_H_
-
-#include "safe_map.h"
-#include "verifier/reg_type.h"
-#include "verifier/reg_type_cache.h"
-
-namespace sea_ir {
-
-// TODO: Replace typedef with an actual class implementation when we have more types.
-typedef art::verifier::RegType Type;
-
-// Stores information about the result type of each instruction.
-// Note: Main purpose is to encapsulate the map<instruction id, type*>,
-//       so that we can replace the underlying storage at any time.
-class TypeData {
- public:
-  art::SafeMap<int, const Type*>* GetTypeMap() {
-    return &type_map_;
-  }
-  // Returns the type associated with instruction with @instruction_id.
-  const Type* FindTypeOf(int instruction_id) {
-    art::SafeMap<int, const Type*>::const_iterator result_it = type_map_.find(instruction_id);
-    if (type_map_.end() != result_it) {
-      return result_it->second;
-    }
-    return NULL;
-  }
-
-  // Saves the fact that instruction @instruction_id produces a value of type @type.
-  void SetTypeOf(int instruction_id, const Type* type) {
-    type_map_.Overwrite(instruction_id, type);
-  }
-
- private:
-  art::SafeMap<int, const Type*> type_map_;
-};
-
-
-
-}  // namespace sea_ir
-#endif  // ART_COMPILER_SEA_IR_TYPES_TYPES_H_
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index 6da375a..cb51ed8 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -20,6 +20,7 @@
 #include "utils/arm/assembler_arm.h"
 #include "utils/arm64/assembler_arm64.h"
 #include "utils/mips/assembler_mips.h"
+#include "utils/mips64/assembler_mips64.h"
 #include "utils/x86/assembler_x86.h"
 #include "utils/x86_64/assembler_x86_64.h"
 
@@ -40,8 +41,7 @@
       __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
       __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
       break;
-    case kPortableAbi:  // R9 holds Thread*.
-    case kQuickAbi:  // Fall-through.
+    case kQuickAbi:  // R9 holds Thread*.
       __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
   }
   __ bkpt(0);
@@ -62,27 +62,27 @@
 
   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));
+    case kQuickAbi:  // X18 holds Thread*.
+      __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
+                Arm64ManagedRegister::FromXRegister(IP0));
 
       break;
   }
 
+  assembler->EmitSlowPaths();
   size_t cs = assembler->CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
@@ -105,8 +105,7 @@
       __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
       __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
       break;
-    case kPortableAbi:  // S1 holds Thread*.
-    case kQuickAbi:  // Fall-through.
+    case kQuickAbi:  // S1 holds Thread*.
       __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
   }
   __ Jr(T9);
@@ -122,6 +121,35 @@
 }
 }  // namespace mips
 
+namespace mips64 {
+static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
+                                                    ThreadOffset<8> offset) {
+  std::unique_ptr<Mips64Assembler> assembler(static_cast<Mips64Assembler*>(Assembler::Create(kMips64)));
+
+  switch (abi) {
+    case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
+      __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
+      break;
+    case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
+      __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
+      __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
+      break;
+    case kQuickAbi:  // Fall-through.
+      __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
+  }
+  __ Jr(T9);
+  __ Nop();
+  __ Break();
+
+  size_t cs = assembler->CodeSize();
+  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+}  // namespace mips64
+
 namespace x86 {
 static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
   std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
@@ -162,11 +190,13 @@
   switch (isa) {
     case kArm64:
       return arm64::CreateTrampoline(abi, offset);
+    case kMips64:
+      return mips64::CreateTrampoline(abi, offset);
     case kX86_64:
       return x86_64::CreateTrampoline(offset);
     default:
       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
-      return nullptr;
+      UNREACHABLE();
   }
 }
 
@@ -182,7 +212,7 @@
       return x86::CreateTrampoline(offset);
     default:
       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
-      return nullptr;
+      UNREACHABLE();
   }
 }
 
diff --git a/compiler/utils/allocation.h b/compiler/utils/allocation.h
deleted file mode 100644
index b0947ca..0000000
--- a/compiler/utils/allocation.h
+++ /dev/null
@@ -1,50 +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_UTILS_ALLOCATION_H_
-#define ART_COMPILER_UTILS_ALLOCATION_H_
-
-#include "arena_allocator.h"
-#include "base/logging.h"
-
-namespace art {
-
-class ArenaObject {
- public:
-  // Allocate a new ArenaObject of 'size' bytes in the Arena.
-  void* operator new(size_t size, ArenaAllocator* allocator) {
-    return allocator->Alloc(size, kArenaAllocMisc);
-  }
-
-  void operator delete(void*, size_t) {
-    LOG(FATAL) << "UNREACHABLE";
-  }
-};
-
-class ValueObject {
- public:
-  void* operator new(size_t size) {
-    LOG(FATAL) << "UNREACHABLE";
-    abort();
-  }
-  void operator delete(void*, size_t) {
-    LOG(FATAL) << "UNREACHABLE";
-  }
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_UTILS_ALLOCATION_H_
diff --git a/compiler/utils/arena_allocator.cc b/compiler/utils/arena_allocator.cc
index 516ac2b..a80ad93 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"
@@ -113,7 +114,7 @@
        << num_allocations << ", avg size: " << bytes_allocated / num_allocations << "\n";
   }
   os << "===== Allocation by kind\n";
-  COMPILE_ASSERT(arraysize(kAllocNames) == kNumArenaAllocKinds, check_arraysize_kAllocNames);
+  static_assert(arraysize(kAllocNames) == kNumArenaAllocKinds, "arraysize of kAllocNames");
   for (int i = 0; i < kNumArenaAllocKinds; i++) {
       os << kAllocNames[i] << std::setw(10) << alloc_stats_[i] << "\n";
   }
@@ -188,6 +189,15 @@
   return ret;
 }
 
+size_t ArenaPool::GetBytesAllocated() const {
+  size_t total = 0;
+  MutexLock lock(Thread::Current(), lock_);
+  for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
+    total += arena->GetBytesAllocated();
+  }
+  return total;
+}
+
 void ArenaPool::FreeArenaChain(Arena* first) {
   if (UNLIKELY(RUNNING_ON_VALGRIND > 0)) {
     for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
diff --git a/compiler/utils/arena_allocator.h b/compiler/utils/arena_allocator.h
index b2f5ca9..7f5bc9a 100644
--- a/compiler/utils/arena_allocator.h
+++ b/compiler/utils/arena_allocator.h
@@ -82,7 +82,7 @@
   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
 
   void Copy(const ArenaAllocatorStatsImpl& other) { UNUSED(other); }
-  void RecordAlloc(size_t bytes, ArenaAllocKind kind) { UNUSED(bytes); UNUSED(kind); }
+  void RecordAlloc(size_t bytes, ArenaAllocKind kind) { UNUSED(bytes, kind); }
   size_t NumAllocations() const { return 0u; }
   size_t BytesAllocated() const { return 0u; }
   void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const {
@@ -135,6 +135,10 @@
     return Size() - bytes_allocated_;
   }
 
+  size_t GetBytesAllocated() const {
+    return bytes_allocated_;
+  }
+
  private:
   size_t bytes_allocated_;
   uint8_t* memory_;
@@ -153,11 +157,12 @@
  public:
   ArenaPool();
   ~ArenaPool();
-  Arena* AllocArena(size_t size);
-  void FreeArenaChain(Arena* first);
+  Arena* AllocArena(size_t size) LOCKS_EXCLUDED(lock_);
+  void FreeArenaChain(Arena* first) LOCKS_EXCLUDED(lock_);
+  size_t GetBytesAllocated() const LOCKS_EXCLUDED(lock_);
 
  private:
-  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   Arena* free_arenas_ GUARDED_BY(lock_);
   DISALLOW_COPY_AND_ASSIGN(ArenaPool);
 };
diff --git a/compiler/utils/arena_bit_vector.cc b/compiler/utils/arena_bit_vector.cc
index de35f3d..f17e5a9 100644
--- a/compiler/utils/arena_bit_vector.cc
+++ b/compiler/utils/arena_bit_vector.cc
@@ -16,12 +16,12 @@
 
 #include "arena_allocator.h"
 #include "arena_bit_vector.h"
-#include "base/allocator.h"
 
 namespace art {
 
 template <typename ArenaAlloc>
-class ArenaBitVectorAllocator FINAL : public Allocator {
+class ArenaBitVectorAllocator FINAL : public Allocator,
+    public ArenaObject<kArenaAllocGrowableBitMap> {
  public:
   explicit ArenaBitVectorAllocator(ArenaAlloc* arena) : arena_(arena) {}
   ~ArenaBitVectorAllocator() {}
@@ -32,11 +32,6 @@
 
   virtual void Free(void*) {}  // Nop.
 
-  static void* operator new(size_t size, ArenaAlloc* arena) {
-    return arena->Alloc(sizeof(ArenaBitVectorAllocator), kArenaAllocGrowableBitMap);
-  }
-  static void operator delete(void* p) {}  // Nop.
-
  private:
   ArenaAlloc* const arena_;
   DISALLOW_COPY_AND_ASSIGN(ArenaBitVectorAllocator);
diff --git a/compiler/utils/arena_bit_vector.h b/compiler/utils/arena_bit_vector.h
index c92658f..34f1ca9 100644
--- a/compiler/utils/arena_bit_vector.h
+++ b/compiler/utils/arena_bit_vector.h
@@ -17,12 +17,14 @@
 #ifndef ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
 #define ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
 
+#include "arena_object.h"
 #include "base/bit_vector.h"
-#include "utils/arena_allocator.h"
-#include "utils/scoped_arena_allocator.h"
 
 namespace art {
 
+class ArenaAllocator;
+class ScopedArenaAllocator;
+
 // Type of growable bitmap for memory tuning.
 enum OatBitMapKind {
   kBitMapMisc = 0,
@@ -50,7 +52,7 @@
 /*
  * A BitVector implementation that uses Arena allocation.
  */
-class ArenaBitVector : public BitVector {
+class ArenaBitVector : public BitVector, public ArenaObject<kArenaAllocGrowableBitMap> {
  public:
   ArenaBitVector(ArenaAllocator* arena, uint32_t start_bits, bool expandable,
                  OatBitMapKind kind = kBitMapMisc);
@@ -58,16 +60,10 @@
                  OatBitMapKind kind = kBitMapMisc);
   ~ArenaBitVector() {}
 
-  static void* operator new(size_t size, ArenaAllocator* arena) {
-    return arena->Alloc(sizeof(ArenaBitVector), kArenaAllocGrowableBitMap);
-  }
-  static void* operator new(size_t size, ScopedArenaAllocator* arena) {
-    return arena->Alloc(sizeof(ArenaBitVector), kArenaAllocGrowableBitMap);
-  }
-  static void operator delete(void* p) {}  // Nop.
-
  private:
   const OatBitMapKind kind_;      // for memory use tuning. TODO: currently unused.
+
+  DISALLOW_COPY_AND_ASSIGN(ArenaBitVector);
 };
 
 
diff --git a/compiler/utils/arena_containers.h b/compiler/utils/arena_containers.h
index c48b0c8..8252591 100644
--- a/compiler/utils/arena_containers.h
+++ b/compiler/utils/arena_containers.h
@@ -66,7 +66,7 @@
 class ArenaAllocatorAdapterKindImpl<false> {
  public:
   // Not tracking allocations, ignore the supplied kind and arbitrarily provide kArenaAllocSTL.
-  explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind) { }
+  explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind) { UNUSED(kind); }
   ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl& other) = default;
   ArenaAllocKind Kind() { return kArenaAllocSTL; }
 };
@@ -159,11 +159,13 @@
   const_pointer address(const_reference x) const { return &x; }
 
   pointer allocate(size_type n, ArenaAllocatorAdapter<void>::pointer hint = nullptr) {
+    UNUSED(hint);
     DCHECK_LE(n, max_size());
     return reinterpret_cast<T*>(arena_allocator_->Alloc(n * sizeof(T),
                                                         ArenaAllocatorAdapterKind::Kind()));
   }
   void deallocate(pointer p, size_type n) {
+    UNUSED(p, n);
   }
 
   void construct(pointer p, const_reference val) {
diff --git a/compiler/utils/arena_object.h b/compiler/utils/arena_object.h
new file mode 100644
index 0000000..d64c419
--- /dev/null
+++ b/compiler/utils/arena_object.h
@@ -0,0 +1,67 @@
+/*
+ * 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_UTILS_ARENA_OBJECT_H_
+#define ART_COMPILER_UTILS_ARENA_OBJECT_H_
+
+#include "arena_allocator.h"
+#include "base/logging.h"
+#include "scoped_arena_allocator.h"
+
+namespace art {
+
+// Parent for arena allocated objects giving appropriate new and delete operators.
+template<enum ArenaAllocKind kAllocKind>
+class ArenaObject {
+ public:
+  // Allocate a new ArenaObject of 'size' bytes in the Arena.
+  void* operator new(size_t size, ArenaAllocator* allocator) {
+    return allocator->Alloc(size, kAllocKind);
+  }
+
+  static void* operator new(size_t size, ScopedArenaAllocator* arena) {
+    return arena->Alloc(size, kAllocKind);
+  }
+
+  void operator delete(void*, size_t) {
+    LOG(FATAL) << "UNREACHABLE";
+    UNREACHABLE();
+  }
+};
+
+
+// Parent for arena allocated objects that get deleted, gives appropriate new and delete operators.
+// Currently this is used by the quick compiler for debug reference counting arena allocations.
+template<enum ArenaAllocKind kAllocKind>
+class DeletableArenaObject {
+ public:
+  // Allocate a new ArenaObject of 'size' bytes in the Arena.
+  void* operator new(size_t size, ArenaAllocator* allocator) {
+    return allocator->Alloc(size, kAllocKind);
+  }
+
+  static void* operator new(size_t size, ScopedArenaAllocator* arena) {
+    return arena->Alloc(size, kAllocKind);
+  }
+
+  void operator delete(void*, size_t) {
+    // Nop.
+  }
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_ARENA_OBJECT_H_
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 637a1ff..0528773 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -92,16 +92,29 @@
       break;
     case kRegister:
       if (is_shift_) {
+        uint32_t shift_type;
+        switch (shift_) {
+          case arm::Shift::ROR:
+            shift_type = static_cast<uint32_t>(shift_);
+            CHECK_NE(immed_, 0U);
+            break;
+          case arm::Shift::RRX:
+            shift_type = static_cast<uint32_t>(arm::Shift::ROR);  // Same encoding as ROR.
+            CHECK_EQ(immed_, 0U);
+            break;
+          default:
+            shift_type = static_cast<uint32_t>(shift_);
+        }
         // Shifted immediate or register.
         if (rs_ == kNoRegister) {
           // Immediate shift.
           return immed_ << kShiftImmShift |
-                          static_cast<uint32_t>(shift_) << kShiftShift |
+                          shift_type << kShiftShift |
                           static_cast<uint32_t>(rm_);
         } else {
           // Register shift.
           return static_cast<uint32_t>(rs_) << kShiftRegisterShift |
-              static_cast<uint32_t>(shift_) << kShiftShift | (1 << 4) |
+              shift_type << kShiftShift | (1 << 4) |
               static_cast<uint32_t>(rm_);
         }
       } else {
@@ -152,36 +165,6 @@
   return 0;
 }
 
-bool ShifterOperand::CanHoldThumb(Register rd, Register rn, Opcode opcode,
-                                  uint32_t immediate, ShifterOperand* shifter_op) {
-  shifter_op->type_ = kImmediate;
-  shifter_op->immed_ = immediate;
-  shifter_op->is_shift_ = false;
-  shifter_op->is_rotate_ = false;
-  switch (opcode) {
-    case ADD:
-    case SUB:
-      if (rn == SP) {
-        if (rd == SP) {
-          return immediate < (1 << 9);    // 9 bits allowed.
-        } else {
-          return immediate < (1 << 12);   // 12 bits.
-        }
-      }
-      if (immediate < (1 << 12)) {    // Less than (or equal to) 12 bits can always be done.
-        return true;
-      }
-      return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
-
-    case MOV:
-      // TODO: Support less than or equal to 12bits.
-      return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
-    case MVN:
-    default:
-      return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
-  }
-}
-
 uint32_t Address::encodingArm() const {
   CHECK(IsAbsoluteUint(12, offset_));
   uint32_t encoding;
@@ -192,10 +175,9 @@
       encoding =  am_ | offset_;
     }
   } else {
-    uint32_t imm5 = offset_;
     uint32_t shift = shift_;
     if (shift == RRX) {
-      imm5 = 0;
+      CHECK_EQ(offset_, 0);
       shift = ROR;
     }
     encoding = am_ | static_cast<uint32_t>(rm_) | shift << 5 | offset_ << 7 | B25;
@@ -301,11 +283,11 @@
   CHECK(IsAbsoluteUint(10, offset));  // In the range -1020 to +1020.
   CHECK_ALIGNED(offset, 2);  // Multiple of 4.
   CHECK((am_ == Offset) || (am_ == NegOffset));
-  uint32_t vencoding = (encoding & (0xf << kRnShift)) | (offset >> 2);
+  uint32_t vencoding_value = (encoding & (0xf << kRnShift)) | (offset >> 2);
   if (am_ == Offset) {
-    vencoding |= 1 << 23;
+    vencoding_value |= 1 << 23;
   }
-  return vencoding;
+  return vencoding_value;
 }
 
 
@@ -324,7 +306,7 @@
       return IsAbsoluteUint(10, offset);  // VFP addressing mode.
     default:
       LOG(FATAL) << "UNREACHABLE";
-      return false;
+      UNREACHABLE();
   }
 }
 
@@ -342,7 +324,7 @@
       return IsAbsoluteUint(10, offset);  // VFP addressing mode.
     default:
       LOG(FATAL) << "UNREACHABLE";
-      return false;
+      UNREACHABLE();
   }
 }
 
@@ -359,9 +341,9 @@
       return IsAbsoluteUint(10, offset);  // VFP addressing mode.
     case kLoadWordPair:
       return IsAbsoluteUint(10, offset);
-  default:
+    default:
       LOG(FATAL) << "UNREACHABLE";
-      return false;
+      UNREACHABLE();
   }
 }
 
@@ -377,16 +359,16 @@
       return IsAbsoluteUint(10, offset);  // VFP addressing mode.
     case kStoreWordPair:
       return IsAbsoluteUint(10, offset);
-  default:
+    default:
       LOG(FATAL) << "UNREACHABLE";
-      return false;
+      UNREACHABLE();
   }
 }
 
 void ArmAssembler::Pad(uint32_t bytes) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   for (uint32_t i = 0; i < bytes; ++i) {
-    buffer_.Emit<byte>(0);
+    buffer_.Emit<uint8_t>(0);
   }
 }
 
@@ -417,9 +399,23 @@
   StoreToOffset(kStoreWord, R0, SP, 0);
 
   // Write out entry spills.
+  int32_t offset = frame_size + sizeof(StackReference<mirror::ArtMethod>);
   for (size_t i = 0; i < entry_spills.size(); ++i) {
-    Register reg = entry_spills.at(i).AsArm().AsCoreRegister();
-    StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize));
+    ArmManagedRegister reg = entry_spills.at(i).AsArm();
+    if (reg.IsNoRegister()) {
+      // only increment stack offset.
+      ManagedRegisterSpill spill = entry_spills.at(i);
+      offset += spill.getSize();
+    } else if (reg.IsCoreRegister()) {
+      StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset);
+      offset += 4;
+    } else if (reg.IsSRegister()) {
+      StoreSToOffset(reg.AsSRegister(), SP, offset);
+      offset += 4;
+    } else if (reg.IsDRegister()) {
+      StoreDToOffset(reg.AsDRegister(), SP, offset);
+      offset += 8;
+    }
   }
 }
 
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 54965f6..d912276 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/value_object.h"
 #include "constants_arm.h"
 #include "utils/arm/managed_register_arm.h"
 #include "utils/assembler.h"
@@ -29,6 +30,9 @@
 namespace art {
 namespace arm {
 
+class Arm32Assembler;
+class Thumb2Assembler;
+
 class ShifterOperand {
  public:
   ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
@@ -102,33 +106,6 @@
     kImmediate
   };
 
-  static bool CanHoldArm(uint32_t immediate, ShifterOperand* shifter_op) {
-    // Avoid the more expensive test for frequent small immediate values.
-    if (immediate < (1 << kImmed8Bits)) {
-      shifter_op->type_ = kImmediate;
-      shifter_op->is_rotate_ = true;
-      shifter_op->rotate_ = 0;
-      shifter_op->immed_ = immediate;
-      return true;
-    }
-    // Note that immediate must be unsigned for the test to work correctly.
-    for (int rot = 0; rot < 16; rot++) {
-      uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot));
-      if (imm8 < (1 << kImmed8Bits)) {
-        shifter_op->type_ = kImmediate;
-        shifter_op->is_rotate_ = true;
-        shifter_op->rotate_ = rot;
-        shifter_op->immed_ = imm8;
-        return true;
-      }
-    }
-    return false;
-  }
-
-  static bool CanHoldThumb(Register rd, Register rn, Opcode opcode,
-                           uint32_t immediate, ShifterOperand* shifter_op);
-
-
  private:
   Type type_;
   Register rm_;
@@ -139,6 +116,9 @@
   uint32_t rotate_;
   uint32_t immed_;
 
+  friend class Arm32Assembler;
+  friend class Thumb2Assembler;
+
 #ifdef SOURCE_ASSEMBLER_SUPPORT
   friend class BinaryAssembler;
 #endif
@@ -179,8 +159,12 @@
   DB_W         = (8|0|1) << 21,  // decrement before with writeback to base
   IB_W         = (8|4|1) << 21   // increment before with writeback to base
 };
+inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) {
+  os << static_cast<int>(rhs);
+  return os;
+}
 
-class Address {
+class Address : public ValueObject {
  public:
   // Memory operand addressing mode (in ARM encoding form.  For others we need
   // to adjust)
@@ -260,13 +244,17 @@
   }
 
  private:
-  Register rn_;
-  Register rm_;
-  int32_t offset_;      // Used as shift amount for register offset.
-  Mode am_;
-  bool is_immed_offset_;
-  Shift shift_;
+  const Register rn_;
+  const Register rm_;
+  const int32_t offset_;      // Used as shift amount for register offset.
+  const Mode am_;
+  const bool is_immed_offset_;
+  const Shift shift_;
 };
+inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) {
+  os << static_cast<int>(rhs);
+  return os;
+}
 
 // Instruction encoding bits.
 enum {
@@ -344,10 +332,6 @@
 
 extern const char* kRegisterNames[];
 extern const char* kConditionNames[];
-extern std::ostream& operator<<(std::ostream& os, const Register& rhs);
-extern std::ostream& operator<<(std::ostream& os, const SRegister& rhs);
-extern std::ostream& operator<<(std::ostream& os, const DRegister& rhs);
-extern std::ostream& operator<<(std::ostream& os, const Condition& rhs);
 
 // This is an abstract ARM assembler.  Subclasses provide assemblers for the individual
 // instruction sets (ARM32, Thumb2, etc.)
@@ -416,6 +400,12 @@
   virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
   virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
 
+  // Bit field extract instructions.
+  virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
+                    Condition cond = AL) = 0;
+  virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
+                    Condition cond = AL) = 0;
+
   // Load/store instructions.
   virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
   virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0;
@@ -439,6 +429,8 @@
 
   virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
   virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
+  virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
+  virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
 
   // Miscellaneous instructions.
   virtual void clrex(Condition cond = AL) = 0;
@@ -448,8 +440,10 @@
   virtual void bkpt(uint16_t imm16) = 0;
   virtual void svc(uint32_t imm24) = 0;
 
-  virtual void it(Condition firstcond, ItState i1 = kItOmitted,
-                  ItState i2 = kItOmitted, ItState i3 = kItOmitted) {
+  virtual void it(Condition firstcond ATTRIBUTE_UNUSED,
+                  ItState i1 ATTRIBUTE_UNUSED = kItOmitted,
+                  ItState i2 ATTRIBUTE_UNUSED = kItOmitted,
+                  ItState i3 ATTRIBUTE_UNUSED = kItOmitted) {
     // Ignored if not supported.
   }
 
@@ -523,6 +517,9 @@
   virtual void blx(Register rm, Condition cond = AL) = 0;
   virtual void bx(Register rm, Condition cond = AL) = 0;
 
+  // Memory barriers.
+  virtual void dmb(DmbOptions flavor) = 0;
+
   void Pad(uint32_t bytes);
 
   // Macros.
@@ -534,14 +531,16 @@
                            Condition cond = AL) = 0;
   virtual void AddConstantSetFlags(Register rd, Register rn, int32_t value,
                                    Condition cond = AL) = 0;
-  virtual void AddConstantWithCarry(Register rd, Register rn, int32_t value,
-                                    Condition cond = AL) = 0;
 
   // Load and Store. May clobber IP.
   virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
-  virtual void LoadSImmediate(SRegister sd, float value, Condition cond = AL) = 0;
-  virtual void LoadDImmediate(DRegister dd, double value,
-                              Register scratch, Condition cond = AL) = 0;
+  void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {
+    if (!vmovs(sd, value, cond)) {
+      LoadImmediate(IP, bit_cast<int32_t, float>(value), cond);
+      vmovsr(sd, IP, cond);
+    }
+  }
+
   virtual void MarkExceptionHandler(Label* label) = 0;
   virtual void LoadFromOffset(LoadOperandType type,
                               Register reg,
@@ -600,7 +599,15 @@
   virtual void Ror(Register rd, Register rm, Register rn, bool setcc = false,
                    Condition cond = AL) = 0;
 
-  static bool IsInstructionForExceptionHandling(uword pc);
+  // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes,
+  // `shifter_op` contains the operand.
+  virtual bool ShifterOperandCanHold(Register rd,
+                                     Register rn,
+                                     Opcode opcode,
+                                     uint32_t immediate,
+                                     ShifterOperand* shifter_op) = 0;
+
+  static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
   virtual void Bind(Label* label) = 0;
 
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index 6af69c8..8d1fb60 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -25,6 +25,37 @@
 namespace art {
 namespace arm {
 
+bool Arm32Assembler::ShifterOperandCanHoldArm32(uint32_t immediate, ShifterOperand* shifter_op) {
+  // Avoid the more expensive test for frequent small immediate values.
+  if (immediate < (1 << kImmed8Bits)) {
+    shifter_op->type_ = ShifterOperand::kImmediate;
+    shifter_op->is_rotate_ = true;
+    shifter_op->rotate_ = 0;
+    shifter_op->immed_ = immediate;
+    return true;
+  }
+  // Note that immediate must be unsigned for the test to work correctly.
+  for (int rot = 0; rot < 16; rot++) {
+    uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot));
+    if (imm8 < (1 << kImmed8Bits)) {
+      shifter_op->type_ = ShifterOperand::kImmediate;
+      shifter_op->is_rotate_ = true;
+      shifter_op->rotate_ = rot;
+      shifter_op->immed_ = imm8;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool Arm32Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED,
+                                           Register rn ATTRIBUTE_UNUSED,
+                                           Opcode opcode ATTRIBUTE_UNUSED,
+                                           uint32_t immediate,
+                                           ShifterOperand* shifter_op) {
+  return ShifterOperandCanHoldArm32(immediate, shifter_op);
+}
+
 void Arm32Assembler::and_(Register rd, Register rn, const ShifterOperand& so,
                         Condition cond) {
   EmitType01(cond, so.type(), AND, 0, rn, rd, so);
@@ -208,6 +239,44 @@
 }
 
 
+void Arm32Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
+  CHECK_NE(rd, kNoRegister);
+  CHECK_NE(rn, kNoRegister);
+  CHECK_NE(cond, kNoCondition);
+  CHECK_LE(lsb, 31U);
+  CHECK(1U <= width && width <= 32U) << width;
+  uint32_t widthminus1 = width - 1;
+
+  int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
+      B26 | B25 | B24 | B23 | B21 |
+      (widthminus1 << 16) |
+      (static_cast<uint32_t>(rd) << 12) |
+      (lsb << 7) |
+      B6 | B4 |
+      static_cast<uint32_t>(rn);
+  Emit(encoding);
+}
+
+
+void Arm32Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
+  CHECK_NE(rd, kNoRegister);
+  CHECK_NE(rn, kNoRegister);
+  CHECK_NE(cond, kNoCondition);
+  CHECK_LE(lsb, 31U);
+  CHECK(1U <= width && width <= 32U) << width;
+  uint32_t widthminus1 = width - 1;
+
+  int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
+      B26 | B25 | B24 | B23 | B22 | B21 |
+      (widthminus1 << 16) |
+      (static_cast<uint32_t>(rd) << 12) |
+      (lsb << 7) |
+      B6 | B4 |
+      static_cast<uint32_t>(rn);
+  Emit(encoding);
+}
+
+
 void Arm32Assembler::ldr(Register rd, const Address& ad, Condition cond) {
   EmitMemOp(cond, true, false, rd, ad);
 }
@@ -709,6 +778,7 @@
   Emit(encoding);
 }
 
+
 void Arm32Assembler::ldrex(Register rt, Register rn, Condition cond) {
   CHECK_NE(rn, kNoRegister);
   CHECK_NE(rt, kNoRegister);
@@ -724,6 +794,25 @@
 }
 
 
+void Arm32Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
+  CHECK_NE(rn, kNoRegister);
+  CHECK_NE(rt, kNoRegister);
+  CHECK_NE(rt2, kNoRegister);
+  CHECK_NE(rt, R14);
+  CHECK_EQ(0u, static_cast<uint32_t>(rt) % 2);
+  CHECK_EQ(static_cast<uint32_t>(rt) + 1, static_cast<uint32_t>(rt2));
+  CHECK_NE(cond, kNoCondition);
+
+  int32_t encoding =
+      (static_cast<uint32_t>(cond) << kConditionShift) |
+      B24 | B23 | B21 | B20 |
+      static_cast<uint32_t>(rn) << 16 |
+      static_cast<uint32_t>(rt) << 12 |
+      B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0;
+  Emit(encoding);
+}
+
+
 void Arm32Assembler::strex(Register rd,
                            Register rt,
                            Register rn,
@@ -742,6 +831,28 @@
   Emit(encoding);
 }
 
+void Arm32Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
+  CHECK_NE(rd, kNoRegister);
+  CHECK_NE(rn, kNoRegister);
+  CHECK_NE(rt, kNoRegister);
+  CHECK_NE(rt2, kNoRegister);
+  CHECK_NE(rt, R14);
+  CHECK_NE(rd, rt);
+  CHECK_NE(rd, rt2);
+  CHECK_EQ(0u, static_cast<uint32_t>(rt) % 2);
+  CHECK_EQ(static_cast<uint32_t>(rt) + 1, static_cast<uint32_t>(rt2));
+  CHECK_NE(cond, kNoCondition);
+
+  int32_t encoding =
+      (static_cast<uint32_t>(cond) << kConditionShift) |
+      B24 | B23 | B21 |
+      static_cast<uint32_t>(rn) << 16 |
+      static_cast<uint32_t>(rd) << 12 |
+      B11 | B10 | B9 | B8 | B7 | B4 |
+      static_cast<uint32_t>(rt);
+  Emit(encoding);
+}
+
 
 void Arm32Assembler::clrex(Condition cond) {
   CHECK_EQ(cond, AL);   // This cannot be conditional on ARM.
@@ -1041,7 +1152,7 @@
 
 void Arm32Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
                          bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Do not use Lsl if no shift is wanted.
+  CHECK_LE(shift_imm, 31u);
   if (setcc) {
     movs(rd, ShifterOperand(rm, LSL, shift_imm), cond);
   } else {
@@ -1052,7 +1163,7 @@
 
 void Arm32Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
                          bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Do not use Lsr if no shift is wanted.
+  CHECK(1u <= shift_imm && shift_imm <= 32u);
   if (shift_imm == 32) shift_imm = 0;  // Comply to UAL syntax.
   if (setcc) {
     movs(rd, ShifterOperand(rm, LSR, shift_imm), cond);
@@ -1064,7 +1175,7 @@
 
 void Arm32Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
                          bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Do not use Asr if no shift is wanted.
+  CHECK(1u <= shift_imm && shift_imm <= 32u);
   if (shift_imm == 32) shift_imm = 0;  // Comply to UAL syntax.
   if (setcc) {
     movs(rd, ShifterOperand(rm, ASR, shift_imm), cond);
@@ -1076,7 +1187,7 @@
 
 void Arm32Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
                          bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Use Rrx instruction.
+  CHECK(1u <= shift_imm && shift_imm <= 31u);
   if (setcc) {
     movs(rd, ShifterOperand(rm, ROR, shift_imm), cond);
   } else {
@@ -1253,16 +1364,16 @@
   // positive values and sub for negatives ones, which would slightly improve
   // the readability of generated code for some constants.
   ShifterOperand shifter_op;
-  if (ShifterOperand::CanHoldArm(value, &shifter_op)) {
+  if (ShifterOperandCanHoldArm32(value, &shifter_op)) {
     add(rd, rn, shifter_op, cond);
-  } else if (ShifterOperand::CanHoldArm(-value, &shifter_op)) {
+  } else if (ShifterOperandCanHoldArm32(-value, &shifter_op)) {
     sub(rd, rn, shifter_op, cond);
   } else {
     CHECK(rn != IP);
-    if (ShifterOperand::CanHoldArm(~value, &shifter_op)) {
+    if (ShifterOperandCanHoldArm32(~value, &shifter_op)) {
       mvn(IP, shifter_op, cond);
       add(rd, rn, ShifterOperand(IP), cond);
-    } else if (ShifterOperand::CanHoldArm(~(-value), &shifter_op)) {
+    } else if (ShifterOperandCanHoldArm32(~(-value), &shifter_op)) {
       mvn(IP, shifter_op, cond);
       sub(rd, rn, ShifterOperand(IP), cond);
     } else {
@@ -1280,16 +1391,16 @@
 void Arm32Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
                                          Condition cond) {
   ShifterOperand shifter_op;
-  if (ShifterOperand::CanHoldArm(value, &shifter_op)) {
+  if (ShifterOperandCanHoldArm32(value, &shifter_op)) {
     adds(rd, rn, shifter_op, cond);
-  } else if (ShifterOperand::CanHoldArm(-value, &shifter_op)) {
+  } else if (ShifterOperandCanHoldArm32(-value, &shifter_op)) {
     subs(rd, rn, shifter_op, cond);
   } else {
     CHECK(rn != IP);
-    if (ShifterOperand::CanHoldArm(~value, &shifter_op)) {
+    if (ShifterOperandCanHoldArm32(~value, &shifter_op)) {
       mvn(IP, shifter_op, cond);
       adds(rd, rn, ShifterOperand(IP), cond);
-    } else if (ShifterOperand::CanHoldArm(~(-value), &shifter_op)) {
+    } else if (ShifterOperandCanHoldArm32(~(-value), &shifter_op)) {
       mvn(IP, shifter_op, cond);
       subs(rd, rn, ShifterOperand(IP), cond);
     } else {
@@ -1303,12 +1414,11 @@
   }
 }
 
-
 void Arm32Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
   ShifterOperand shifter_op;
-  if (ShifterOperand::CanHoldArm(value, &shifter_op)) {
+  if (ShifterOperandCanHoldArm32(value, &shifter_op)) {
     mov(rd, shifter_op, cond);
-  } else if (ShifterOperand::CanHoldArm(~value, &shifter_op)) {
+  } else if (ShifterOperandCanHoldArm32(~value, &shifter_op)) {
     mvn(rd, shifter_op, cond);
   } else {
     movw(rd, Low16Bits(value), cond);
@@ -1356,6 +1466,7 @@
       break;
     default:
       LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
   }
 }
 
@@ -1427,6 +1538,7 @@
       break;
     default:
       LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
   }
 }
 
@@ -1469,19 +1581,22 @@
 
 void Arm32Assembler::MemoryBarrier(ManagedRegister mscratch) {
   CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
-#if ANDROID_SMP != 0
-  int32_t encoding = 0xf57ff05f;  // dmb
-  Emit(encoding);
-#endif
+  dmb(SY);
 }
 
 
-void Arm32Assembler::cbz(Register rn, Label* target) {
+void Arm32Assembler::dmb(DmbOptions flavor) {
+  int32_t encoding = 0xf57ff05f;  // dmb
+  Emit(encoding | flavor);
+}
+
+
+void Arm32Assembler::cbz(Register rn ATTRIBUTE_UNUSED, Label* target ATTRIBUTE_UNUSED) {
   LOG(FATAL) << "cbz is not supported on ARM32";
 }
 
 
-void Arm32Assembler::cbnz(Register rn, Label* target) {
+void Arm32Assembler::cbnz(Register rn ATTRIBUTE_UNUSED, Label* target ATTRIBUTE_UNUSED) {
   LOG(FATAL) << "cbnz is not supported on ARM32";
 }
 
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index 7f9094d..b922d66 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -96,6 +96,10 @@
   void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
   void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
 
+  // Bit field extract instructions.
+  void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
+  void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
+
   // Load/store instructions.
   void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
   void str(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
@@ -119,6 +123,8 @@
 
   void ldrex(Register rd, Register rn, Condition cond = AL) OVERRIDE;
   void strex(Register rd, Register rt, Register rn, Condition cond = AL) OVERRIDE;
+  void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
+  void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
 
   // Miscellaneous instructions.
   void clrex(Condition cond = AL) OVERRIDE;
@@ -228,6 +234,8 @@
   void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE;
   void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE;
 
+  // Memory barriers.
+  void dmb(DmbOptions flavor) OVERRIDE;
 
   // Macros.
   // Add signed constant value to rd. May clobber IP.
@@ -236,14 +244,9 @@
                    Condition cond = AL) OVERRIDE;
   void AddConstantSetFlags(Register rd, Register rn, int32_t value,
                            Condition cond = AL) OVERRIDE;
-  void AddConstantWithCarry(Register rd, Register rn, int32_t value,
-                            Condition cond = AL) {}
 
   // Load and Store. May clobber IP.
   void LoadImmediate(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
-  void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {}
-  void LoadDImmediate(DRegister dd, double value,
-                      Register scratch, Condition cond = AL) {}
   void MarkExceptionHandler(Label* label) OVERRIDE;
   void LoadFromOffset(LoadOperandType type,
                       Register reg,
@@ -272,8 +275,14 @@
                       int32_t offset,
                       Condition cond = AL) OVERRIDE;
 
+  bool ShifterOperandCanHold(Register rd,
+                             Register rn,
+                             Opcode opcode,
+                             uint32_t immediate,
+                             ShifterOperand* shifter_op) OVERRIDE;
 
-  static bool IsInstructionForExceptionHandling(uword pc);
+
+  static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
   // Emit data (e.g. encoded instruction or immediate) to the
   // instruction stream.
@@ -358,6 +367,7 @@
   static int DecodeBranchOffset(int32_t inst);
   int32_t EncodeTstOffset(int offset, int32_t inst);
   int DecodeTstOffset(int32_t inst);
+  bool ShifterOperandCanHoldArm32(uint32_t immediate, ShifterOperand* shifter_op);
 };
 
 }  // namespace arm
diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc
new file mode 100644
index 0000000..4a0ae0b
--- /dev/null
+++ b/compiler/utils/arm/assembler_arm32_test.cc
@@ -0,0 +1,724 @@
+/*
+ * 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 "assembler_arm32.h"
+
+#include <functional>
+#include <type_traits>
+
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "utils/arm/assembler_arm_test.h"
+
+namespace art {
+
+using std::placeholders::_1;
+using std::placeholders::_2;
+using std::placeholders::_3;
+using std::placeholders::_4;
+using std::placeholders::_5;
+
+// To speed up tests, don't use all register combinations.
+static constexpr bool kUseSparseRegisterList = true;
+
+// To speed up tests, don't use all condition codes.
+static constexpr bool kUseSparseConditionList = true;
+
+// To speed up tests, don't use all shift immediates.
+static constexpr bool kUseSparseShiftImmediates = true;
+
+class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler,
+                                                   arm::Register, arm::SRegister,
+                                                   uint32_t, arm::ShifterOperand, arm::Condition> {
+ protected:
+  std::string GetArchitectureString() OVERRIDE {
+    return "arm";
+  }
+
+  std::string GetAssemblerParameters() OVERRIDE {
+    // Arm-v7a, cortex-a15 (means we have sdiv).
+    return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
+  }
+
+  const char* GetAssemblyHeader() OVERRIDE {
+    return kArm32AssemblyHeader;
+  }
+
+  std::string GetDisassembleParameters() OVERRIDE {
+    return " -D -bbinary -marm --no-show-raw-insn";
+  }
+
+  void SetUpHelpers() OVERRIDE {
+    if (registers_.size() == 0) {
+      if (kUseSparseRegisterList) {
+        registers_.insert(end(registers_),
+                          {  // NOLINT(whitespace/braces)
+                              new arm::Register(arm::R0),
+                              new arm::Register(arm::R1),
+                              new arm::Register(arm::R4),
+                              new arm::Register(arm::R8),
+                              new arm::Register(arm::R11),
+                              new arm::Register(arm::R12),
+                              new arm::Register(arm::R13),
+                              new arm::Register(arm::R14),
+                              new arm::Register(arm::R15)
+                          });
+      } else {
+        registers_.insert(end(registers_),
+                          {  // NOLINT(whitespace/braces)
+                              new arm::Register(arm::R0),
+                              new arm::Register(arm::R1),
+                              new arm::Register(arm::R2),
+                              new arm::Register(arm::R3),
+                              new arm::Register(arm::R4),
+                              new arm::Register(arm::R5),
+                              new arm::Register(arm::R6),
+                              new arm::Register(arm::R7),
+                              new arm::Register(arm::R8),
+                              new arm::Register(arm::R9),
+                              new arm::Register(arm::R10),
+                              new arm::Register(arm::R11),
+                              new arm::Register(arm::R12),
+                              new arm::Register(arm::R13),
+                              new arm::Register(arm::R14),
+                              new arm::Register(arm::R15)
+                          });
+      }
+    }
+
+    if (!kUseSparseConditionList) {
+      conditions_.push_back(arm::Condition::EQ);
+      conditions_.push_back(arm::Condition::NE);
+      conditions_.push_back(arm::Condition::CS);
+      conditions_.push_back(arm::Condition::CC);
+      conditions_.push_back(arm::Condition::MI);
+      conditions_.push_back(arm::Condition::PL);
+      conditions_.push_back(arm::Condition::VS);
+      conditions_.push_back(arm::Condition::VC);
+      conditions_.push_back(arm::Condition::HI);
+      conditions_.push_back(arm::Condition::LS);
+      conditions_.push_back(arm::Condition::GE);
+      conditions_.push_back(arm::Condition::LT);
+      conditions_.push_back(arm::Condition::GT);
+      conditions_.push_back(arm::Condition::LE);
+      conditions_.push_back(arm::Condition::AL);
+    } else {
+      conditions_.push_back(arm::Condition::EQ);
+      conditions_.push_back(arm::Condition::NE);
+      conditions_.push_back(arm::Condition::CC);
+      conditions_.push_back(arm::Condition::VC);
+      conditions_.push_back(arm::Condition::HI);
+      conditions_.push_back(arm::Condition::LT);
+      conditions_.push_back(arm::Condition::AL);
+    }
+
+    shifter_operands_.push_back(arm::ShifterOperand(0));
+    shifter_operands_.push_back(arm::ShifterOperand(1));
+    shifter_operands_.push_back(arm::ShifterOperand(2));
+    shifter_operands_.push_back(arm::ShifterOperand(3));
+    shifter_operands_.push_back(arm::ShifterOperand(4));
+    shifter_operands_.push_back(arm::ShifterOperand(5));
+    shifter_operands_.push_back(arm::ShifterOperand(127));
+    shifter_operands_.push_back(arm::ShifterOperand(128));
+    shifter_operands_.push_back(arm::ShifterOperand(254));
+    shifter_operands_.push_back(arm::ShifterOperand(255));
+
+    if (!kUseSparseRegisterList) {
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
+    } else {
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
+      shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
+    }
+
+    std::vector<arm::Shift> shifts {
+      arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
+    };
+
+    // ShifterOperands of form "reg shift-type imm."
+    for (arm::Shift shift : shifts) {
+      for (arm::Register* reg : registers_) {  // Note: this will pick up the sparse set.
+        if (*reg == arm::R15) {  // Skip PC.
+          continue;
+        }
+        if (shift != arm::Shift::RRX) {
+          if (!kUseSparseShiftImmediates) {
+            for (uint32_t imm = 1; imm < 32; ++imm) {
+              shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
+            }
+          } else {
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
+            shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
+          }
+        } else {
+          // RRX doesn't have an immediate.
+          shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
+        }
+      }
+    }
+  }
+
+  std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
+                                                        int32_t shift_min, int32_t shift_max) {
+    std::vector<arm::ShifterOperand> res;
+    static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
+                                              arm::Shift::ROR };
+
+    for (arm::Shift shift : kShifts) {
+      for (arm::Register* reg : base_regs) {
+        // Take the min, the max, and three values in between.
+        res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
+        if (shift_min != shift_max) {
+          res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
+          int32_t middle = (shift_min + shift_max) / 2;
+          res.push_back(arm::ShifterOperand(*reg, shift, middle));
+          res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
+          res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
+        }
+      }
+    }
+
+    return res;
+  }
+
+  void TearDown() OVERRIDE {
+    AssemblerArmTest::TearDown();
+    STLDeleteElements(&registers_);
+  }
+
+  std::vector<arm::Register*> GetRegisters() OVERRIDE {
+    return registers_;
+  }
+
+  uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
+    return imm_value;
+  }
+
+  std::vector<arm::Condition>& GetConditions() OVERRIDE {
+    return conditions_;
+  }
+
+  std::string GetConditionString(arm::Condition c) OVERRIDE {
+    std::ostringstream oss;
+    oss << c;
+    return oss.str();
+  }
+
+  arm::Register GetPCRegister() OVERRIDE {
+    return arm::R15;
+  }
+
+  std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
+    return shifter_operands_;
+  }
+
+  std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
+    std::ostringstream oss;
+    if (sop.IsShift()) {
+      // Not a rotate...
+      if (sop.GetShift() == arm::Shift::RRX) {
+        oss << sop.GetRegister() << ", " << sop.GetShift();
+      } else {
+        oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
+      }
+    } else if (sop.IsRegister()) {
+      oss << sop.GetRegister();
+    } else {
+      CHECK(sop.IsImmediate());
+      oss << "#" << sop.GetImmediate();
+    }
+    return oss.str();
+  }
+
+  static const char* GetRegTokenFromDepth(int depth) {
+    switch (depth) {
+      case 0:
+        return Base::REG1_TOKEN;
+      case 1:
+        return Base::REG2_TOKEN;
+      case 2:
+        return REG3_TOKEN;
+      case 3:
+        return REG4_TOKEN;
+      default:
+        LOG(FATAL) << "Depth problem.";
+        UNREACHABLE();
+    }
+  }
+
+  void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
+    if (first_) {
+      first_ = false;
+    } else {
+      oss << "\n";
+    }
+    oss << fmt;
+
+    f();
+  }
+
+  void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
+                      bool without_pc,
+                      std::string fmt, std::ostringstream& oss) {
+    std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
+    for (auto reg : registers) {
+      std::string after_reg = fmt;
+
+      std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
+      size_t reg_index;
+      const char* reg_token = GetRegTokenFromDepth(depth);
+
+      while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
+        after_reg.replace(reg_index, strlen(reg_token), reg_string);
+      }
+
+      ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
+    }
+  }
+
+  void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
+                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+    for (const arm::ShifterOperand& shift : GetShiftOperands()) {
+      std::string after_shift = fmt;
+
+      std::string shift_string = GetShiftString(shift);
+      size_t shift_index;
+      while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
+        after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+      }
+
+      ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
+    }
+  }
+
+  void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
+                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+    for (arm::Condition c : GetConditions()) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
+    }
+  }
+
+  template <typename... Args>
+  void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
+                      std::string fmt, std::ostringstream& oss) {
+    std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
+    for (auto reg : registers) {
+      std::string after_reg = fmt;
+
+      std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
+      size_t reg_index;
+      const char* reg_token = GetRegTokenFromDepth(depth);
+
+      while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
+        after_reg.replace(reg_index, strlen(reg_token), reg_string);
+      }
+
+      auto lambda = [&] (Args... args) { f(*reg, args...); };  // NOLINT [readability/braces] [4]
+      TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
+          after_reg, oss);
+    }
+  }
+
+  template <typename... Args>
+  void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
+                      bool without_pc, std::string fmt, std::ostringstream& oss) {
+    for (const arm::ShifterOperand& shift : GetShiftOperands()) {
+      std::string after_shift = fmt;
+
+      std::string shift_string = GetShiftString(shift);
+      size_t shift_index;
+      while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
+        after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+      }
+
+      auto lambda = [&] (Args... args) { f(shift, args...); };  // NOLINT [readability/braces] [4]
+      TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
+          after_shift, oss);
+    }
+  }
+
+  template <typename... Args>
+  void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
+                      std::string fmt, std::ostringstream& oss) {
+    for (arm::Condition c : GetConditions()) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      auto lambda = [&] (Args... args) { f(c, args...); };  // NOLINT [readability/braces] [4]
+      TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
+          after_cond, oss);
+    }
+  }
+
+  template <typename T1, typename T2>
+  std::function<void(T1, T2)> GetBoundFunction2(void (arm::Arm32Assembler::*f)(T1, T2)) {
+    return std::bind(f, GetAssembler(), _1, _2);
+  }
+
+  template <typename T1, typename T2, typename T3>
+  std::function<void(T1, T2, T3)> GetBoundFunction3(void (arm::Arm32Assembler::*f)(T1, T2, T3)) {
+    return std::bind(f, GetAssembler(), _1, _2, _3);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4>
+  std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
+      void (arm::Arm32Assembler::*f)(T1, T2, T3, T4)) {
+    return std::bind(f, GetAssembler(), _1, _2, _3, _4);
+  }
+
+  template <typename T1, typename T2, typename T3, typename T4, typename T5>
+  std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
+      void (arm::Arm32Assembler::*f)(T1, T2, T3, T4, T5)) {
+    return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
+  }
+
+  template <typename... Args>
+  void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
+                             std::string fmt, std::string test_name) {
+    first_ = false;
+    WarnOnCombinations(CountHelper<Args...>(without_pc));
+
+    std::ostringstream oss;
+
+    TemplateHelper(f, 0, without_pc, fmt, oss);
+
+    oss << "\n";  // Trailing newline.
+
+    DriverStr(oss.str(), test_name);
+  }
+
+  template <typename... Args>
+  void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
+                std::string test_name) {
+    GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
+  }
+
+  template <typename... Args>
+  void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
+      std::string test_name) {
+    GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
+  }
+
+  template <typename... Args>
+  void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
+      std::string test_name) {
+    GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
+  }
+
+  template <typename... Args>
+  void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
+      std::string test_name) {
+    GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
+  }
+
+ private:
+  template <typename T>
+  size_t CountHelper(bool without_pc) {
+    size_t tmp;
+    if (std::is_same<T, arm::Register>::value) {
+      tmp = GetRegisters().size();
+      if (without_pc) {
+        tmp--;;  // Approximation...
+      }
+      return tmp;
+    } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
+      return GetShiftOperands().size();
+    } else if (std::is_same<T, arm::Condition>::value) {
+      return GetConditions().size();
+    } else {
+      LOG(WARNING) << "Unknown type while counting.";
+      return 1;
+    }
+  }
+
+  template <typename T1, typename T2, typename... Args>
+  size_t CountHelper(bool without_pc) {
+    size_t tmp;
+    if (std::is_same<T1, arm::Register>::value) {
+      tmp = GetRegisters().size();
+      if (without_pc) {
+        tmp--;;  // Approximation...
+      }
+    } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
+      tmp =  GetShiftOperands().size();
+    } else if (std::is_same<T1, arm::Condition>::value) {
+      tmp = GetConditions().size();
+    } else {
+      LOG(WARNING) << "Unknown type while counting.";
+      tmp = 1;
+    }
+    size_t rec = CountHelper<T2, Args...>(without_pc);
+    return rec * tmp;
+  }
+
+  bool first_;
+
+  static constexpr const char* kArm32AssemblyHeader = ".arm\n";
+
+  std::vector<arm::Register*> registers_;
+  std::vector<arm::Condition> conditions_;
+  std::vector<arm::ShifterOperand> shifter_operands_;
+};
+
+
+TEST_F(AssemblerArm32Test, Toolchain) {
+  EXPECT_TRUE(CheckTools());
+}
+
+TEST_F(AssemblerArm32Test, Sbfx) {
+  std::vector<std::pair<uint32_t, uint32_t>> immediates;
+  immediates.push_back({0, 1});
+  immediates.push_back({0, 8});
+  immediates.push_back({0, 15});
+  immediates.push_back({0, 16});
+  immediates.push_back({0, 31});
+  immediates.push_back({0, 32});
+
+  immediates.push_back({1, 1});
+  immediates.push_back({1, 15});
+  immediates.push_back({1, 31});
+
+  immediates.push_back({8, 1});
+  immediates.push_back({8, 15});
+  immediates.push_back({8, 16});
+  immediates.push_back({8, 24});
+
+  immediates.push_back({31, 1});
+
+  DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
+                        "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
+}
+
+TEST_F(AssemblerArm32Test, Ubfx) {
+  std::vector<std::pair<uint32_t, uint32_t>> immediates;
+  immediates.push_back({0, 1});
+  immediates.push_back({0, 8});
+  immediates.push_back({0, 15});
+  immediates.push_back({0, 16});
+  immediates.push_back({0, 31});
+  immediates.push_back({0, 32});
+
+  immediates.push_back({1, 1});
+  immediates.push_back({1, 15});
+  immediates.push_back({1, 31});
+
+  immediates.push_back({8, 1});
+  immediates.push_back({8, 15});
+  immediates.push_back({8, 16});
+  immediates.push_back({8, 24});
+
+  immediates.push_back({31, 1});
+
+  DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
+                        "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
+}
+
+TEST_F(AssemblerArm32Test, Mul) {
+  T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
+}
+
+TEST_F(AssemblerArm32Test, Mla) {
+  T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
+}
+
+/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
+TEST_F(AssemblerArm32Test, Umull) {
+  T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
+           "umull");
+}
+*/
+
+TEST_F(AssemblerArm32Test, Sdiv) {
+  T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
+}
+
+TEST_F(AssemblerArm32Test, Udiv) {
+  T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
+}
+
+TEST_F(AssemblerArm32Test, And) {
+  T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and");
+}
+
+TEST_F(AssemblerArm32Test, Eor) {
+  T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor");
+}
+
+TEST_F(AssemblerArm32Test, Orr) {
+  T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr");
+}
+
+TEST_F(AssemblerArm32Test, Orrs) {
+  T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
+}
+
+TEST_F(AssemblerArm32Test, Bic) {
+  T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic");
+}
+
+TEST_F(AssemblerArm32Test, Mov) {
+  T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov");
+}
+
+TEST_F(AssemblerArm32Test, Movs) {
+  T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
+}
+
+TEST_F(AssemblerArm32Test, Mvn) {
+  T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn");
+}
+
+TEST_F(AssemblerArm32Test, Mvns) {
+  T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
+}
+
+TEST_F(AssemblerArm32Test, Add) {
+  T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add");
+}
+
+TEST_F(AssemblerArm32Test, Adds) {
+  T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
+}
+
+TEST_F(AssemblerArm32Test, Adc) {
+  T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc");
+}
+
+TEST_F(AssemblerArm32Test, Sub) {
+  T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub");
+}
+
+TEST_F(AssemblerArm32Test, Subs) {
+  T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
+}
+
+TEST_F(AssemblerArm32Test, Sbc) {
+  T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc");
+}
+
+TEST_F(AssemblerArm32Test, Rsb) {
+  T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb");
+}
+
+TEST_F(AssemblerArm32Test, Rsbs) {
+  T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
+}
+
+TEST_F(AssemblerArm32Test, Rsc) {
+  T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
+}
+
+/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
+TEST_F(AssemblerArm32Test, Strex) {
+  RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
+}
+*/
+
+TEST_F(AssemblerArm32Test, Clz) {
+  T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
+}
+
+TEST_F(AssemblerArm32Test, Tst) {
+  T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
+}
+
+TEST_F(AssemblerArm32Test, Teq) {
+  T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
+}
+
+TEST_F(AssemblerArm32Test, Cmp) {
+  T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
+}
+
+TEST_F(AssemblerArm32Test, Cmn) {
+  T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
+}
+
+TEST_F(AssemblerArm32Test, Blx) {
+  T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
+}
+
+TEST_F(AssemblerArm32Test, Bx) {
+  T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
+}
+
+TEST_F(AssemblerArm32Test, Vmstat) {
+  GetAssembler()->vmstat();
+
+  const char* expected = "vmrs APSR_nzcv, FPSCR\n";
+
+  DriverStr(expected, "vmrs");
+}
+
+TEST_F(AssemblerArm32Test, ldrexd) {
+  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
+  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
+  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
+
+  const char* expected =
+      "ldrexd r0, r1, [r0]\n"
+      "ldrexd r0, r1, [r1]\n"
+      "ldrexd r0, r1, [r2]\n";
+  DriverStr(expected, "ldrexd");
+}
+
+TEST_F(AssemblerArm32Test, strexd) {
+  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
+  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
+  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
+
+  const char* expected =
+      "strexd r9, r0, r1, [r0]\n"
+      "strexd r9, r0, r1, [r1]\n"
+      "strexd r9, r0, r1, [r2]\n";
+  DriverStr(expected, "strexd");
+}
+
+}  // namespace art
diff --git a/compiler/utils/arm/assembler_arm_test.h b/compiler/utils/arm/assembler_arm_test.h
new file mode 100644
index 0000000..838abb6
--- /dev/null
+++ b/compiler/utils/arm/assembler_arm_test.h
@@ -0,0 +1,545 @@
+/*
+ * 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_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
+#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
+
+#include "utils/assembler_test.h"
+
+namespace art {
+
+template<typename Ass, typename Reg, typename FPReg, typename Imm, typename SOp, typename Cond>
+class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> {
+ public:
+  typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base;
+
+  using Base::GetRegisters;
+  using Base::GetRegName;
+  using Base::CreateImmediate;
+  using Base::WarnOnCombinations;
+
+  static constexpr int64_t kFullImmRangeThreshold = 32;
+
+  virtual void FillImmediates(std::vector<Imm>& immediates, int64_t imm_min, int64_t imm_max) {
+    // Small range: do completely.
+    if (imm_max - imm_min <= kFullImmRangeThreshold) {
+      for (int64_t i = imm_min; i <= imm_max; ++i) {
+        immediates.push_back(CreateImmediate(i));
+      }
+    } else {
+      immediates.push_back(CreateImmediate(imm_min));
+      immediates.push_back(CreateImmediate(imm_max));
+      if (imm_min < imm_max - 1) {
+        immediates.push_back(CreateImmediate(imm_min + 1));
+      }
+      if (imm_min < imm_max - 2) {
+        immediates.push_back(CreateImmediate(imm_min + 2));
+      }
+      if (imm_min < imm_max - 3) {
+        immediates.push_back(CreateImmediate(imm_max - 1));
+      }
+      if (imm_min < imm_max - 4) {
+        immediates.push_back(CreateImmediate((imm_min + imm_max) / 2));
+      }
+    }
+  }
+
+  std::string RepeatRRIIC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
+                          int64_t imm1_min, int64_t imm1_max,
+                          int64_t imm2_min, int64_t imm2_max,
+                          std::string fmt) {
+    return RepeatTemplatedRRIIC(f, GetRegisters(), GetRegisters(),
+                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+                                &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+                                imm1_min, imm1_max, imm2_min, imm2_max,
+                                fmt);
+  }
+
+  template <typename Reg1, typename Reg2>
+  std::string RepeatTemplatedRRIIC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
+                                   const std::vector<Reg1*> reg1_registers,
+                                   const std::vector<Reg2*> reg2_registers,
+                                   std::string (AssemblerArmTest::*GetName1)(const Reg1&),
+                                   std::string (AssemblerArmTest::*GetName2)(const Reg2&),
+                                   int64_t imm1_min, int64_t imm1_max,
+                                   int64_t imm2_min, int64_t imm2_max,
+                                   std::string fmt) {
+    std::vector<Imm> immediates1;
+    FillImmediates(immediates1, imm1_min, imm1_max);
+    std::vector<Imm> immediates2;
+    FillImmediates(immediates2, imm2_min, imm2_max);
+
+    std::vector<Cond>& cond = GetConditions();
+
+    WarnOnCombinations(cond.size() * immediates1.size() * immediates2.size() *
+                       reg1_registers.size() * reg2_registers.size());
+
+    std::ostringstream oss;
+    bool first = true;
+    for (Cond& c : cond) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      for (Imm i : immediates1) {
+        std::string base = after_cond;
+
+        size_t imm1_index = base.find(IMM1_TOKEN);
+        if (imm1_index != std::string::npos) {
+          std::ostringstream sreg;
+          sreg << i;
+          std::string imm_string = sreg.str();
+          base.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
+        }
+
+        for (Imm j : immediates2) {
+          std::string base2 = base;
+
+          size_t imm2_index = base2.find(IMM2_TOKEN);
+          if (imm2_index != std::string::npos) {
+            std::ostringstream sreg;
+            sreg << j;
+            std::string imm_string = sreg.str();
+            base2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
+          }
+
+          for (auto reg1 : reg1_registers) {
+            std::string base3 = base2;
+
+            std::string reg1_string = (this->*GetName1)(*reg1);
+            size_t reg1_index;
+            while ((reg1_index = base3.find(Base::REG1_TOKEN)) != std::string::npos) {
+              base3.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
+            }
+
+            for (auto reg2 : reg2_registers) {
+              std::string base4 = base3;
+
+              std::string reg2_string = (this->*GetName2)(*reg2);
+              size_t reg2_index;
+              while ((reg2_index = base4.find(Base::REG2_TOKEN)) != std::string::npos) {
+                base4.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
+              }
+
+              if (first) {
+                first = false;
+              } else {
+                oss << "\n";
+              }
+              oss << base4;
+
+              (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
+            }
+          }
+        }
+      }
+    }
+    // Add a newline at the end.
+    oss << "\n";
+
+    return oss.str();
+  }
+
+  std::string RepeatRRiiC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond),
+                          std::vector<std::pair<Imm, Imm>>& immediates,
+                          std::string fmt) {
+    return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(),
+        &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+        immediates, fmt);
+  }
+
+  template <typename Reg1, typename Reg2>
+  std::string RepeatTemplatedRRiiC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond),
+        const std::vector<Reg1*> reg1_registers,
+        const std::vector<Reg2*> reg2_registers,
+        std::string (AssemblerArmTest::*GetName1)(const Reg1&),
+        std::string (AssemblerArmTest::*GetName2)(const Reg2&),
+        std::vector<std::pair<Imm, Imm>>& immediates,
+        std::string fmt) {
+    std::vector<Cond>& cond = GetConditions();
+
+    WarnOnCombinations(cond.size() * immediates.size() * reg1_registers.size() *
+                       reg2_registers.size());
+
+    std::ostringstream oss;
+    bool first = true;
+    for (Cond& c : cond) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      for (std::pair<Imm, Imm>& pair : immediates) {
+        Imm i = pair.first;
+        Imm j = pair.second;
+        std::string after_imm1 = after_cond;
+
+        size_t imm1_index = after_imm1.find(IMM1_TOKEN);
+        if (imm1_index != std::string::npos) {
+          std::ostringstream sreg;
+          sreg << i;
+          std::string imm_string = sreg.str();
+          after_imm1.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string);
+        }
+
+        std::string after_imm2 = after_imm1;
+
+        size_t imm2_index = after_imm2.find(IMM2_TOKEN);
+        if (imm2_index != std::string::npos) {
+          std::ostringstream sreg;
+          sreg << j;
+          std::string imm_string = sreg.str();
+          after_imm2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string);
+        }
+
+        for (auto reg1 : reg1_registers) {
+          std::string after_reg1 = after_imm2;
+
+          std::string reg1_string = (this->*GetName1)(*reg1);
+          size_t reg1_index;
+          while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
+            after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
+          }
+
+          for (auto reg2 : reg2_registers) {
+            std::string after_reg2 = after_reg1;
+
+            std::string reg2_string = (this->*GetName2)(*reg2);
+            size_t reg2_index;
+            while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
+              after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
+            }
+
+            if (first) {
+              first = false;
+            } else {
+              oss << "\n";
+            }
+            oss << after_reg2;
+
+            (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c);
+          }
+        }
+      }
+    }
+    // Add a newline at the end.
+    oss << "\n";
+
+    return oss.str();
+  }
+
+  std::string RepeatRRC(void (Ass::*f)(Reg, Reg, Cond), std::string fmt) {
+    return RepeatTemplatedRRC(f, GetRegisters(), GetRegisters(), GetConditions(),
+        &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+        fmt);
+  }
+
+  template <typename Reg1, typename Reg2>
+  std::string RepeatTemplatedRRC(void (Ass::*f)(Reg1, Reg2, Cond),
+                                 const std::vector<Reg1*>& reg1_registers,
+                                 const std::vector<Reg2*>& reg2_registers,
+                                 const std::vector<Cond>& cond,
+                                 std::string (AssemblerArmTest::*GetName1)(const Reg1&),
+                                 std::string (AssemblerArmTest::*GetName2)(const Reg2&),
+                                 std::string fmt) {
+    WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size());
+
+    std::ostringstream oss;
+    bool first = true;
+    for (const Cond& c : cond) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      for (auto reg1 : reg1_registers) {
+        std::string after_reg1 = after_cond;
+
+        std::string reg1_string = (this->*GetName1)(*reg1);
+        size_t reg1_index;
+        while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
+          after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
+        }
+
+        for (auto reg2 : reg2_registers) {
+          std::string after_reg2 = after_reg1;
+
+          std::string reg2_string = (this->*GetName2)(*reg2);
+          size_t reg2_index;
+          while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
+            after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
+          }
+
+          if (first) {
+            first = false;
+          } else {
+            oss << "\n";
+          }
+          oss << after_reg2;
+
+          (Base::GetAssembler()->*f)(*reg1, *reg2, c);
+        }
+      }
+    }
+    // Add a newline at the end.
+    oss << "\n";
+
+    return oss.str();
+  }
+
+  std::string RepeatRRRC(void (Ass::*f)(Reg, Reg, Reg, Cond), std::string fmt) {
+    return RepeatTemplatedRRRC(f, GetRegisters(), GetRegisters(), GetRegisters(), GetConditions(),
+                               &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+                               &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+                               &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>,
+                               fmt);
+  }
+
+  template <typename Reg1, typename Reg2, typename Reg3>
+  std::string RepeatTemplatedRRRC(void (Ass::*f)(Reg1, Reg2, Reg3, Cond),
+                                  const std::vector<Reg1*>& reg1_registers,
+                                  const std::vector<Reg2*>& reg2_registers,
+                                  const std::vector<Reg3*>& reg3_registers,
+                                  const std::vector<Cond>& cond,
+                                  std::string (AssemblerArmTest::*GetName1)(const Reg1&),
+                                  std::string (AssemblerArmTest::*GetName2)(const Reg2&),
+                                  std::string (AssemblerArmTest::*GetName3)(const Reg3&),
+                                  std::string fmt) {
+    WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() *
+                       reg3_registers.size());
+
+    std::ostringstream oss;
+    bool first = true;
+    for (const Cond& c : cond) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      for (auto reg1 : reg1_registers) {
+        std::string after_reg1 = after_cond;
+
+        std::string reg1_string = (this->*GetName1)(*reg1);
+        size_t reg1_index;
+        while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
+          after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
+        }
+
+        for (auto reg2 : reg2_registers) {
+          std::string after_reg2 = after_reg1;
+
+          std::string reg2_string = (this->*GetName2)(*reg2);
+          size_t reg2_index;
+          while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
+            after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
+          }
+
+          for (auto reg3 : reg3_registers) {
+            std::string after_reg3 = after_reg2;
+
+            std::string reg3_string = (this->*GetName3)(*reg3);
+            size_t reg3_index;
+            while ((reg3_index = after_reg3.find(REG3_TOKEN)) != std::string::npos) {
+              after_reg3.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
+            }
+
+            if (first) {
+              first = false;
+            } else {
+              oss << "\n";
+            }
+            oss << after_reg3;
+
+            (Base::GetAssembler()->*f)(*reg1, *reg2, *reg3, c);
+          }
+        }
+      }
+    }
+    // Add a newline at the end.
+    oss << "\n";
+
+    return oss.str();
+  }
+
+  template <typename RegT>
+  std::string RepeatTemplatedRSC(void (Ass::*f)(RegT, SOp, Cond),
+                                 const std::vector<RegT*>& registers,
+                                 const std::vector<SOp>& shifts,
+                                 const std::vector<Cond>& cond,
+                                 std::string (AssemblerArmTest::*GetName)(const RegT&),
+                                 std::string fmt) {
+    WarnOnCombinations(cond.size() * registers.size() * shifts.size());
+
+    std::ostringstream oss;
+    bool first = true;
+    for (const Cond& c : cond) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      for (const SOp& shift : shifts) {
+        std::string after_shift = after_cond;
+
+        std::string shift_string = GetShiftString(shift);
+        size_t shift_index;
+        while ((shift_index = after_shift.find(Base::SHIFT_TOKEN)) != std::string::npos) {
+          after_shift.replace(shift_index, ConstexprStrLen(Base::SHIFT_TOKEN), shift_string);
+        }
+
+        for (auto reg : registers) {
+          std::string after_reg = after_shift;
+
+          std::string reg_string = (this->*GetName)(*reg);
+          size_t reg_index;
+          while ((reg_index = after_reg.find(Base::REG_TOKEN)) != std::string::npos) {
+            after_reg.replace(reg_index, ConstexprStrLen(Base::REG_TOKEN), reg_string);
+          }
+
+          if (first) {
+            first = false;
+          } else {
+            oss << "\n";
+          }
+          oss << after_reg;
+
+          (Base::GetAssembler()->*f)(*reg, shift, c);
+        }
+      }
+    }
+    // Add a newline at the end.
+    oss << "\n";
+
+    return oss.str();
+  }
+
+  template <typename Reg1, typename Reg2>
+  std::string RepeatTemplatedRRSC(void (Ass::*f)(Reg1, Reg2, const SOp&, Cond),
+                                  const std::vector<Reg1*>& reg1_registers,
+                                  const std::vector<Reg2*>& reg2_registers,
+                                  const std::vector<SOp>& shifts,
+                                  const std::vector<Cond>& cond,
+                                  std::string (AssemblerArmTest::*GetName1)(const Reg1&),
+                                  std::string (AssemblerArmTest::*GetName2)(const Reg2&),
+                                  std::string fmt) {
+    WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * shifts.size());
+
+    std::ostringstream oss;
+    bool first = true;
+    for (const Cond& c : cond) {
+      std::string after_cond = fmt;
+
+      size_t cond_index = after_cond.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+
+      for (const SOp& shift : shifts) {
+        std::string after_shift = after_cond;
+
+        std::string shift_string = GetShiftString(shift);
+        size_t shift_index;
+        while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
+          after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+        }
+
+        for (auto reg1 : reg1_registers) {
+          std::string after_reg1 = after_shift;
+
+          std::string reg1_string = (this->*GetName1)(*reg1);
+          size_t reg1_index;
+          while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) {
+            after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string);
+          }
+
+          for (auto reg2 : reg2_registers) {
+            std::string after_reg2 = after_reg1;
+
+            std::string reg2_string = (this->*GetName2)(*reg2);
+            size_t reg2_index;
+            while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) {
+              after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string);
+            }
+
+            if (first) {
+              first = false;
+            } else {
+              oss << "\n";
+            }
+            oss << after_reg2;
+
+            (Base::GetAssembler()->*f)(*reg1, *reg2, shift, c);
+          }
+        }
+      }
+    }
+    // Add a newline at the end.
+    oss << "\n";
+
+    return oss.str();
+  }
+
+ protected:
+  explicit AssemblerArmTest() {}
+
+  virtual std::vector<Cond>& GetConditions() = 0;
+  virtual std::string GetConditionString(Cond c) = 0;
+
+  virtual std::vector<SOp>& GetShiftOperands() = 0;
+  virtual std::string GetShiftString(SOp sop) = 0;
+
+  virtual Reg GetPCRegister() = 0;
+  virtual std::vector<Reg*> GetRegistersWithoutPC() {
+    std::vector<Reg*> without_pc = GetRegisters();
+    Reg pc_reg = GetPCRegister();
+
+    for (auto it = without_pc.begin(); it != without_pc.end(); ++it) {
+      if (**it == pc_reg) {
+        without_pc.erase(it);
+        break;
+      }
+    }
+
+    return without_pc;
+  }
+
+  static constexpr const char* IMM1_TOKEN = "{imm1}";
+  static constexpr const char* IMM2_TOKEN = "{imm2}";
+  static constexpr const char* REG3_TOKEN = "{reg3}";
+  static constexpr const char* REG4_TOKEN = "{reg4}";
+  static constexpr const char* COND_TOKEN = "{cond}";
+  static constexpr const char* SHIFT_TOKEN = "{shift}";
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AssemblerArmTest);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 7968a77..3eccd3f 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -25,6 +25,39 @@
 namespace art {
 namespace arm {
 
+bool Thumb2Assembler::ShifterOperandCanHold(Register rd,
+                                            Register rn,
+                                            Opcode opcode,
+                                            uint32_t immediate,
+                                            ShifterOperand* shifter_op) {
+  shifter_op->type_ = ShifterOperand::kImmediate;
+  shifter_op->immed_ = immediate;
+  shifter_op->is_shift_ = false;
+  shifter_op->is_rotate_ = false;
+  switch (opcode) {
+    case ADD:
+    case SUB:
+      if (rn == SP) {
+        if (rd == SP) {
+          return immediate < (1 << 9);    // 9 bits allowed.
+        } else {
+          return immediate < (1 << 12);   // 12 bits.
+        }
+      }
+      if (immediate < (1 << 12)) {    // Less than (or equal to) 12 bits can always be done.
+        return true;
+      }
+      return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
+
+    case MOV:
+      // TODO: Support less than or equal to 12bits.
+      return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
+    case MVN:
+    default:
+      return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
+  }
+}
+
 void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so,
                            Condition cond) {
   EmitDataProcessing(cond, AND, 0, rn, rd, so);
@@ -152,6 +185,8 @@
 
 
 void Thumb2Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
+  CheckCondition(cond);
+
   if (rd == rm && !IsHighRegister(rd) && !IsHighRegister(rn) && !force_32bit_) {
     // 16 bit.
     int16_t encoding = B14 | B9 | B8 | B6 |
@@ -176,6 +211,8 @@
 
 void Thumb2Assembler::mla(Register rd, Register rn, Register rm, Register ra,
                           Condition cond) {
+  CheckCondition(cond);
+
   uint32_t op1 = 0U /* 0b000 */;
   uint32_t op2 = 0U /* 0b00 */;
   int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
@@ -192,6 +229,8 @@
 
 void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra,
                           Condition cond) {
+  CheckCondition(cond);
+
   uint32_t op1 = 0U /* 0b000 */;
   uint32_t op2 = 01 /* 0b01 */;
   int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
@@ -208,6 +247,8 @@
 
 void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
                             Register rm, Condition cond) {
+  CheckCondition(cond);
+
   uint32_t op1 = 2U /* 0b010; */;
   uint32_t op2 = 0U /* 0b0000 */;
   int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
@@ -223,6 +264,8 @@
 
 
 void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
+  CheckCondition(cond);
+
   uint32_t op1 = 1U  /* 0b001 */;
   uint32_t op2 = 15U /* 0b1111 */;
   int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 |
@@ -238,6 +281,8 @@
 
 
 void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
+  CheckCondition(cond);
+
   uint32_t op1 = 1U  /* 0b001 */;
   uint32_t op2 = 15U /* 0b1111 */;
   int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 |
@@ -252,6 +297,48 @@
 }
 
 
+void Thumb2Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
+  CheckCondition(cond);
+  CHECK_LE(lsb, 31U);
+  CHECK(1U <= width && width <= 32U) << width;
+  uint32_t widthminus1 = width - 1;
+  uint32_t imm2 = lsb & (B1 | B0);  // Bits 0-1 of `lsb`.
+  uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2;  // Bits 2-4 of `lsb`.
+
+  uint32_t op = 20U /* 0b10100 */;
+  int32_t encoding = B31 | B30 | B29 | B28 | B25 |
+      op << 20 |
+      static_cast<uint32_t>(rn) << 16 |
+      imm3 << 12 |
+      static_cast<uint32_t>(rd) << 8 |
+      imm2 << 6 |
+      widthminus1;
+
+  Emit32(encoding);
+}
+
+
+void Thumb2Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
+  CheckCondition(cond);
+  CHECK_LE(lsb, 31U);
+  CHECK(1U <= width && width <= 32U) << width;
+  uint32_t widthminus1 = width - 1;
+  uint32_t imm2 = lsb & (B1 | B0);  // Bits 0-1 of `lsb`.
+  uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2;  // Bits 2-4 of `lsb`.
+
+  uint32_t op = 28U /* 0b11100 */;
+  int32_t encoding = B31 | B30 | B29 | B28 | B25 |
+      op << 20 |
+      static_cast<uint32_t>(rn) << 16 |
+      imm3 << 12 |
+      static_cast<uint32_t>(rd) << 8 |
+      imm2 << 6 |
+      widthminus1;
+
+  Emit32(encoding);
+}
+
+
 void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
   EmitLoadStore(cond, true, false, false, false, rd, ad);
 }
@@ -293,6 +380,7 @@
 
 
 void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
+  CheckCondition(cond);
   CHECK_EQ(rd % 2, 0);
   // This is different from other loads.  The encoding is like ARM.
   int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
@@ -304,6 +392,7 @@
 
 
 void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
+  CheckCondition(cond);
   CHECK_EQ(rd % 2, 0);
   // This is different from other loads.  The encoding is like ARM.
   int32_t encoding = B31 | B30 | B29 | B27 | B22 |
@@ -318,16 +407,11 @@
                           Register base,
                           RegList regs,
                           Condition cond) {
-  if (__builtin_popcount(regs) == 1) {
+  CHECK_NE(regs, 0u);  // Do not use ldm if there's nothing to load.
+  if (IsPowerOfTwo(regs)) {
     // Thumb doesn't support one reg in the list.
     // Find the register number.
-    int reg = 0;
-    while (reg < 16) {
-      if ((regs & (1 << reg)) != 0) {
-         break;
-      }
-      ++reg;
-    }
+    int reg = CTZ(static_cast<uint32_t>(regs));
     CHECK_LT(reg, 16);
     CHECK(am == DB_W);      // Only writeback is supported.
     ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
@@ -341,16 +425,11 @@
                           Register base,
                           RegList regs,
                           Condition cond) {
-  if (__builtin_popcount(regs) == 1) {
+  CHECK_NE(regs, 0u);  // Do not use stm if there's nothing to store.
+  if (IsPowerOfTwo(regs)) {
     // Thumb doesn't support one reg in the list.
     // Find the register number.
-    int reg = 0;
-    while (reg < 16) {
-      if ((regs & (1 << reg)) != 0) {
-         break;
-      }
-      ++reg;
-    }
+    int reg = CTZ(static_cast<uint32_t>(regs));
     CHECK_LT(reg, 16);
     CHECK(am == IA || am == IA_W);
     Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
@@ -609,9 +688,9 @@
 }
 
 
-bool Thumb2Assembler::Is32BitDataProcessing(Condition cond,
+bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
                                             Opcode opcode,
-                                            int set_cc,
+                                            bool set_cc ATTRIBUTE_UNUSED,
                                             Register rn,
                                             Register rd,
                                             const ShifterOperand& so) {
@@ -619,48 +698,37 @@
     return true;
   }
 
-  bool can_contain_high_register = (opcode == MOV)
-      || ((opcode == ADD || opcode == SUB) && (rn == rd));
-
-  if (IsHighRegister(rd) || IsHighRegister(rn)) {
-    if (can_contain_high_register) {
-      // There are high register instructions available for this opcode.
-      // However, there is no RRX available.
-      if (so.IsShift() && so.GetShift() == RRX) {
-        return true;
+  // Check special case for SP relative ADD and SUB immediate.
+  if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) {
+    // If the immediate is in range, use 16 bit.
+    if (rd == SP) {
+      if (so.GetImmediate() < (1 << 9)) {    // 9 bit immediate.
+        return false;
       }
-
-      // Check special case for SP relative ADD and SUB immediate.
-      if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
-        // If rn is SP and rd is a high register we need to use a 32 bit encoding.
-         if (rn == SP && rd != SP && IsHighRegister(rd)) {
-           return true;
-         }
-
-         uint32_t imm = so.GetImmediate();
-         // If the immediates are out of range use 32 bit.
-         if (rd == SP && rn == SP) {
-           if (imm > (1 << 9)) {    // 9 bit immediate.
-             return true;
-           }
-         } else if (opcode == ADD && rd != SP && rn == SP) {   // 10 bit immediate.
-           if (imm > (1 << 10)) {
-             return true;
-           }
-         } else if (opcode == SUB && rd != SP && rn == SP) {
-           // SUB rd, SP, #imm is always 32 bit.
-           return true;
-         }
+    } else if (!IsHighRegister(rd) && opcode == ADD) {
+      if (so.GetImmediate() < (1 << 10)) {    // 10 bit immediate.
+        return false;
       }
     }
+  }
 
-    // The ADD,SUB and MOV instructions that work with high registers don't have
-    // immediate variants.
-    if (so.IsImmediate()) {
+  bool can_contain_high_register = (opcode == MOV)
+      || ((opcode == ADD) && (rn == rd));
+
+  if (IsHighRegister(rd) || IsHighRegister(rn)) {
+    if (!can_contain_high_register) {
       return true;
     }
 
-    if (!can_contain_high_register) {
+    // There are high register instructions available for this opcode.
+    // However, there is no actual shift available, neither for ADD nor for MOV (ASR/LSR/LSL/ROR).
+    if (so.IsShift() && (so.GetShift() == RRX || so.GetImmediate() != 0u)) {
+      return true;
+    }
+
+    // The ADD and MOV instructions that work with high registers don't have 16-bit
+    // immediate variants.
+    if (so.IsImmediate()) {
       return true;
     }
   }
@@ -727,9 +795,9 @@
 }
 
 
-void Thumb2Assembler::Emit32BitDataProcessing(Condition cond,
+void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
                                               Opcode opcode,
-                                              int set_cc,
+                                              bool set_cc,
                                               Register rn,
                                               Register rd,
                                               const ShifterOperand& so) {
@@ -757,6 +825,7 @@
 
   if (thumb_opcode == 255U /* 0b11111111 */) {
     LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
+    UNREACHABLE();
   }
 
   int32_t encoding = 0;
@@ -786,10 +855,11 @@
       uint32_t imm = ModifiedImmediate(so.encodingThumb());
       if (imm == kInvalidModifiedImmediate) {
         LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
+        UNREACHABLE();
       }
       encoding = B31 | B30 | B29 | B28 |
           thumb_opcode << 21 |
-          set_cc << 20 |
+          (set_cc ? 1 : 0) << 20 |
           rn << 16 |
           rd << 8 |
           imm;
@@ -798,7 +868,7 @@
      // Register (possibly shifted)
      encoding = B31 | B30 | B29 | B27 | B25 |
          thumb_opcode << 21 |
-         set_cc << 20 |
+         (set_cc ? 1 : 0) << 20 |
          rn << 16 |
          rd << 8 |
          so.encodingThumb();
@@ -809,7 +879,7 @@
 
 void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
                                               Opcode opcode,
-                                              int set_cc,
+                                              bool set_cc,
                                               Register rn,
                                               Register rd,
                                               const ShifterOperand& so) {
@@ -923,6 +993,7 @@
 
   if (thumb_opcode == 255U /* 0b11111111 */) {
     LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
+    UNREACHABLE();
   }
 
   int16_t encoding = dp_opcode << 14 |
@@ -936,9 +1007,9 @@
 
 
 // ADD and SUB are complex enough to warrant their own emitter.
-void Thumb2Assembler::Emit16BitAddSub(Condition cond,
+void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
                                       Opcode opcode,
-                                      int set_cc,
+                                      bool set_cc ATTRIBUTE_UNUSED,
                                       Register rn,
                                       Register rd,
                                       const ShifterOperand& so) {
@@ -948,7 +1019,7 @@
   uint8_t rn_shift = 3;
   uint8_t immediate_shift = 0;
   bool use_immediate = false;
-  uint8_t immediate = 0;
+  uint32_t immediate = 0;  // Should be at most 9 bits but keep the full immediate for CHECKs.
   uint8_t thumb_opcode;;
 
   if (so.IsImmediate()) {
@@ -984,8 +1055,8 @@
           dp_opcode = 2U /* 0b10 */;
           thumb_opcode = 3U /* 0b11 */;
           opcode_shift = 12;
-          CHECK_LT(immediate, (1 << 9));
-          CHECK_EQ((immediate & 3 /* 0b11 */), 0);
+          CHECK_LT(immediate, (1u << 9));
+          CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
 
           // Remove rd and rn from instruction by orring it with immed and clearing bits.
           rn = R0;
@@ -998,8 +1069,8 @@
           dp_opcode = 2U /* 0b10 */;
           thumb_opcode = 5U /* 0b101 */;
           opcode_shift = 11;
-          CHECK_LT(immediate, (1 << 10));
-          CHECK_EQ((immediate & 3 /* 0b11 */), 0);
+          CHECK_LT(immediate, (1u << 10));
+          CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
 
           // Remove rn from instruction.
           rn = R0;
@@ -1035,8 +1106,8 @@
            dp_opcode = 2U /* 0b10 */;
            thumb_opcode = 0x61 /* 0b1100001 */;
            opcode_shift = 7;
-           CHECK_LT(immediate, (1 << 9));
-           CHECK_EQ((immediate & 3 /* 0b11 */), 0);
+           CHECK_LT(immediate, (1u << 9));
+           CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
 
            // Remove rd and rn from instruction by orring it with immed and clearing bits.
            rn = R0;
@@ -1060,7 +1131,7 @@
       break;
     default:
       LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
-      return;
+      UNREACHABLE();
   }
 
   int16_t encoding = dp_opcode << 14 |
@@ -1075,7 +1146,7 @@
 
 void Thumb2Assembler::EmitDataProcessing(Condition cond,
                                          Opcode opcode,
-                                         int set_cc,
+                                         bool set_cc,
                                          Register rn,
                                          Register rd,
                                          const ShifterOperand& so) {
@@ -1101,6 +1172,7 @@
       case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
       default:
         LOG(FATAL) << "Unsupported thumb2 shift opcode";
+        UNREACHABLE();
     }
     // 32 bit.
     int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
@@ -1118,7 +1190,8 @@
       case LSR: opcode = 1U /* 0b01 */; break;
       case ASR: opcode = 2U /* 0b10 */; break;
       default:
-         LOG(FATAL) << "Unsupported thumb2 shift opcode";
+        LOG(FATAL) << "Unsupported thumb2 shift opcode";
+        UNREACHABLE();
     }
     int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
         static_cast<int16_t>(rd);
@@ -1142,6 +1215,7 @@
        case ROR: opcode = 3U /* 0b11 */; break;
        default:
          LOG(FATAL) << "Unsupported thumb2 shift opcode";
+         UNREACHABLE();
      }
      // 32 bit.
      int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
@@ -1156,7 +1230,8 @@
       case LSR: opcode = 3U /* 0b0011 */; break;
       case ASR: opcode = 4U /* 0b0100 */; break;
       default:
-         LOG(FATAL) << "Unsupported thumb2 shift opcode";
+        LOG(FATAL) << "Unsupported thumb2 shift opcode";
+        UNREACHABLE();
     }
     int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
         static_cast<int16_t>(rd);
@@ -1185,6 +1260,7 @@
     } else {
       if (x) {
         LOG(FATAL) << "Invalid use of BX";
+        UNREACHABLE();
       } else {
         if (cond_ == AL) {
           // Can use the T4 encoding allowing a 24 bit offset.
@@ -1405,7 +1481,7 @@
 
 
 void Thumb2Assembler::EmitMultiMemOp(Condition cond,
-                                     BlockAddressMode am,
+                                     BlockAddressMode bam,
                                      bool load,
                                      Register base,
                                      RegList regs) {
@@ -1413,11 +1489,20 @@
   CheckCondition(cond);
   bool must_be_32bit = force_32bit_;
 
+  if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
+      (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
+    // Use 16-bit PUSH/POP.
+    int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
+        ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
+    Emit16(encoding);
+    return;
+  }
+
   if ((regs & 0xff00) != 0) {
     must_be_32bit = true;
   }
 
-  uint32_t w_bit = am == IA_W || am == DB_W || am == DA_W || am == IB_W;
+  bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
   // 16 bit always uses writeback.
   if (!w_bit) {
     must_be_32bit = true;
@@ -1425,7 +1510,7 @@
 
   if (must_be_32bit) {
     uint32_t op = 0;
-    switch (am) {
+    switch (bam) {
       case IA:
       case IA_W:
         op = 1U /* 0b01 */;
@@ -1438,7 +1523,8 @@
       case IB:
       case DA_W:
       case IB_W:
-        LOG(FATAL) << "LDM/STM mode not supported on thumb: " << am;
+        LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
+        UNREACHABLE();
     }
     if (load) {
       // Cannot have SP in the list.
@@ -1576,9 +1662,6 @@
   CHECK_NE(rn, kNoRegister);
   CHECK_NE(rt, kNoRegister);
   CheckCondition(cond);
-  CHECK_NE(rn, kNoRegister);
-  CHECK_NE(rt, kNoRegister);
-  CheckCondition(cond);
   CHECK_LT(imm, (1u << 10));
 
   int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
@@ -1615,6 +1698,22 @@
 }
 
 
+void Thumb2Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
+  CHECK_NE(rn, kNoRegister);
+  CHECK_NE(rt, kNoRegister);
+  CHECK_NE(rt2, kNoRegister);
+  CHECK_NE(rt, rt2);
+  CheckCondition(cond);
+
+  int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 | B20 |
+      static_cast<uint32_t>(rn) << 16 |
+      static_cast<uint32_t>(rt) << 12 |
+      static_cast<uint32_t>(rt2) << 8 |
+      B6 | B5 | B4 | B3 | B2 | B1 | B0;
+  Emit32(encoding);
+}
+
+
 void Thumb2Assembler::strex(Register rd,
                             Register rt,
                             Register rn,
@@ -1623,6 +1722,26 @@
 }
 
 
+void Thumb2Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
+  CHECK_NE(rd, kNoRegister);
+  CHECK_NE(rn, kNoRegister);
+  CHECK_NE(rt, kNoRegister);
+  CHECK_NE(rt2, kNoRegister);
+  CHECK_NE(rt, rt2);
+  CHECK_NE(rd, rt);
+  CHECK_NE(rd, rt2);
+  CheckCondition(cond);
+
+  int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 |
+      static_cast<uint32_t>(rn) << 16 |
+      static_cast<uint32_t>(rt) << 12 |
+      static_cast<uint32_t>(rt2) << 8 |
+      B6 | B5 | B4 |
+      static_cast<uint32_t>(rd);
+  Emit32(encoding);
+}
+
+
 void Thumb2Assembler::clrex(Condition cond) {
   CheckCondition(cond);
   int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
@@ -1925,8 +2044,13 @@
 
 
 void Thumb2Assembler::vmstat(Condition cond) {  // VMRS APSR_nzcv, FPSCR.
+  CHECK_NE(cond, kNoCondition);
   CheckCondition(cond);
-  UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
+  int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
+      B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
+      (static_cast<int32_t>(PC)*B12) |
+      B11 | B9 | B4;
+  Emit32(encoding);
 }
 
 
@@ -2012,6 +2136,7 @@
   CheckCondition(AL);
   if (label->IsBound()) {
     LOG(FATAL) << "cbz can only be used to branch forwards";
+    UNREACHABLE();
   } else {
     uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
     label->LinkTo(branchid);
@@ -2023,6 +2148,7 @@
   CheckCondition(AL);
   if (label->IsBound()) {
     LOG(FATAL) << "cbnz can only be used to branch forwards";
+    UNREACHABLE();
   } else {
     uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
     label->LinkTo(branchid);
@@ -2107,8 +2233,8 @@
         branch->ResetSize(Branch::k16Bit);
 
         // Now add a compare instruction in the place the branch was.
-        int16_t cmp = B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8;
-        buffer_.Store<int16_t>(branch_location, cmp);
+        buffer_.Store<int16_t>(branch_location,
+                               B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
 
         // Since have moved made a hole in the code we need to reload the
         // current pc.
@@ -2154,7 +2280,7 @@
 
 void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
                           bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Do not use Lsl if no shift is wanted.
+  CHECK_LE(shift_imm, 31u);
   CheckCondition(cond);
   EmitShift(rd, rm, LSL, shift_imm, setcc);
 }
@@ -2162,7 +2288,7 @@
 
 void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
                           bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Do not use Lsr if no shift is wanted.
+  CHECK(1u <= shift_imm && shift_imm <= 32u);
   if (shift_imm == 32) shift_imm = 0;  // Comply to UAL syntax.
   CheckCondition(cond);
   EmitShift(rd, rm, LSR, shift_imm, setcc);
@@ -2171,7 +2297,7 @@
 
 void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
                           bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Do not use Asr if no shift is wanted.
+  CHECK(1u <= shift_imm && shift_imm <= 32u);
   if (shift_imm == 32) shift_imm = 0;  // Comply to UAL syntax.
   CheckCondition(cond);
   EmitShift(rd, rm, ASR, shift_imm, setcc);
@@ -2180,7 +2306,7 @@
 
 void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
                           bool setcc, Condition cond) {
-  CHECK_NE(shift_imm, 0u);  // Use Rrx instruction.
+  CHECK(1u <= shift_imm && shift_imm <= 31u);
   CheckCondition(cond);
   EmitShift(rd, rm, ROR, shift_imm, setcc);
 }
@@ -2304,16 +2430,16 @@
   // positive values and sub for negatives ones, which would slightly improve
   // the readability of generated code for some constants.
   ShifterOperand shifter_op;
-  if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
+  if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
     add(rd, rn, shifter_op, cond);
-  } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
+  } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
     sub(rd, rn, shifter_op, cond);
   } else {
     CHECK(rn != IP);
-    if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
+    if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
       mvn(IP, shifter_op, cond);
       add(rd, rn, ShifterOperand(IP), cond);
-    } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
+    } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
       mvn(IP, shifter_op, cond);
       sub(rd, rn, ShifterOperand(IP), cond);
     } else {
@@ -2331,16 +2457,16 @@
 void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
                                           Condition cond) {
   ShifterOperand shifter_op;
-  if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
+  if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
     adds(rd, rn, shifter_op, cond);
-  } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
+  } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
     subs(rd, rn, shifter_op, cond);
   } else {
     CHECK(rn != IP);
-    if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
+    if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
       mvn(IP, shifter_op, cond);
       adds(rd, rn, ShifterOperand(IP), cond);
-    } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
+    } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
       mvn(IP, shifter_op, cond);
       subs(rd, rn, ShifterOperand(IP), cond);
     } else {
@@ -2357,9 +2483,9 @@
 
 void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
   ShifterOperand shifter_op;
-  if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
+  if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
     mov(rd, shifter_op, cond);
-  } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
+  } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
     mvn(rd, shifter_op, cond);
   } else {
     movw(rd, Low16Bits(value), cond);
@@ -2370,6 +2496,7 @@
   }
 }
 
+
 // Implementation note: this method must emit at most one instruction when
 // Address::CanHoldLoadOffsetThumb.
 void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
@@ -2378,7 +2505,7 @@
                                      int32_t offset,
                                      Condition cond) {
   if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
-    CHECK(base != IP);
+    CHECK_NE(base, IP);
     LoadImmediate(IP, offset, cond);
     add(IP, IP, ShifterOperand(base), cond);
     base = IP;
@@ -2406,6 +2533,7 @@
       break;
     default:
       LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
   }
 }
 
@@ -2453,12 +2581,26 @@
                                     Register base,
                                     int32_t offset,
                                     Condition cond) {
+  Register tmp_reg = kNoRegister;
   if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
-    CHECK(reg != IP);
-    CHECK(base != IP);
-    LoadImmediate(IP, offset, cond);
-    add(IP, IP, ShifterOperand(base), cond);
-    base = IP;
+    CHECK_NE(base, IP);
+    if (reg != IP) {
+      tmp_reg = IP;
+    } else {
+      // Be careful not to use IP twice (for `reg` and to build the
+      // Address object used by the store instruction(s) below).
+      // Instead, save R5 on the stack (or R6 if R5 is not available),
+      // use it as secondary temporary register, and restore it after
+      // the store instruction has been emitted.
+      tmp_reg = base != R5 ? R5 : R6;
+      Push(tmp_reg);
+      if (base == SP) {
+        offset += kRegisterSize;
+      }
+    }
+    LoadImmediate(tmp_reg, offset, cond);
+    add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
+    base = tmp_reg;
     offset = 0;
   }
   CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
@@ -2477,6 +2619,11 @@
       break;
     default:
       LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
+  }
+  if (tmp_reg != kNoRegister && tmp_reg != IP) {
+    DCHECK(tmp_reg == R5 || tmp_reg == R6);
+    Pop(tmp_reg);
   }
 }
 
@@ -2519,10 +2666,13 @@
 
 void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
   CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
-#if ANDROID_SMP != 0
-  int32_t encoding = 0xf3bf8f5f;  // dmb in T1 encoding.
-  Emit32(encoding);
-#endif
+  dmb(SY);
+}
+
+
+void Thumb2Assembler::dmb(DmbOptions flavor) {
+  int32_t encoding = 0xf3bf8f50;  // dmb in T1 encoding.
+  Emit32(encoding | flavor);
 }
 
 
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index ee33bf2..81dd138 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -118,6 +118,10 @@
   void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
   void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
 
+  // Bit field extract instructions.
+  void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
+  void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
+
   // Load/store instructions.
   void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
   void str(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
@@ -145,6 +149,8 @@
   void ldrex(Register rd, Register rn, uint16_t imm, Condition cond = AL);
   void strex(Register rd, Register rt, Register rn, uint16_t imm, Condition cond = AL);
 
+  void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
+  void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
 
   // Miscellaneous instructions.
   void clrex(Condition cond = AL) OVERRIDE;
@@ -259,6 +265,9 @@
   void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE;
   void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE;
 
+  // Memory barriers.
+  void dmb(DmbOptions flavor) OVERRIDE;
+
   // Macros.
   // Add signed constant value to rd. May clobber IP.
   void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
@@ -266,14 +275,9 @@
                    Condition cond = AL) OVERRIDE;
   void AddConstantSetFlags(Register rd, Register rn, int32_t value,
                            Condition cond = AL) OVERRIDE;
-  void AddConstantWithCarry(Register rd, Register rn, int32_t value,
-                            Condition cond = AL) {}
 
   // Load and Store. May clobber IP.
   void LoadImmediate(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
-  void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {}
-  void LoadDImmediate(DRegister dd, double value,
-                      Register scratch, Condition cond = AL) {}
   void MarkExceptionHandler(Label* label) OVERRIDE;
   void LoadFromOffset(LoadOperandType type,
                       Register reg,
@@ -302,8 +306,14 @@
                       int32_t offset,
                       Condition cond = AL) OVERRIDE;
 
+  bool ShifterOperandCanHold(Register rd,
+                             Register rn,
+                             Opcode opcode,
+                             uint32_t immediate,
+                             ShifterOperand* shifter_op) OVERRIDE;
 
-  static bool IsInstructionForExceptionHandling(uword pc);
+
+  static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
   // Emit data (e.g. encoded instruction or immediate) to the.
   // instruction stream.
@@ -321,40 +331,40 @@
  private:
   // Emit a single 32 or 16 bit data processing instruction.
   void EmitDataProcessing(Condition cond,
-                  Opcode opcode,
-                  int set_cc,
-                  Register rn,
-                  Register rd,
-                  const ShifterOperand& so);
+                          Opcode opcode,
+                          bool set_cc,
+                          Register rn,
+                          Register rd,
+                          const ShifterOperand& so);
 
   // Must the instruction be 32 bits or can it possibly be encoded
   // in 16 bits?
   bool Is32BitDataProcessing(Condition cond,
-                  Opcode opcode,
-                  int set_cc,
-                  Register rn,
-                  Register rd,
-                  const ShifterOperand& so);
+                             Opcode opcode,
+                             bool set_cc,
+                             Register rn,
+                             Register rd,
+                             const ShifterOperand& so);
 
   // Emit a 32 bit data processing instruction.
   void Emit32BitDataProcessing(Condition cond,
-                  Opcode opcode,
-                  int set_cc,
-                  Register rn,
-                  Register rd,
-                  const ShifterOperand& so);
+                               Opcode opcode,
+                               bool set_cc,
+                               Register rn,
+                               Register rd,
+                               const ShifterOperand& so);
 
   // Emit a 16 bit data processing instruction.
   void Emit16BitDataProcessing(Condition cond,
-                  Opcode opcode,
-                  int set_cc,
-                  Register rn,
-                  Register rd,
-                  const ShifterOperand& so);
+                               Opcode opcode,
+                               bool set_cc,
+                               Register rn,
+                               Register rd,
+                               const ShifterOperand& so);
 
   void Emit16BitAddSub(Condition cond,
                        Opcode opcode,
-                       int set_cc,
+                       bool set_cc,
                        Register rn,
                        Register rd,
                        const ShifterOperand& so);
@@ -362,12 +372,12 @@
   uint16_t EmitCompareAndBranch(Register rn, uint16_t prev, bool n);
 
   void EmitLoadStore(Condition cond,
-                 bool load,
-                 bool byte,
-                 bool half,
-                 bool is_signed,
-                 Register rd,
-                 const Address& ad);
+                     bool load,
+                     bool byte,
+                     bool half,
+                     bool is_signed,
+                     Register rd,
+                     const Address& ad);
 
   void EmitMemOpAddressMode3(Condition cond,
                              int32_t mode,
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
new file mode 100644
index 0000000..425ccd7
--- /dev/null
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -0,0 +1,195 @@
+/*
+ * 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 "assembler_thumb2.h"
+
+#include "base/stl_util.h"
+#include "utils/assembler_test.h"
+
+namespace art {
+
+class AssemblerThumb2Test : public AssemblerTest<arm::Thumb2Assembler,
+                                                 arm::Register, arm::SRegister,
+                                                 uint32_t> {
+ protected:
+  std::string GetArchitectureString() OVERRIDE {
+    return "arm";
+  }
+
+  std::string GetAssemblerParameters() OVERRIDE {
+    return " -mthumb -mfpu=neon";
+  }
+
+  std::string GetDisassembleParameters() OVERRIDE {
+    return " -D -bbinary -marm --no-show-raw-insn";
+  }
+
+  void SetUpHelpers() OVERRIDE {
+    if (registers_.size() == 0) {
+      registers_.insert(end(registers_),
+                        {  // NOLINT(whitespace/braces)
+                          new arm::Register(arm::R0),
+                          new arm::Register(arm::R1),
+                          new arm::Register(arm::R2),
+                          new arm::Register(arm::R3),
+                          new arm::Register(arm::R4),
+                          new arm::Register(arm::R5),
+                          new arm::Register(arm::R6),
+                          new arm::Register(arm::R7),
+                          new arm::Register(arm::R8),
+                          new arm::Register(arm::R9),
+                          new arm::Register(arm::R10),
+                          new arm::Register(arm::R11),
+                          new arm::Register(arm::R12),
+                          new arm::Register(arm::R13),
+                          new arm::Register(arm::R14),
+                          new arm::Register(arm::R15)
+                        });
+    }
+  }
+
+  void TearDown() OVERRIDE {
+    AssemblerTest::TearDown();
+    STLDeleteElements(&registers_);
+  }
+
+  std::vector<arm::Register*> GetRegisters() OVERRIDE {
+    return registers_;
+  }
+
+  uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
+    return imm_value;
+  }
+
+ private:
+  std::vector<arm::Register*> registers_;
+};
+
+
+TEST_F(AssemblerThumb2Test, Toolchain) {
+  EXPECT_TRUE(CheckTools());
+}
+
+
+TEST_F(AssemblerThumb2Test, Sbfx) {
+  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 1);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 8);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 16);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 32);
+
+  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 1);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 8);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 16);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 24);
+
+  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 1);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 8);
+  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 16);
+
+  GetAssembler()->sbfx(arm::R0, arm::R1, 31, 1);
+
+  const char* expected =
+      "sbfx r0, r1, #0, #1\n"
+      "sbfx r0, r1, #0, #8\n"
+      "sbfx r0, r1, #0, #16\n"
+      "sbfx r0, r1, #0, #32\n"
+
+      "sbfx r0, r1, #8, #1\n"
+      "sbfx r0, r1, #8, #8\n"
+      "sbfx r0, r1, #8, #16\n"
+      "sbfx r0, r1, #8, #24\n"
+
+      "sbfx r0, r1, #16, #1\n"
+      "sbfx r0, r1, #16, #8\n"
+      "sbfx r0, r1, #16, #16\n"
+
+      "sbfx r0, r1, #31, #1\n";
+  DriverStr(expected, "sbfx");
+}
+
+TEST_F(AssemblerThumb2Test, Ubfx) {
+  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32);
+
+  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24);
+
+  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8);
+  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16);
+
+  GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1);
+
+  const char* expected =
+      "ubfx r0, r1, #0, #1\n"
+      "ubfx r0, r1, #0, #8\n"
+      "ubfx r0, r1, #0, #16\n"
+      "ubfx r0, r1, #0, #32\n"
+
+      "ubfx r0, r1, #8, #1\n"
+      "ubfx r0, r1, #8, #8\n"
+      "ubfx r0, r1, #8, #16\n"
+      "ubfx r0, r1, #8, #24\n"
+
+      "ubfx r0, r1, #16, #1\n"
+      "ubfx r0, r1, #16, #8\n"
+      "ubfx r0, r1, #16, #16\n"
+
+      "ubfx r0, r1, #31, #1\n";
+  DriverStr(expected, "ubfx");
+}
+
+TEST_F(AssemblerThumb2Test, Vmstat) {
+  GetAssembler()->vmstat();
+
+  const char* expected = "vmrs APSR_nzcv, FPSCR\n";
+
+  DriverStr(expected, "vmrs");
+}
+
+TEST_F(AssemblerThumb2Test, ldrexd) {
+  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
+  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
+  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
+  GetAssembler()->ldrexd(arm::R5, arm::R3, arm::R7);
+
+  const char* expected =
+      "ldrexd r0, r1, [r0]\n"
+      "ldrexd r0, r1, [r1]\n"
+      "ldrexd r0, r1, [r2]\n"
+      "ldrexd r5, r3, [r7]\n";
+  DriverStr(expected, "ldrexd");
+}
+
+TEST_F(AssemblerThumb2Test, strexd) {
+  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
+  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
+  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
+  GetAssembler()->strexd(arm::R9, arm::R5, arm::R3, arm::R7);
+
+  const char* expected =
+      "strexd r9, r0, r1, [r0]\n"
+      "strexd r9, r0, r1, [r1]\n"
+      "strexd r9, r0, r1, [r2]\n"
+      "strexd r9, r5, r3, [r7]\n";
+  DriverStr(expected, "strexd");
+}
+
+}  // namespace art
diff --git a/compiler/utils/arm/constants_arm.h b/compiler/utils/arm/constants_arm.h
index 3e4cd43..1513296 100644
--- a/compiler/utils/arm/constants_arm.h
+++ b/compiler/utils/arm/constants_arm.h
@@ -38,15 +38,16 @@
 // Constants for specific fields are defined in their respective named enums.
 // General constants are in an anonymous enum in class Instr.
 
-
-// We support both VFPv3-D16 and VFPv3-D32 profiles, but currently only one at
-// a time, so that compile time optimizations can be applied.
-// Warning: VFPv3-D32 is untested.
-#define VFPv3_D16
-#if defined(VFPv3_D16) == defined(VFPv3_D32)
-#error "Exactly one of VFPv3_D16 or VFPv3_D32 can be defined at a time."
-#endif
-
+// 4 bits option for the dmb instruction.
+// Order and values follows those of the ARM Architecture Reference Manual.
+enum DmbOptions {
+  SY = 0xf,
+  ST = 0xe,
+  ISH = 0xb,
+  ISHST = 0xa,
+  NSH = 0x7,
+  NSHST = 0x6
+};
 
 enum ScaleFactor {
   TIMES_1 = 0,
@@ -56,26 +57,23 @@
 };
 
 // Values for double-precision floating point registers.
-enum DRegister {
-  D0  =  0,
-  D1  =  1,
-  D2  =  2,
-  D3  =  3,
-  D4  =  4,
-  D5  =  5,
-  D6  =  6,
-  D7  =  7,
-  D8  =  8,
-  D9  =  9,
+enum DRegister {  // private marker to avoid generate-operator-out.py from processing.
+  D0  = 0,
+  D1  = 1,
+  D2  = 2,
+  D3  = 3,
+  D4  = 4,
+  D5  = 5,
+  D6  = 6,
+  D7  = 7,
+  D8  = 8,
+  D9  = 9,
   D10 = 10,
   D11 = 11,
   D12 = 12,
   D13 = 13,
   D14 = 14,
   D15 = 15,
-#ifdef VFPv3_D16
-  kNumberOfDRegisters = 16,
-#else
   D16 = 16,
   D17 = 17,
   D18 = 18,
@@ -93,7 +91,6 @@
   D30 = 30,
   D31 = 31,
   kNumberOfDRegisters = 32,
-#endif
   kNumberOfOverlappingDRegisters = 16,
   kNoDRegister = -1,
 };
@@ -101,18 +98,18 @@
 
 
 // Values for the condition field as defined in section A3.2.
-enum Condition {
+enum Condition {  // private marker to avoid generate-operator-out.py from processing.
   kNoCondition = -1,
-  EQ =  0,  // equal
-  NE =  1,  // not equal
-  CS =  2,  // carry set/unsigned higher or same
-  CC =  3,  // carry clear/unsigned lower
-  MI =  4,  // minus/negative
-  PL =  5,  // plus/positive or zero
-  VS =  6,  // overflow
-  VC =  7,  // no overflow
-  HI =  8,  // unsigned higher
-  LS =  9,  // unsigned lower or same
+  EQ = 0,   // equal
+  NE = 1,   // not equal
+  CS = 2,   // carry set/unsigned higher or same
+  CC = 3,   // carry clear/unsigned lower
+  MI = 4,   // minus/negative
+  PL = 5,   // plus/positive or zero
+  VS = 6,   // overflow
+  VC = 7,   // no overflow
+  HI = 8,   // unsigned higher
+  LS = 9,   // unsigned lower or same
   GE = 10,  // signed greater than or equal
   LT = 11,  // signed less than
   GT = 12,  // signed greater than
@@ -128,16 +125,16 @@
 // as defined in section A3.4
 enum Opcode {
   kNoOperand = -1,
-  AND =  0,  // Logical AND
-  EOR =  1,  // Logical Exclusive OR
-  SUB =  2,  // Subtract
-  RSB =  3,  // Reverse Subtract
-  ADD =  4,  // Add
-  ADC =  5,  // Add with Carry
-  SBC =  6,  // Subtract with Carry
-  RSC =  7,  // Reverse Subtract with Carry
-  TST =  8,  // Test
-  TEQ =  9,  // Test Equivalence
+  AND = 0,   // Logical AND
+  EOR = 1,   // Logical Exclusive OR
+  SUB = 2,   // Subtract
+  RSB = 3,   // Reverse Subtract
+  ADD = 4,   // Add
+  ADC = 5,   // Add with Carry
+  SBC = 6,   // Subtract with Carry
+  RSC = 7,   // Reverse Subtract with Carry
+  TST = 8,   // Test
+  TEQ = 9,   // Test Equivalence
   CMP = 10,  // Compare
   CMN = 11,  // Compare Negated
   ORR = 12,  // Logical (inclusive) OR
@@ -146,7 +143,7 @@
   MVN = 15,  // Move Not
   kMaxOperand = 16
 };
-
+std::ostream& operator<<(std::ostream& os, const Opcode& rhs);
 
 // Shifter types for Data-processing operands as defined in section A5.1.2.
 enum Shift {
@@ -158,11 +155,11 @@
   RRX = 4,  // Rotate right with extend.
   kMaxShift
 };
-
+std::ostream& operator<<(std::ostream& os, const Shift& rhs);
 
 // Constants used for the decoding or encoding of the individual fields of
 // instructions. Based on the "Figure 3-1 ARM instruction set summary".
-enum InstructionFields {
+enum InstructionFields {  // private marker to avoid generate-operator-out.py from processing.
   kConditionShift = 28,
   kConditionBits = 4,
   kTypeShift = 25,
@@ -223,7 +220,7 @@
 // Example: Test whether the instruction at ptr does set the condition code
 // bits.
 //
-// bool InstructionSetsConditionCodes(byte* ptr) {
+// bool InstructionSetsConditionCodes(uint8_t* ptr) {
 //   Instr* instr = Instr::At(ptr);
 //   int type = instr->TypeField();
 //   return ((type == 0) || (type == 1)) && instr->HasS();
@@ -435,7 +432,7 @@
   // reference to an instruction is to convert a pointer. There is no way
   // to allocate or create instances of class Instr.
   // Use the At(pc) function to create references to Instr.
-  static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
+  static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); }
   Instr* Next() { return this + kInstrSize; }
 
  private:
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index c82b4f0..21014c8 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -42,17 +42,17 @@
 }
 
 size_t Arm64Assembler::CodeSize() const {
-  return ___ SizeOfCodeGenerated();
+  return vixl_masm_->BufferCapacity() - vixl_masm_->RemainingBufferSpace();
 }
 
 void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
   // Copy the instructions from the buffer.
-  MemoryRegion from(reinterpret_cast<void*>(vixl_buf_), CodeSize());
+  MemoryRegion from(vixl_masm_->GetStartAddress<void*>(), CodeSize());
   region.CopyFrom(0, from);
 }
 
 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_w(dst.AsOverlappingWRegister()), 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_x(src.AsOverlappingXRegister()));
         }
       }
     } 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";
   }
@@ -474,11 +474,9 @@
   UNIMPLEMENTED(FATAL) << "Unimplemented Copy() variant";
 }
 
-void Arm64Assembler::MemoryBarrier(ManagedRegister m_scratch) {
+void Arm64Assembler::MemoryBarrier(ManagedRegister m_scratch ATTRIBUTE_UNUSED) {
   // TODO: Should we check that m_scratch is IP? - see arm.
-#if ANDROID_SMP != 0
   ___ Dmb(vixl::InnerShareable, vixl::BarrierAll);
-#endif
 }
 
 void Arm64Assembler::SignExtend(ManagedRegister mreg, size_t size) {
@@ -486,9 +484,9 @@
   CHECK(size == 1 || size == 2) << size;
   CHECK(reg.IsWRegister()) << reg;
   if (size == 1) {
-    ___ sxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+    ___ Sxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
   } else {
-    ___ sxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+    ___ Sxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
   }
 }
 
@@ -497,9 +495,9 @@
   CHECK(size == 1 || size == 2) << size;
   CHECK(reg.IsWRegister()) << reg;
   if (size == 1) {
-    ___ uxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+    ___ Uxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
   } else {
-    ___ uxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
+    ___ Uxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister()));
   }
 }
 
@@ -514,31 +512,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 +548,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 +609,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 +625,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 +644,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 +698,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 bf89d24..a69be25 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -27,8 +27,13 @@
 #include "utils/assembler.h"
 #include "offsets.h"
 #include "utils.h"
+
+// TODO: make vixl clean wrt -Wshadow.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
 #include "a64/macro-assembler-a64.h"
 #include "a64/disasm-a64.h"
+#pragma GCC diagnostic pop
 
 namespace art {
 namespace arm64 {
@@ -59,12 +64,12 @@
 
 class Arm64Assembler FINAL : public Assembler {
  public:
-  Arm64Assembler() : vixl_buf_(new byte[kBufferSizeArm64]),
-  vixl_masm_(new vixl::MacroAssembler(vixl_buf_, kBufferSizeArm64)) {}
+  // We indicate the size of the initial code generation buffer to the VIXL
+  // assembler. From there we it will automatically manage the buffer.
+  Arm64Assembler() : vixl_masm_(new vixl::MacroAssembler(kArm64BaseBufferSize)) {}
 
   virtual ~Arm64Assembler() {
     delete vixl_masm_;
-    delete[] vixl_buf_;
   }
 
   // Emit slow paths queued during assembly.
@@ -173,7 +178,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 +188,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,30 +209,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 buffer.
-  byte* vixl_buf_;
-
-  // Vixl assembler.
-  vixl::MacroAssembler* 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/constants_arm64.h b/compiler/utils/arm64/constants_arm64.h
index 0cbbb1e..ffb54d3 100644
--- a/compiler/utils/arm64/constants_arm64.h
+++ b/compiler/utils/arm64/constants_arm64.h
@@ -31,8 +31,7 @@
 
 constexpr unsigned int kJniRefSpillRegsSize = 11;
 
-// Vixl buffer size.
-constexpr size_t kBufferSizeArm64 = 4096*2;
+constexpr size_t kArm64BaseBufferSize = 4096;
 
 }  // namespace arm64
 }  // namespace art
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/array_ref.h b/compiler/utils/array_ref.h
index e6b4a6a..b1b0ee5 100644
--- a/compiler/utils/array_ref.h
+++ b/compiler/utils/array_ref.h
@@ -68,18 +68,13 @@
 
   template <typename U, size_t size>
   constexpr ArrayRef(U (&array)[size],
-                     typename std::enable_if<std::is_same<T, const U>::value, tag>::type t = tag())
+                     typename std::enable_if<std::is_same<T, const U>::value, tag>::type
+                         t ATTRIBUTE_UNUSED = tag())
     : array_(array), size_(size) {
   }
 
-  constexpr ArrayRef(T* array, size_t size)
-      : array_(array), size_(size) {
-  }
-
-  template <typename U>
-  constexpr ArrayRef(U* array, size_t size,
-                     typename std::enable_if<std::is_same<T, const U>::value, tag>::type t = tag())
-      : array_(array), size_(size) {
+  constexpr ArrayRef(T* array_in, size_t size_in)
+      : array_(array_in), size_(size_in) {
   }
 
   template <typename Alloc>
@@ -89,7 +84,8 @@
 
   template <typename U, typename Alloc>
   ArrayRef(const std::vector<U, Alloc>& v,
-           typename std::enable_if<std::is_same<T, const U>::value, tag>::tag t = tag())
+           typename std::enable_if<std::is_same<T, const U>::value, tag>::type
+               t ATTRIBUTE_UNUSED = tag())
       : array_(v.data()), size_(v.size()) {
   }
 
diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc
index e3045e1..5340dd3 100644
--- a/compiler/utils/assembler.cc
+++ b/compiler/utils/assembler.cc
@@ -23,6 +23,7 @@
 #include "arm/assembler_thumb2.h"
 #include "arm64/assembler_arm64.h"
 #include "mips/assembler_mips.h"
+#include "mips64/assembler_mips64.h"
 #include "x86/assembler_x86.h"
 #include "x86_64/assembler_x86_64.h"
 #include "globals.h"
@@ -30,8 +31,8 @@
 
 namespace art {
 
-static byte* NewContents(size_t capacity) {
-  return new byte[capacity];
+static uint8_t* NewContents(size_t capacity) {
+  return new uint8_t[capacity];
 }
 
 
@@ -85,7 +86,7 @@
   size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
 
   // Allocate the new data area and copy contents of the old one to it.
-  byte* new_contents = NewContents(new_capacity);
+  uint8_t* new_contents = NewContents(new_capacity);
   memmove(reinterpret_cast<void*>(new_contents),
           reinterpret_cast<void*>(contents_),
           old_size);
@@ -115,6 +116,8 @@
       return new arm64::Arm64Assembler();
     case kMips:
       return new mips::MipsAssembler();
+    case kMips64:
+      return new mips64::Mips64Assembler();
     case kX86:
       return new x86::X86Assembler();
     case kX86_64:
@@ -125,77 +128,91 @@
   }
 }
 
-void Assembler::StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm,
-                                         ManagedRegister scratch) {
+void Assembler::StoreImmediateToThread32(ThreadOffset<4> dest ATTRIBUTE_UNUSED,
+                                         uint32_t imm ATTRIBUTE_UNUSED,
+                                         ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::StoreImmediateToThread64(ThreadOffset<8> dest, uint32_t imm,
-                                         ManagedRegister scratch) {
+void Assembler::StoreImmediateToThread64(ThreadOffset<8> dest ATTRIBUTE_UNUSED,
+                                         uint32_t imm ATTRIBUTE_UNUSED,
+                                         ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::StoreStackOffsetToThread32(ThreadOffset<4> thr_offs,
-                                           FrameOffset fr_offs,
-                                           ManagedRegister scratch) {
+void Assembler::StoreStackOffsetToThread32(ThreadOffset<4> thr_offs ATTRIBUTE_UNUSED,
+                                           FrameOffset fr_offs ATTRIBUTE_UNUSED,
+                                           ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::StoreStackOffsetToThread64(ThreadOffset<8> thr_offs,
-                                           FrameOffset fr_offs,
-                                           ManagedRegister scratch) {
+void Assembler::StoreStackOffsetToThread64(ThreadOffset<8> thr_offs ATTRIBUTE_UNUSED,
+                                           FrameOffset fr_offs ATTRIBUTE_UNUSED,
+                                           ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::StoreStackPointerToThread32(ThreadOffset<4> thr_offs) {
+void Assembler::StoreStackPointerToThread32(ThreadOffset<4> thr_offs ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::StoreStackPointerToThread64(ThreadOffset<8> thr_offs) {
+void Assembler::StoreStackPointerToThread64(ThreadOffset<8> thr_offs ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) {
+void Assembler::LoadFromThread32(ManagedRegister dest ATTRIBUTE_UNUSED,
+                                 ThreadOffset<4> src ATTRIBUTE_UNUSED,
+                                 size_t size ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::LoadFromThread64(ManagedRegister dest, ThreadOffset<8> src, size_t size) {
+void Assembler::LoadFromThread64(ManagedRegister dest ATTRIBUTE_UNUSED,
+                                 ThreadOffset<8> src ATTRIBUTE_UNUSED,
+                                 size_t size ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) {
+void Assembler::LoadRawPtrFromThread32(ManagedRegister dest ATTRIBUTE_UNUSED,
+                                       ThreadOffset<4> offs ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset<8> offs) {
+void Assembler::LoadRawPtrFromThread64(ManagedRegister dest ATTRIBUTE_UNUSED,
+                                       ThreadOffset<8> offs ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
-                                       ManagedRegister scratch) {
+void Assembler::CopyRawPtrFromThread32(FrameOffset fr_offs ATTRIBUTE_UNUSED,
+                                       ThreadOffset<4> thr_offs ATTRIBUTE_UNUSED,
+                                       ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<8> thr_offs,
-                                       ManagedRegister scratch) {
+void Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs ATTRIBUTE_UNUSED,
+                                       ThreadOffset<8> thr_offs ATTRIBUTE_UNUSED,
+                                       ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
-                                     ManagedRegister scratch) {
+void Assembler::CopyRawPtrToThread32(ThreadOffset<4> thr_offs ATTRIBUTE_UNUSED,
+                                     FrameOffset fr_offs ATTRIBUTE_UNUSED,
+                                     ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::CopyRawPtrToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs,
-                                     ManagedRegister scratch) {
+void Assembler::CopyRawPtrToThread64(ThreadOffset<8> thr_offs ATTRIBUTE_UNUSED,
+                                     FrameOffset fr_offs ATTRIBUTE_UNUSED,
+                                     ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) {
+void Assembler::CallFromThread32(ThreadOffset<4> offset ATTRIBUTE_UNUSED,
+                                 ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
-void Assembler::CallFromThread64(ThreadOffset<8> offset, ManagedRegister scratch) {
+void Assembler::CallFromThread64(ThreadOffset<8> offset ATTRIBUTE_UNUSED,
+                                 ManagedRegister scratch ATTRIBUTE_UNUSED) {
   UNIMPLEMENTED(FATAL);
 }
 
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 4addfa0..923ecdb 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -19,16 +19,16 @@
 
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "arm/constants_arm.h"
-#include "mips/constants_mips.h"
-#include "x86/constants_x86.h"
-#include "x86_64/constants_x86_64.h"
-#include "instruction_set.h"
 #include "managed_register.h"
 #include "memory_region.h"
+#include "mips/constants_mips.h"
 #include "offsets.h"
+#include "x86/constants_x86.h"
+#include "x86_64/constants_x86_64.h"
 
 namespace art {
 
@@ -47,6 +47,9 @@
 namespace mips {
   class MipsAssembler;
 }
+namespace mips64 {
+  class Mips64Assembler;
+}
 namespace x86 {
   class X86Assembler;
 }
@@ -56,19 +59,19 @@
 
 class ExternalLabel {
  public:
-  ExternalLabel(const char* name, uword address)
-      : name_(name), address_(address) {
-    DCHECK(name != nullptr);
+  ExternalLabel(const char* name_in, uintptr_t address_in)
+      : name_(name_in), address_(address_in) {
+    DCHECK(name_in != nullptr);
   }
 
   const char* name() const { return name_; }
-  uword address() const {
+  uintptr_t address() const {
     return address_;
   }
 
  private:
   const char* name_;
-  const uword address_;
+  const uintptr_t address_;
 };
 
 class Label {
@@ -84,12 +87,12 @@
   // for unused labels.
   int Position() const {
     CHECK(!IsUnused());
-    return IsBound() ? -position_ - kPointerSize : position_ - kPointerSize;
+    return IsBound() ? -position_ - sizeof(void*) : position_ - sizeof(void*);
   }
 
   int LinkPosition() const {
     CHECK(IsLinked());
-    return position_ - kPointerSize;
+    return position_ - sizeof(void*);
   }
 
   bool IsBound() const { return position_ < 0; }
@@ -105,20 +108,22 @@
 
   void BindTo(int position) {
     CHECK(!IsBound());
-    position_ = -position - kPointerSize;
+    position_ = -position - sizeof(void*);
     CHECK(IsBound());
   }
 
   void LinkTo(int position) {
     CHECK(!IsBound());
-    position_ = position + kPointerSize;
+    position_ = position + sizeof(void*);
     CHECK(IsLinked());
   }
 
   friend class arm::ArmAssembler;
   friend class arm::Arm32Assembler;
   friend class arm::Thumb2Assembler;
+  friend class arm64::Arm64Assembler;
   friend class mips::MipsAssembler;
+  friend class mips64::Mips64Assembler;
   friend class x86::X86Assembler;
   friend class x86_64::X86_64Assembler;
 
@@ -139,10 +144,10 @@
   int position_;
 
   AssemblerFixup* previous() const { return previous_; }
-  void set_previous(AssemblerFixup* previous) { previous_ = previous; }
+  void set_previous(AssemblerFixup* previous_in) { previous_ = previous_in; }
 
   int position() const { return position_; }
-  void set_position(int position) { position_ = position; }
+  void set_position(int position_in) { position_ = position_in; }
 
   friend class AssemblerBuffer;
 };
@@ -236,7 +241,7 @@
     return cursor_ - contents_;
   }
 
-  byte* contents() const { return contents_; }
+  uint8_t* contents() const { return contents_; }
 
   // Copy the assembled instructions into the specified memory block
   // and apply all fixups.
@@ -316,9 +321,9 @@
   // for a single, fast space check per instruction.
   static const int kMinimumGap = 32;
 
-  byte* contents_;
-  byte* cursor_;
-  byte* limit_;
+  uint8_t* contents_;
+  uint8_t* cursor_;
+  uint8_t* limit_;
   AssemblerFixup* fixup_;
 #ifndef NDEBUG
   bool fixups_processed_;
@@ -327,8 +332,8 @@
   // Head of linked list of slow paths
   SlowPath* slow_path_;
 
-  byte* cursor() const { return cursor_; }
-  byte* limit() const { return limit_; }
+  uint8_t* cursor() const { return cursor_; }
+  uint8_t* limit() const { return limit_; }
   size_t Capacity() const {
     CHECK_GE(limit_, contents_);
     return (limit_ - contents_) + kMinimumGap;
@@ -340,7 +345,7 @@
 
   // Compute the limit based on the data area and the capacity. See
   // description of kMinimumGap for the reasoning behind the value.
-  static byte* ComputeLimit(byte* data, size_t capacity) {
+  static uint8_t* ComputeLimit(uint8_t* data, size_t capacity) {
     return data + capacity - kMinimumGap;
   }
 
@@ -365,7 +370,7 @@
   }
 
   // TODO: Implement with disassembler.
-  virtual void Comment(const char* format, ...) { }
+  virtual void Comment(const char* format, ...) { UNUSED(format); }
 
   // Emit code that will create an activation on the stack
   virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg,
@@ -501,6 +506,8 @@
 
   virtual void InitializeFrameDescriptionEntry() {}
   virtual void FinalizeFrameDescriptionEntry() {}
+  // Give a vector containing FDE data, or null if not used. Note: the assembler must take care
+  // of handling the lifecycle.
   virtual std::vector<uint8_t>* GetFrameDescriptionEntry() { return nullptr; }
 
   virtual ~Assembler() {}
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 3742913..6f8b301 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -24,27 +24,40 @@
 #include <cstdio>
 #include <cstdlib>
 #include <fstream>
-#include <iostream>
 #include <iterator>
 #include <sys/stat.h>
 
 namespace art {
 
+// If you want to take a look at the differences between the ART assembler and GCC, set this flag
+// to true. The disassembled files will then remain in the tmp directory.
+static constexpr bool kKeepDisassembledFiles = false;
+
+// Helper for a constexpr string length.
+constexpr size_t ConstexprStrLen(char const* str, size_t count = 0) {
+  return ('\0' == str[0]) ? count : ConstexprStrLen(str+1, count+1);
+}
+
 // Use a glocal static variable to keep the same name for all test data. Else we'll just spam the
 // temp directory.
 static std::string tmpnam_;
 
-template<typename Ass, typename Reg, typename Imm>
+enum class RegisterView {  // private
+  kUsePrimaryName,
+  kUseSecondaryName
+};
+
+template<typename Ass, typename Reg, typename FPReg, typename Imm>
 class AssemblerTest : public testing::Test {
  public:
   Ass* GetAssembler() {
     return assembler_.get();
   }
 
-  typedef std::string (*TestFn)(Ass* assembler);
+  typedef std::string (*TestFn)(AssemblerTest* assembler_test, Ass* assembler);
 
   void DriverFn(TestFn f, std::string test_name) {
-    Driver(f(assembler_.get()), test_name);
+    Driver(f(this, assembler_.get()), test_name);
   }
 
   // This driver assumes the assembler has already been called.
@@ -53,118 +66,117 @@
   }
 
   std::string RepeatR(void (Ass::*f)(Reg), std::string fmt) {
-    const std::vector<Reg*> registers = GetRegisters();
-    std::string str;
-    for (auto reg : registers) {
-      (assembler_.get()->*f)(*reg);
-      std::string base = fmt;
+    return RepeatTemplatedRegister<Reg>(f,
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        fmt);
+  }
 
-      size_t reg_index = base.find("{reg}");
-      if (reg_index != std::string::npos) {
-        std::ostringstream sreg;
-        sreg << *reg;
-        std::string reg_string = sreg.str();
-        base.replace(reg_index, 5, reg_string);
-      }
-
-      if (str.size() > 0) {
-        str += "\n";
-      }
-      str += base;
-    }
-    // Add a newline at the end.
-    str += "\n";
-    return str;
+  std::string Repeatr(void (Ass::*f)(Reg), std::string fmt) {
+    return RepeatTemplatedRegister<Reg>(f,
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        fmt);
   }
 
   std::string RepeatRR(void (Ass::*f)(Reg, Reg), std::string fmt) {
-    const std::vector<Reg*> registers = GetRegisters();
-    std::string str;
-    for (auto reg1 : registers) {
-      for (auto reg2 : registers) {
-        (assembler_.get()->*f)(*reg1, *reg2);
-        std::string base = fmt;
+    return RepeatTemplatedRegisters<Reg, Reg>(f,
+        GetRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        fmt);
+  }
 
-        size_t reg1_index = base.find("{reg1}");
-        if (reg1_index != std::string::npos) {
-          std::ostringstream sreg;
-          sreg << *reg1;
-          std::string reg_string = sreg.str();
-          base.replace(reg1_index, 6, reg_string);
-        }
+  std::string Repeatrr(void (Ass::*f)(Reg, Reg), std::string fmt) {
+    return RepeatTemplatedRegisters<Reg, Reg>(f,
+        GetRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        fmt);
+  }
 
-        size_t reg2_index = base.find("{reg2}");
-        if (reg2_index != std::string::npos) {
-          std::ostringstream sreg;
-          sreg << *reg2;
-          std::string reg_string = sreg.str();
-          base.replace(reg2_index, 6, reg_string);
-        }
-
-        if (str.size() > 0) {
-          str += "\n";
-        }
-        str += base;
-      }
-    }
-    // Add a newline at the end.
-    str += "\n";
-    return str;
+  std::string RepeatRr(void (Ass::*f)(Reg, Reg), std::string fmt) {
+    return RepeatTemplatedRegisters<Reg, Reg>(f,
+        GetRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        fmt);
   }
 
   std::string RepeatRI(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
-    const std::vector<Reg*> registers = GetRegisters();
-    std::string str;
-    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;
-        std::string base = fmt;
-
-        size_t reg_index = base.find("{reg}");
-        if (reg_index != std::string::npos) {
-          std::ostringstream sreg;
-          sreg << *reg;
-          std::string reg_string = sreg.str();
-          base.replace(reg_index, 5, reg_string);
-        }
-
-        size_t imm_index = base.find("{imm}");
-        if (imm_index != std::string::npos) {
-          std::ostringstream sreg;
-          sreg << imm;
-          std::string imm_string = sreg.str();
-          base.replace(imm_index, 5, imm_string);
-        }
-
-        if (str.size() > 0) {
-          str += "\n";
-        }
-        str += base;
-      }
-    }
-    // Add a newline at the end.
-    str += "\n";
-    return str;
+    return RepeatRegisterImm<RegisterView::kUsePrimaryName>(f, imm_bytes, fmt);
   }
 
-  std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt) {
+  std::string Repeatri(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes, std::string fmt) {
+    return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
+  }
+
+  std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
+    return RepeatTemplatedRegisters<FPReg, FPReg>(f,
+                                                  GetFPRegisters(),
+                                                  GetFPRegisters(),
+                                                  &AssemblerTest::GetFPRegName,
+                                                  &AssemblerTest::GetFPRegName,
+                                                  fmt);
+  }
+
+  std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
+    return RepeatTemplatedRegisters<FPReg, Reg>(f,
+        GetFPRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetFPRegName,
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        fmt);
+  }
+
+  std::string RepeatFr(void (Ass::*f)(FPReg, Reg), std::string fmt) {
+    return RepeatTemplatedRegisters<FPReg, Reg>(f,
+        GetFPRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetFPRegName,
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        fmt);
+  }
+
+  std::string RepeatRF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
+    return RepeatTemplatedRegisters<Reg, FPReg>(f,
+        GetRegisters(),
+        GetFPRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetFPRegName,
+        fmt);
+  }
+
+  std::string RepeatrF(void (Ass::*f)(Reg, FPReg), std::string fmt) {
+    return RepeatTemplatedRegisters<Reg, FPReg>(f,
+        GetRegisters(),
+        GetFPRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUseSecondaryName>,
+        &AssemblerTest::GetFPRegName,
+        fmt);
+  }
+
+  std::string RepeatI(void (Ass::*f)(const Imm&), size_t imm_bytes, std::string fmt,
+                      bool as_uint = false) {
     std::string str;
-    std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
+    std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
+
+    WarnOnCombinations(imms.size());
+
     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}");
+      size_t imm_index = base.find(IMM_TOKEN);
       if (imm_index != std::string::npos) {
         std::ostringstream sreg;
         sreg << imm;
         std::string imm_string = sreg.str();
-        base.replace(imm_index, 5, imm_string);
+        base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
       }
 
       if (str.size() > 0) {
@@ -179,12 +191,12 @@
 
   // This is intended to be run as a test.
   bool CheckTools() {
-    if (!FileExists(GetAssemblerCommand())) {
+    if (!FileExists(FindTool(GetAssemblerCmdName()))) {
       return false;
     }
     LOG(INFO) << "Chosen assembler command: " << GetAssemblerCommand();
 
-    if (!FileExists(GetObjdumpCommand())) {
+    if (!FileExists(FindTool(GetObjdumpCmdName()))) {
       return false;
     }
     LOG(INFO) << "Chosen objdump command: " << GetObjdumpCommand();
@@ -192,7 +204,7 @@
     // Disassembly is optional.
     std::string disassembler = GetDisassembleCommand();
     if (disassembler.length() != 0) {
-      if (!FileExists(disassembler)) {
+      if (!FileExists(FindTool(GetDisassembleCmdName()))) {
         return false;
       }
       LOG(INFO) << "Chosen disassemble command: " << GetDisassembleCommand();
@@ -203,7 +215,28 @@
     return true;
   }
 
+  // The following functions are public so that TestFn can use them...
+
+  virtual std::vector<Reg*> GetRegisters() = 0;
+
+  virtual std::vector<FPReg*> GetFPRegisters() {
+    UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
+    UNREACHABLE();
+  }
+
+  // Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
+  virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
+    UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
+    UNREACHABLE();
+  }
+
+  std::string GetRegisterName(const Reg& reg) {
+    return GetRegName<RegisterView::kUsePrimaryName>(reg);
+  }
+
  protected:
+  explicit AssemblerTest() {}
+
   void SetUp() OVERRIDE {
     assembler_.reset(new Ass());
 
@@ -222,8 +255,6 @@
   // Override this to set up any architecture-specific things, e.g., register vectors.
   virtual void SetUpHelpers() {}
 
-  virtual std::vector<Reg*> GetRegisters() = 0;
-
   // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
   virtual std::string GetArchitectureString() = 0;
 
@@ -251,7 +282,7 @@
 
     resolved_assembler_cmd_ = line + GetAssemblerParameters();
 
-    return line;
+    return resolved_assembler_cmd_;
   }
 
   // Get the name of the objdump, e.g., "objdump" by default.
@@ -278,7 +309,7 @@
 
     resolved_objdump_cmd_ = line + GetObjdumpParameters();
 
-    return line;
+    return resolved_objdump_cmd_;
   }
 
   // Get the name of the objdump, e.g., "objdump" by default.
@@ -304,27 +335,45 @@
 
     resolved_disassemble_cmd_ = line + GetDisassembleParameters();
 
-    return line;
+    return resolved_disassemble_cmd_;
   }
 
   // Create a couple of immediate values up to the number of bytes given.
-  virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes) {
+  virtual std::vector<int64_t> CreateImmediateValues(size_t imm_bytes, bool as_uint = false) {
     std::vector<int64_t> res;
     res.push_back(0);
-    res.push_back(-1);
+    if (!as_uint) {
+      res.push_back(-1);
+    } else {
+      res.push_back(0xFF);
+    }
     res.push_back(0x12);
     if (imm_bytes >= 2) {
       res.push_back(0x1234);
-      res.push_back(-0x1234);
+      if (!as_uint) {
+        res.push_back(-0x1234);
+      } else {
+        res.push_back(0xFFFF);
+      }
       if (imm_bytes >= 4) {
         res.push_back(0x12345678);
-        res.push_back(-0x12345678);
+        if (!as_uint) {
+          res.push_back(-0x12345678);
+        } else {
+          res.push_back(0xFFFFFFFF);
+        }
         if (imm_bytes >= 6) {
           res.push_back(0x123456789ABC);
-          res.push_back(-0x123456789ABC);
+          if (!as_uint) {
+            res.push_back(-0x123456789ABC);
+          }
           if (imm_bytes >= 8) {
             res.push_back(0x123456789ABCDEF0);
-            res.push_back(-0x123456789ABCDEF0);
+            if (!as_uint) {
+              res.push_back(-0x123456789ABCDEF0);
+            } else {
+              res.push_back(0xFFFFFFFFFFFFFFFF);
+            }
           }
         }
       }
@@ -333,9 +382,150 @@
   }
 
   // Create an immediate from the specific value.
-  virtual Imm* CreateImmediate(int64_t imm_value) = 0;
+  virtual Imm CreateImmediate(int64_t imm_value) = 0;
+
+  template <typename RegType>
+  std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
+                                      const std::vector<RegType*> registers,
+                                      std::string (AssemblerTest::*GetName)(const RegType&),
+                                      std::string fmt) {
+    std::string str;
+    for (auto reg : registers) {
+      (assembler_.get()->*f)(*reg);
+      std::string base = fmt;
+
+      std::string reg_string = (this->*GetName)(*reg);
+      size_t reg_index;
+      if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
+        base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
+      }
+
+      if (str.size() > 0) {
+        str += "\n";
+      }
+      str += base;
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
+  template <typename Reg1, typename Reg2>
+  std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2),
+                                       const std::vector<Reg1*> reg1_registers,
+                                       const std::vector<Reg2*> reg2_registers,
+                                       std::string (AssemblerTest::*GetName1)(const Reg1&),
+                                       std::string (AssemblerTest::*GetName2)(const Reg2&),
+                                       std::string fmt) {
+    WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
+
+    std::string str;
+    for (auto reg1 : reg1_registers) {
+      for (auto reg2 : reg2_registers) {
+        (assembler_.get()->*f)(*reg1, *reg2);
+        std::string base = fmt;
+
+        std::string reg1_string = (this->*GetName1)(*reg1);
+        size_t reg1_index;
+        while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
+          base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
+        }
+
+        std::string reg2_string = (this->*GetName2)(*reg2);
+        size_t reg2_index;
+        while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
+          base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
+        }
+
+        if (str.size() > 0) {
+          str += "\n";
+        }
+        str += base;
+      }
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
+  template <RegisterView kRegView>
+  std::string GetRegName(const Reg& reg) {
+    std::ostringstream sreg;
+    switch (kRegView) {
+      case RegisterView::kUsePrimaryName:
+        sreg << reg;
+        break;
+
+      case RegisterView::kUseSecondaryName:
+        sreg << GetSecondaryRegisterName(reg);
+        break;
+    }
+    return sreg.str();
+  }
+
+  std::string GetFPRegName(const FPReg& reg) {
+    std::ostringstream sreg;
+    sreg << reg;
+    return sreg.str();
+  }
+
+  // If the assembly file needs a header, return it in a sub-class.
+  virtual const char* GetAssemblyHeader() {
+    return nullptr;
+  }
+
+  void WarnOnCombinations(size_t count) {
+    if (count > kWarnManyCombinationsThreshold) {
+      GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
+    }
+  }
+
+  static constexpr const char* REG_TOKEN = "{reg}";
+  static constexpr const char* REG1_TOKEN = "{reg1}";
+  static constexpr const char* REG2_TOKEN = "{reg2}";
+  static constexpr const char* IMM_TOKEN = "{imm}";
 
  private:
+  template <RegisterView kRegView>
+  std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
+                                  std::string fmt) {
+    const std::vector<Reg*> registers = GetRegisters();
+    std::string str;
+    std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
+
+    WarnOnCombinations(registers.size() * imms.size());
+
+    for (auto reg : registers) {
+      for (int64_t imm : imms) {
+        Imm new_imm = CreateImmediate(imm);
+        (assembler_.get()->*f)(*reg, new_imm);
+        std::string base = fmt;
+
+        std::string reg_string = GetRegName<kRegView>(*reg);
+        size_t reg_index;
+        while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
+          base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
+        }
+
+        size_t imm_index = base.find(IMM_TOKEN);
+        if (imm_index != std::string::npos) {
+          std::ostringstream sreg;
+          sreg << imm;
+          std::string imm_string = sreg.str();
+          base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
+        }
+
+        if (str.size() > 0) {
+          str += "\n";
+        }
+        str += base;
+      }
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
   // Driver() assembles and compares the results. If the results are not equal and we have a
   // disassembler, disassemble both and check whether they have the same mnemonics (in which case
   // we just warn).
@@ -373,7 +563,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.";
       }
     }
   }
@@ -389,7 +579,7 @@
 
   // Compile the assembly file from_file to a binary file to_file. Returns true on success.
   bool Assemble(const char* from_file, const char* to_file, std::string* error_msg) {
-    bool have_assembler = FileExists(GetAssemblerCommand());
+    bool have_assembler = FileExists(FindTool(GetAssemblerCmdName()));
     EXPECT_TRUE(have_assembler) << "Cannot find assembler:" << GetAssemblerCommand();
     if (!have_assembler) {
       return false;
@@ -397,18 +587,34 @@
 
     std::vector<std::string> args;
 
+    // Encaspulate the whole command line in a single string passed to
+    // the shell, so that GetAssemblerCommand() may contain arguments
+    // in addition to the program name.
     args.push_back(GetAssemblerCommand());
     args.push_back("-o");
     args.push_back(to_file);
     args.push_back(from_file);
+    std::string cmd = Join(args, ' ');
 
-    return Exec(args, error_msg);
+    args.clear();
+    args.push_back("/bin/sh");
+    args.push_back("-c");
+    args.push_back(cmd);
+
+    bool success = Exec(args, error_msg);
+    if (!success) {
+      LOG(INFO) << "Assembler command line:";
+      for (std::string arg : args) {
+        LOG(INFO) << arg;
+      }
+    }
+    return success;
   }
 
   // Runs objdump -h on the binary file and extracts the first line with .text.
   // Returns "" on failure.
   std::string Objdump(std::string file) {
-    bool have_objdump = FileExists(GetObjdumpCommand());
+    bool have_objdump = FileExists(FindTool(GetObjdumpCmdName()));
     EXPECT_TRUE(have_objdump) << "Cannot find objdump: " << GetObjdumpCommand();
     if (!have_objdump) {
       return "";
@@ -417,6 +623,9 @@
     std::string error_msg;
     std::vector<std::string> args;
 
+    // Encaspulate the whole command line in a single string passed to
+    // the shell, so that GetObjdumpCommand() may contain arguments
+    // in addition to the program name.
     args.push_back(GetObjdumpCommand());
     args.push_back(file);
     args.push_back(">");
@@ -480,7 +689,7 @@
 
     bool result = CompareFiles(data_name + ".dis", as_name + ".dis");
 
-    if (result) {
+    if (!kKeepDisassembledFiles) {
       std::remove(data_name.c_str());
       std::remove(as_name.c_str());
       std::remove((data_name + ".dis").c_str());
@@ -493,6 +702,9 @@
   bool DisassembleBinary(std::string file, std::string* error_msg) {
     std::vector<std::string> args;
 
+    // Encaspulate the whole command line in a single string passed to
+    // the shell, so that GetDisassembleCommand() may contain arguments
+    // in addition to the program name.
     args.push_back(GetDisassembleCommand());
     args.push_back(file);
     args.push_back("| sed -n \'/<.data>/,$p\' | sed -e \'s/.*://\'");
@@ -541,6 +753,10 @@
     // TODO: Lots of error checking.
 
     std::ofstream s_out(res->base_name + ".S");
+    const char* header = GetAssemblyHeader();
+    if (header != nullptr) {
+      s_out << header;
+    }
     s_out << assembly_code;
     s_out.close();
 
@@ -689,6 +905,9 @@
     return tmpnam_;
   }
 
+  static constexpr size_t kWarnManyCombinationsThreshold = 500;
+  static constexpr size_t OBJDUMP_SECTION_LINE_MIN_TOKENS = 6;
+
   std::unique_ptr<Ass> assembler_;
 
   std::string resolved_assembler_cmd_;
@@ -697,7 +916,7 @@
 
   std::string android_data_;
 
-  static constexpr size_t OBJDUMP_SECTION_LINE_MIN_TOKENS = 6;
+  DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
 };
 
 }  // namespace art
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 3f2641c..3d03234 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -102,11 +102,11 @@
   "   4:	11a3      	asrs	r3, r4, #6\n",
   "   6:	ea4f 13f4 	mov.w	r3, r4, ror #7\n",
   "   a:	41e3      	rors	r3, r4\n",
-  "   c:	0128      	lsls	r0, r5, #4\n",
-  "   e:	0968      	lsrs	r0, r5, #5\n",
-  "  10:	11a8      	asrs	r0, r5, #6\n",
-  "  12:	ea4f 18f4 	mov.w	r8, r4, ror #7\n",
-  "  16:	ea4f 0834 	mov.w	r8, r4, rrx\n",
+  "   c:	ea4f 1804 	mov.w	r8, r4, lsl #4\n",
+  "  10:	ea4f 1854 	mov.w	r8, r4, lsr #5\n",
+  "  14:	ea4f 18a4 	mov.w	r8, r4, asr #6\n",
+  "  18:	ea4f 18f4 	mov.w	r8, r4, ror #7\n",
+  "  1c:	ea4f 0834 	mov.w	r8, r4, rrx\n",
   nullptr
 };
 const char* BasicLoadResults[] = {
@@ -340,15 +340,15 @@
   nullptr
 };
 const char* SpecialAddSubResults[] = {
-  "   0:	f20d 0250 	addw	r2, sp, #80	; 0x50\n",
-  "   4:	f20d 0d50 	addw	sp, sp, #80	; 0x50\n",
-  "   8:	f20d 0850 	addw	r8, sp, #80	; 0x50\n",
-  "   c:	f60d 7200 	addw	r2, sp, #3840	; 0xf00\n",
-  "  10:	f60d 7d00 	addw	sp, sp, #3840	; 0xf00\n",
-  "  14:	f2ad 0d50 	subw	sp, sp, #80	; 0x50\n",
-  "  18:	f2ad 0050 	subw	r0, sp, #80	; 0x50\n",
-  "  1c:	f2ad 0850 	subw	r8, sp, #80	; 0x50\n",
-  "  20:	f6ad 7d00 	subw	sp, sp, #3840	; 0xf00\n",
+  "   0:	aa14      	add	r2, sp, #80	; 0x50\n",
+  "   2:	b014      	add	sp, #80		; 0x50\n",
+  "   4:	f20d 0850 	addw	r8, sp, #80	; 0x50\n",
+  "   8:	f60d 7200 	addw	r2, sp, #3840	; 0xf00\n",
+  "   c:	f60d 7d00 	addw	sp, sp, #3840	; 0xf00\n",
+  "  10:	b094      	sub	sp, #80		; 0x50\n",
+  "  12:	f2ad 0050 	subw	r0, sp, #80	; 0x50\n",
+  "  16:	f2ad 0850 	subw	r8, sp, #80	; 0x50\n",
+  "  1a:	f6ad 7d00 	subw	sp, sp, #3840	; 0xf00\n",
   nullptr
 };
 const char* StoreToOffsetResults[] = {
diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h
index 4c52174..b062a2a 100644
--- a/compiler/utils/dedupe_set.h
+++ b/compiler/utils/dedupe_set.h
@@ -17,50 +17,89 @@
 #ifndef ART_COMPILER_UTILS_DEDUPE_SET_H_
 #define ART_COMPILER_UTILS_DEDUPE_SET_H_
 
+#include <algorithm>
+#include <inttypes.h>
+#include <memory>
 #include <set>
 #include <string>
 
 #include "base/mutex.h"
 #include "base/stl_util.h"
 #include "base/stringprintf.h"
+#include "utils/swap_space.h"
 
 namespace art {
 
 // A set of Keys that support a HashFunc returning HashType. Used to find duplicates of Key in the
 // Add method. The data-structure is thread-safe through the use of internal locks, it also
 // supports the lock being sharded.
-template <typename Key, typename HashType, typename HashFunc, HashType kShard = 1>
+template <typename InKey, typename StoreKey, typename HashType, typename HashFunc,
+          HashType kShard = 1>
 class DedupeSet {
-  typedef std::pair<HashType, Key*> HashedKey;
+  typedef std::pair<HashType, const InKey*> HashedInKey;
+  struct HashedKey {
+    StoreKey* store_ptr;
+    union {
+      HashType store_hash;        // Valid if store_ptr != nullptr.
+      const HashedInKey* in_key;  // Valid if store_ptr == nullptr.
+    };
+  };
 
   class Comparator {
    public:
     bool operator()(const HashedKey& a, const HashedKey& b) const {
-      if (a.first != b.first) {
-        return a.first < b.first;
+      HashType a_hash = (a.store_ptr != nullptr) ? a.store_hash : a.in_key->first;
+      HashType b_hash = (b.store_ptr != nullptr) ? b.store_hash : b.in_key->first;
+      if (a_hash != b_hash) {
+        return a_hash < b_hash;
+      }
+      if (a.store_ptr != nullptr && b.store_ptr != nullptr) {
+        return std::lexicographical_compare(a.store_ptr->begin(), a.store_ptr->end(),
+                                            b.store_ptr->begin(), b.store_ptr->end());
+      } else if (a.store_ptr != nullptr && b.store_ptr == nullptr) {
+        return std::lexicographical_compare(a.store_ptr->begin(), a.store_ptr->end(),
+                                            b.in_key->second->begin(), b.in_key->second->end());
+      } else if (a.store_ptr == nullptr && b.store_ptr != nullptr) {
+        return std::lexicographical_compare(a.in_key->second->begin(), a.in_key->second->end(),
+                                            b.store_ptr->begin(), b.store_ptr->end());
       } else {
-        return *a.second < *b.second;
+        return std::lexicographical_compare(a.in_key->second->begin(), a.in_key->second->end(),
+                                            b.in_key->second->begin(), b.in_key->second->end());
       }
     }
   };
 
  public:
-  Key* Add(Thread* self, const Key& key) {
+  StoreKey* Add(Thread* self, const InKey& key) {
+    uint64_t hash_start;
+    if (kIsDebugBuild) {
+      hash_start = NanoTime();
+    }
     HashType raw_hash = HashFunc()(key);
+    if (kIsDebugBuild) {
+      uint64_t hash_end = NanoTime();
+      hash_time_ += hash_end - hash_start;
+    }
     HashType shard_hash = raw_hash / kShard;
     HashType shard_bin = raw_hash % kShard;
-    HashedKey hashed_key(shard_hash, const_cast<Key*>(&key));
+    HashedInKey hashed_in_key(shard_hash, &key);
+    HashedKey hashed_key;
+    hashed_key.store_ptr = nullptr;
+    hashed_key.in_key = &hashed_in_key;
     MutexLock lock(self, *lock_[shard_bin]);
     auto it = keys_[shard_bin].find(hashed_key);
     if (it != keys_[shard_bin].end()) {
-      return it->second;
+      DCHECK(it->store_ptr != nullptr);
+      return it->store_ptr;
     }
-    hashed_key.second = new Key(key);
+    hashed_key.store_ptr = CreateStoreKey(key);
+    hashed_key.store_hash = shard_hash;
     keys_[shard_bin].insert(hashed_key);
-    return hashed_key.second;
+    return hashed_key.store_ptr;
   }
 
-  explicit DedupeSet(const char* set_name) {
+  explicit DedupeSet(const char* set_name, SwapAllocator<void>& alloc)
+      : allocator_(alloc), hash_time_(0) {
     for (HashType i = 0; i < kShard; ++i) {
       std::ostringstream oss;
       oss << set_name << " lock " << i;
@@ -70,15 +109,59 @@
   }
 
   ~DedupeSet() {
-    for (HashType i = 0; i < kShard; ++i) {
-      STLDeleteValues(&keys_[i]);
+    // Have to manually free all pointers.
+    for (auto& shard : keys_) {
+      for (const auto& hashed_key : shard) {
+        DCHECK(hashed_key.store_ptr != nullptr);
+        DeleteStoreKey(hashed_key.store_ptr);
+      }
     }
   }
 
+  std::string DumpStats() const {
+    size_t collision_sum = 0;
+    size_t collision_max = 0;
+    for (HashType shard = 0; shard < kShard; ++shard) {
+      HashType last_hash = 0;
+      size_t collision_cur_max = 0;
+      for (const HashedKey& key : keys_[shard]) {
+        DCHECK(key.store_ptr != nullptr);
+        if (key.store_hash == last_hash) {
+          collision_cur_max++;
+          if (collision_cur_max > 1) {
+            collision_sum++;
+            if (collision_cur_max > collision_max) {
+              collision_max = collision_cur_max;
+            }
+          }
+        } else {
+          collision_cur_max = 1;
+          last_hash = key.store_hash;
+        }
+      }
+    }
+    return StringPrintf("%zu collisions, %zu max bucket size, %" PRIu64 " ns hash time",
+                        collision_sum, collision_max, hash_time_);
+  }
+
  private:
+  StoreKey* CreateStoreKey(const InKey& key) {
+    StoreKey* ret = allocator_.allocate(1);
+    allocator_.construct(ret, key.begin(), key.end(), allocator_);
+    return ret;
+  }
+
+  void DeleteStoreKey(StoreKey* key) {
+    SwapAllocator<StoreKey> alloc(allocator_);
+    alloc.destroy(key);
+    alloc.deallocate(key, 1);
+  }
+
   std::string lock_name_[kShard];
   std::unique_ptr<Mutex> lock_[kShard];
   std::set<HashedKey, Comparator> keys_[kShard];
+  SwapAllocator<StoreKey> allocator_;
+  uint64_t hash_time_;
 
   DISALLOW_COPY_AND_ASSIGN(DedupeSet);
 };
diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc
index 8abe6de..637964e 100644
--- a/compiler/utils/dedupe_set_test.cc
+++ b/compiler/utils/dedupe_set_test.cc
@@ -15,6 +15,10 @@
  */
 
 #include "dedupe_set.h"
+
+#include <algorithm>
+#include <cstdio>
+
 #include "gtest/gtest.h"
 #include "thread-inl.h"
 
@@ -35,19 +39,22 @@
 TEST(DedupeSetTest, Test) {
   Thread* self = Thread::Current();
   typedef std::vector<uint8_t> ByteArray;
-  DedupeSet<ByteArray, size_t, DedupeHashFunc> deduplicator("test");
-  ByteArray* array1;
+  SwapAllocator<void> swap(nullptr);
+  DedupeSet<ByteArray, SwapVector<uint8_t>, size_t, DedupeHashFunc> deduplicator("test", swap);
+  SwapVector<uint8_t>* array1;
   {
     ByteArray test1;
     test1.push_back(10);
     test1.push_back(20);
     test1.push_back(30);
     test1.push_back(45);
+
     array1 = deduplicator.Add(self, test1);
-    ASSERT_EQ(test1, *array1);
+    ASSERT_NE(array1, nullptr);
+    ASSERT_TRUE(std::equal(test1.begin(), test1.end(), array1->begin()));
   }
 
-  ByteArray* array2;
+  SwapVector<uint8_t>* array2;
   {
     ByteArray test1;
     test1.push_back(10);
@@ -56,10 +63,10 @@
     test1.push_back(45);
     array2 = deduplicator.Add(self, test1);
     ASSERT_EQ(array2, array1);
-    ASSERT_EQ(test1, *array2);
+    ASSERT_TRUE(std::equal(test1.begin(), test1.end(), array2->begin()));
   }
 
-  ByteArray* array3;
+  SwapVector<uint8_t>* array3;
   {
     ByteArray test1;
     test1.push_back(10);
@@ -67,8 +74,8 @@
     test1.push_back(30);
     test1.push_back(47);
     array3 = deduplicator.Add(self, test1);
-    ASSERT_NE(array3, &test1);
-    ASSERT_EQ(test1, *array3);
+    ASSERT_NE(array3, nullptr);
+    ASSERT_TRUE(std::equal(test1.begin(), test1.end(), array3->begin()));
   }
 }
 
diff --git a/compiler/utils/dex_instruction_utils.h b/compiler/utils/dex_instruction_utils.h
new file mode 100644
index 0000000..2c6e525
--- /dev/null
+++ b/compiler/utils/dex_instruction_utils.h
@@ -0,0 +1,196 @@
+/*
+ * 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_UTILS_DEX_INSTRUCTION_UTILS_H_
+#define ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_
+
+#include "dex_instruction.h"
+
+namespace art {
+
+// Dex invoke type corresponds to the ordering of INVOKE instructions;
+// this order is the same for range and non-range invokes.
+enum DexInvokeType : uint8_t {
+  kDexInvokeVirtual = 0,  // invoke-virtual, invoke-virtual-range
+  kDexInvokeSuper,        // invoke-super, invoke-super-range
+  kDexInvokeDirect,       // invoke-direct, invoke-direct-range
+  kDexInvokeStatic,       // invoke-static, invoke-static-range
+  kDexInvokeInterface,    // invoke-interface, invoke-interface-range
+  kDexInvokeTypeCount
+};
+
+// Dex instruction memory access types correspond to the ordering of GET/PUT instructions;
+// this order is the same for IGET, IPUT, SGET, SPUT, AGET and APUT.
+enum DexMemAccessType : uint8_t {
+  kDexMemAccessWord = 0,  // op         0; int or float, the actual type is not encoded.
+  kDexMemAccessWide,      // op_WIDE    1; long or double, the actual type is not encoded.
+  kDexMemAccessObject,    // op_OBJECT  2; the actual reference type is not encoded.
+  kDexMemAccessBoolean,   // op_BOOLEAN 3
+  kDexMemAccessByte,      // op_BYTE    4
+  kDexMemAccessChar,      // op_CHAR    5
+  kDexMemAccessShort,     // op_SHORT   6
+  kDexMemAccessTypeCount
+};
+
+std::ostream& operator<<(std::ostream& os, const DexMemAccessType& type);
+
+// NOTE: The following functions disregard quickened instructions.
+
+constexpr bool IsInstructionReturn(Instruction::Code opcode) {
+  return Instruction::RETURN_VOID <= opcode && opcode <= Instruction::RETURN_OBJECT;
+}
+
+constexpr bool IsInstructionInvoke(Instruction::Code opcode) {
+  return Instruction::INVOKE_VIRTUAL <= opcode && opcode <= Instruction::INVOKE_INTERFACE_RANGE &&
+      opcode != Instruction::RETURN_VOID_BARRIER;
+}
+
+constexpr bool IsInstructionInvokeStatic(Instruction::Code opcode) {
+  return opcode == Instruction::INVOKE_STATIC || opcode == Instruction::INVOKE_STATIC_RANGE;
+}
+
+constexpr bool IsInstructionGoto(Instruction::Code opcode) {
+  return Instruction::GOTO <= opcode && opcode <= Instruction::GOTO_32;
+}
+
+constexpr bool IsInstructionIfCc(Instruction::Code opcode) {
+  return Instruction::IF_EQ <= opcode && opcode <= Instruction::IF_LE;
+}
+
+constexpr bool IsInstructionIfCcZ(Instruction::Code opcode) {
+  return Instruction::IF_EQZ <= opcode && opcode <= Instruction::IF_LEZ;
+}
+
+constexpr bool IsInstructionIGet(Instruction::Code code) {
+  return Instruction::IGET <= code && code <= Instruction::IGET_SHORT;
+}
+
+constexpr bool IsInstructionIPut(Instruction::Code code) {
+  return Instruction::IPUT <= code && code <= Instruction::IPUT_SHORT;
+}
+
+constexpr bool IsInstructionSGet(Instruction::Code code) {
+  return Instruction::SGET <= code && code <= Instruction::SGET_SHORT;
+}
+
+constexpr bool IsInstructionSPut(Instruction::Code code) {
+  return Instruction::SPUT <= code && code <= Instruction::SPUT_SHORT;
+}
+
+constexpr bool IsInstructionAGet(Instruction::Code code) {
+  return Instruction::AGET <= code && code <= Instruction::AGET_SHORT;
+}
+
+constexpr bool IsInstructionAPut(Instruction::Code code) {
+  return Instruction::APUT <= code && code <= Instruction::APUT_SHORT;
+}
+
+constexpr bool IsInstructionIGetOrIPut(Instruction::Code code) {
+  return Instruction::IGET <= code && code <= Instruction::IPUT_SHORT;
+}
+
+constexpr bool IsInstructionSGetOrSPut(Instruction::Code code) {
+  return Instruction::SGET <= code && code <= Instruction::SPUT_SHORT;
+}
+
+constexpr bool IsInstructionAGetOrAPut(Instruction::Code code) {
+  return Instruction::AGET <= code && code <= Instruction::APUT_SHORT;
+}
+
+// TODO: Remove the #if guards below when we fully migrate to C++14.
+
+constexpr bool IsInvokeInstructionRange(Instruction::Code opcode) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionInvoke(opcode));
+#endif
+  return opcode >= Instruction::INVOKE_VIRTUAL_RANGE;
+}
+
+constexpr DexInvokeType InvokeInstructionType(Instruction::Code opcode) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionInvoke(opcode));
+#endif
+  return static_cast<DexInvokeType>(IsInvokeInstructionRange(opcode)
+                                    ? (opcode - Instruction::INVOKE_VIRTUAL_RANGE)
+                                    : (opcode - Instruction::INVOKE_VIRTUAL));
+}
+
+constexpr DexMemAccessType IGetMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionIGet(opcode));
+#endif
+  return static_cast<DexMemAccessType>(code - Instruction::IGET);
+}
+
+constexpr DexMemAccessType IPutMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionIPut(opcode));
+#endif
+  return static_cast<DexMemAccessType>(code - Instruction::IPUT);
+}
+
+constexpr DexMemAccessType SGetMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionSGet(opcode));
+#endif
+  return static_cast<DexMemAccessType>(code - Instruction::SGET);
+}
+
+constexpr DexMemAccessType SPutMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionSPut(opcode));
+#endif
+  return static_cast<DexMemAccessType>(code - Instruction::SPUT);
+}
+
+constexpr DexMemAccessType AGetMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionAGet(opcode));
+#endif
+  return static_cast<DexMemAccessType>(code - Instruction::AGET);
+}
+
+constexpr DexMemAccessType APutMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionAPut(opcode));
+#endif
+  return static_cast<DexMemAccessType>(code - Instruction::APUT);
+}
+
+constexpr DexMemAccessType IGetOrIPutMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionIGetOrIPut(opcode));
+#endif
+  return (code >= Instruction::IPUT) ? IPutMemAccessType(code) : IGetMemAccessType(code);
+}
+
+constexpr DexMemAccessType SGetOrSPutMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionSGetOrSPut(opcode));
+#endif
+  return (code >= Instruction::SPUT) ? SPutMemAccessType(code) : SGetMemAccessType(code);
+}
+
+constexpr DexMemAccessType AGetOrAPutMemAccessType(Instruction::Code code) {
+#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
+  DCHECK(IsInstructionAGetOrAPut(opcode));
+#endif
+  return (code >= Instruction::APUT) ? APutMemAccessType(code) : AGetMemAccessType(code);
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_
diff --git a/compiler/utils/growable_array.h b/compiler/utils/growable_array.h
index 61e420c..fde65e7 100644
--- a/compiler/utils/growable_array.h
+++ b/compiler/utils/growable_array.h
@@ -19,26 +19,20 @@
 
 #include <stdint.h>
 #include <stddef.h>
-#include "arena_allocator.h"
+
+#include "arena_object.h"
 
 namespace art {
 
-// Type of growable list for memory tuning.
-enum OatListKind {
-  kGrowableArrayMisc = 0,
-  kGNumListKinds
-};
-
 // Deprecated
 // TODO: Replace all uses with ArenaVector<T>.
 template<typename T>
-class GrowableArray {
+class GrowableArray : public ArenaObject<kArenaAllocGrowableArray> {
   public:
-    GrowableArray(ArenaAllocator* arena, size_t init_length, OatListKind kind = kGrowableArrayMisc)
+    GrowableArray(ArenaAllocator* arena, size_t init_length)
       : arena_(arena),
         num_allocated_(init_length),
-        num_used_(0),
-        kind_(kind) {
+        num_used_(0) {
       elem_list_ = static_cast<T*>(arena_->Alloc(sizeof(T) * init_length,
                                                  kArenaAllocGrowableArray));
     }
@@ -152,16 +146,10 @@
 
     T* GetRawStorage() const { return elem_list_; }
 
-    static void* operator new(size_t size, ArenaAllocator* arena) {
-      return arena->Alloc(sizeof(GrowableArray<T>), kArenaAllocGrowableArray);
-    }
-    static void operator delete(void* p) {}  // Nop.
-
   private:
     ArenaAllocator* const arena_;
     size_t num_allocated_;
     size_t num_used_;
-    OatListKind kind_;
     T* elem_list_;
 };
 
diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h
index bfb2829..bb62bca 100644
--- a/compiler/utils/managed_register.h
+++ b/compiler/utils/managed_register.h
@@ -30,6 +30,9 @@
 namespace mips {
 class MipsManagedRegister;
 }
+namespace mips64 {
+class Mips64ManagedRegister;
+}
 
 namespace x86 {
 class X86ManagedRegister;
@@ -54,6 +57,7 @@
   arm::ArmManagedRegister AsArm() const;
   arm64::Arm64ManagedRegister AsArm64() const;
   mips::MipsManagedRegister AsMips() const;
+  mips64::Mips64ManagedRegister AsMips64() const;
   x86::X86ManagedRegister AsX86() const;
   x86_64::X86_64ManagedRegister AsX86_64() const;
 
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 8001dcd..b5437b0 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -332,7 +332,7 @@
 }
 
 void MipsAssembler::Jr(Register rs) {
-  EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x08);
+  EmitR(0, rs, static_cast<Register>(0), static_cast<Register>(0), 0, 0x09);  // Jalr zero, rs
   Nop();
 }
 
@@ -420,7 +420,7 @@
 }
 
 void MipsAssembler::Move(Register rt, Register rs) {
-  EmitI(0x8, rs, rt, 0);
+  EmitI(0x9, rs, rt, 0);    // Addiu
 }
 
 void MipsAssembler::Clear(Register rt) {
@@ -447,11 +447,11 @@
 }
 
 void MipsAssembler::AddConstant(Register rt, Register rs, int32_t value) {
-  Addi(rt, rs, value);
+  Addiu(rt, rs, value);
 }
 
 void MipsAssembler::LoadImmediate(Register rt, int32_t value) {
-  Addi(rt, ZERO, value);
+  Addiu(rt, ZERO, value);
 }
 
 void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
new file mode 100644
index 0000000..233ae7d
--- /dev/null
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -0,0 +1,1036 @@
+/*
+ * 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 "assembler_mips64.h"
+
+#include "base/casts.h"
+#include "entrypoints/quick/quick_entrypoints.h"
+#include "memory_region.h"
+#include "thread.h"
+
+namespace art {
+namespace mips64 {
+
+void Mips64Assembler::Emit(int32_t value) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  buffer_.Emit<int32_t>(value);
+}
+
+void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd,
+                            int shamt, int funct) {
+  CHECK_NE(rs, kNoGpuRegister);
+  CHECK_NE(rt, kNoGpuRegister);
+  CHECK_NE(rd, kNoGpuRegister);
+  int32_t encoding = opcode << kOpcodeShift |
+                     static_cast<int32_t>(rs) << kRsShift |
+                     static_cast<int32_t>(rt) << kRtShift |
+                     static_cast<int32_t>(rd) << kRdShift |
+                     shamt << kShamtShift |
+                     funct;
+  Emit(encoding);
+}
+
+void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
+  CHECK_NE(rs, kNoGpuRegister);
+  CHECK_NE(rt, kNoGpuRegister);
+  int32_t encoding = opcode << kOpcodeShift |
+                     static_cast<int32_t>(rs) << kRsShift |
+                     static_cast<int32_t>(rt) << kRtShift |
+                     imm;
+  Emit(encoding);
+}
+
+void Mips64Assembler::EmitJ(int opcode, int address) {
+  int32_t encoding = opcode << kOpcodeShift |
+                     address;
+  Emit(encoding);
+}
+
+void Mips64Assembler::EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd,
+int funct) {
+  CHECK_NE(ft, kNoFpuRegister);
+  CHECK_NE(fs, kNoFpuRegister);
+  CHECK_NE(fd, kNoFpuRegister);
+  int32_t encoding = opcode << kOpcodeShift |
+                     fmt << kFmtShift |
+                     static_cast<int32_t>(ft) << kFtShift |
+                     static_cast<int32_t>(fs) << kFsShift |
+                     static_cast<int32_t>(fd) << kFdShift |
+                     funct;
+  Emit(encoding);
+}
+
+void Mips64Assembler::EmitFI(int opcode, int fmt, FpuRegister rt, uint16_t imm) {
+  CHECK_NE(rt, kNoFpuRegister);
+  int32_t encoding = opcode << kOpcodeShift |
+                     fmt << kFmtShift |
+                     static_cast<int32_t>(rt) << kRtShift |
+                     imm;
+  Emit(encoding);
+}
+
+void Mips64Assembler::EmitBranch(GpuRegister rt, GpuRegister rs, Label* label, bool equal) {
+  int offset;
+  if (label->IsBound()) {
+    offset = label->Position() - buffer_.Size();
+  } else {
+    // Use the offset field of the branch instruction for linking the sites.
+    offset = label->position_;
+    label->LinkTo(buffer_.Size());
+  }
+  if (equal) {
+    Beq(rt, rs, (offset >> 2) & kBranchOffsetMask);
+  } else {
+    Bne(rt, rs, (offset >> 2) & kBranchOffsetMask);
+  }
+}
+
+void Mips64Assembler::EmitJump(Label* label, bool link) {
+  int offset;
+  if (label->IsBound()) {
+    offset = label->Position() - buffer_.Size();
+  } else {
+    // Use the offset field of the jump instruction for linking the sites.
+    offset = label->position_;
+    label->LinkTo(buffer_.Size());
+  }
+  if (link) {
+    Jal((offset >> 2) & kJumpOffsetMask);
+  } else {
+    J((offset >> 2) & kJumpOffsetMask);
+  }
+}
+
+int32_t Mips64Assembler::EncodeBranchOffset(int offset, int32_t inst, bool is_jump) {
+  CHECK_ALIGNED(offset, 4);
+  CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset;
+
+  // Properly preserve only the bits supported in the instruction.
+  offset >>= 2;
+  if (is_jump) {
+    offset &= kJumpOffsetMask;
+    return (inst & ~kJumpOffsetMask) | offset;
+  } else {
+    offset &= kBranchOffsetMask;
+    return (inst & ~kBranchOffsetMask) | offset;
+  }
+}
+
+int Mips64Assembler::DecodeBranchOffset(int32_t inst, bool is_jump) {
+  // Sign-extend, then left-shift by 2.
+  if (is_jump) {
+    return (((inst & kJumpOffsetMask) << 6) >> 4);
+  } else {
+    return (((inst & kBranchOffsetMask) << 16) >> 14);
+  }
+}
+
+void Mips64Assembler::Bind(Label* label, bool is_jump) {
+  CHECK(!label->IsBound());
+  int bound_pc = buffer_.Size();
+  while (label->IsLinked()) {
+    int32_t position = label->Position();
+    int32_t next = buffer_.Load<int32_t>(position);
+    int32_t offset = is_jump ? bound_pc - position : bound_pc - position - 4;
+    int32_t encoded = Mips64Assembler::EncodeBranchOffset(offset, next, is_jump);
+    buffer_.Store<int32_t>(position, encoded);
+    label->position_ = Mips64Assembler::DecodeBranchOffset(next, is_jump);
+  }
+  label->BindTo(bound_pc);
+}
+
+void Mips64Assembler::Add(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x20);
+}
+
+void Mips64Assembler::Addi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x8, rs, rt, imm16);
+}
+
+void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x21);
+}
+
+void Mips64Assembler::Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x9, rs, rt, imm16);
+}
+
+void Mips64Assembler::Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x19, rs, rt, imm16);
+}
+
+void Mips64Assembler::Sub(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x22);
+}
+
+void Mips64Assembler::Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x23);
+}
+
+void Mips64Assembler::Mult(GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, static_cast<GpuRegister>(0), 0, 0x18);
+}
+
+void Mips64Assembler::Multu(GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, static_cast<GpuRegister>(0), 0, 0x19);
+}
+
+void Mips64Assembler::Div(GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, static_cast<GpuRegister>(0), 0, 0x1a);
+}
+
+void Mips64Assembler::Divu(GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, static_cast<GpuRegister>(0), 0, 0x1b);
+}
+
+void Mips64Assembler::And(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x24);
+}
+
+void Mips64Assembler::Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0xc, rs, rt, imm16);
+}
+
+void Mips64Assembler::Or(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x25);
+}
+
+void Mips64Assembler::Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0xd, rs, rt, imm16);
+}
+
+void Mips64Assembler::Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x26);
+}
+
+void Mips64Assembler::Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0xe, rs, rt, imm16);
+}
+
+void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x27);
+}
+
+void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rs, int shamt) {
+  EmitR(0, rs, static_cast<GpuRegister>(0), rd, shamt, 0x00);
+}
+
+void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rs, int shamt) {
+  EmitR(0, rs, static_cast<GpuRegister>(0), rd, shamt, 0x02);
+}
+
+void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rs, int shamt) {
+  EmitR(0, rs, static_cast<GpuRegister>(0), rd, shamt, 0x03);
+}
+
+void Mips64Assembler::Sllv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x04);
+}
+
+void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x06);
+}
+
+void Mips64Assembler::Srav(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x07);
+}
+
+void Mips64Assembler::Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x20, rs, rt, imm16);
+}
+
+void Mips64Assembler::Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x21, rs, rt, imm16);
+}
+
+void Mips64Assembler::Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x23, rs, rt, imm16);
+}
+
+void Mips64Assembler::Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x37, rs, rt, imm16);
+}
+
+void Mips64Assembler::Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x24, rs, rt, imm16);
+}
+
+void Mips64Assembler::Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x25, rs, rt, imm16);
+}
+
+void Mips64Assembler::Lui(GpuRegister rt, uint16_t imm16) {
+  EmitI(0xf, static_cast<GpuRegister>(0), rt, imm16);
+}
+
+void Mips64Assembler::Mfhi(GpuRegister rd) {
+  EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), rd, 0, 0x10);
+}
+
+void Mips64Assembler::Mflo(GpuRegister rd) {
+  EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), rd, 0, 0x12);
+}
+
+void Mips64Assembler::Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x28, rs, rt, imm16);
+}
+
+void Mips64Assembler::Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x29, rs, rt, imm16);
+}
+
+void Mips64Assembler::Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x2b, rs, rt, imm16);
+}
+
+void Mips64Assembler::Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x3f, rs, rt, imm16);
+}
+
+void Mips64Assembler::Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x2a);
+}
+
+void Mips64Assembler::Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  EmitR(0, rs, rt, rd, 0, 0x2b);
+}
+
+void Mips64Assembler::Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0xa, rs, rt, imm16);
+}
+
+void Mips64Assembler::Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0xb, rs, rt, imm16);
+}
+
+void Mips64Assembler::Beq(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x4, rs, rt, imm16);
+  Nop();
+}
+
+void Mips64Assembler::Bne(GpuRegister rt, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x5, rs, rt, imm16);
+  Nop();
+}
+
+void Mips64Assembler::J(uint32_t address) {
+  EmitJ(0x2, address);
+  Nop();
+}
+
+void Mips64Assembler::Jal(uint32_t address) {
+  EmitJ(0x2, address);
+  Nop();
+}
+
+void Mips64Assembler::Jr(GpuRegister rs) {
+  EmitR(0, rs, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), 0, 0x09);  // Jalr zero, rs
+  Nop();
+}
+
+void Mips64Assembler::Jalr(GpuRegister rs) {
+  EmitR(0, rs, static_cast<GpuRegister>(0), RA, 0, 0x09);
+  Nop();
+}
+
+void Mips64Assembler::AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x10, ft, fs, fd, 0x0);
+}
+
+void Mips64Assembler::SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x10, ft, fs, fd, 0x1);
+}
+
+void Mips64Assembler::MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x10, ft, fs, fd, 0x2);
+}
+
+void Mips64Assembler::DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x10, ft, fs, fd, 0x3);
+}
+
+void Mips64Assembler::AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x11, static_cast<FpuRegister>(ft), static_cast<FpuRegister>(fs),
+         static_cast<FpuRegister>(fd), 0x0);
+}
+
+void Mips64Assembler::SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x11, static_cast<FpuRegister>(ft), static_cast<FpuRegister>(fs),
+         static_cast<FpuRegister>(fd), 0x1);
+}
+
+void Mips64Assembler::MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x11, static_cast<FpuRegister>(ft), static_cast<FpuRegister>(fs),
+         static_cast<FpuRegister>(fd), 0x2);
+}
+
+void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+  EmitFR(0x11, 0x11, static_cast<FpuRegister>(ft), static_cast<FpuRegister>(fs),
+         static_cast<FpuRegister>(fd), 0x3);
+}
+
+void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
+  EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
+}
+
+void Mips64Assembler::MovD(FpuRegister fd, FpuRegister fs) {
+  EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), static_cast<FpuRegister>(fs),
+         static_cast<FpuRegister>(fd), 0x6);
+}
+
+void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
+  EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
+}
+
+void Mips64Assembler::Mtc1(FpuRegister ft, GpuRegister rs) {
+  EmitFR(0x11, 0x04, ft, static_cast<FpuRegister>(rs), static_cast<FpuRegister>(0), 0x0);
+}
+
+void Mips64Assembler::Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x31, rs, static_cast<GpuRegister>(ft), imm16);
+}
+
+void Mips64Assembler::Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x35, rs, static_cast<GpuRegister>(ft), imm16);
+}
+
+void Mips64Assembler::Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x39, rs, static_cast<GpuRegister>(ft), imm16);
+}
+
+void Mips64Assembler::Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16) {
+  EmitI(0x3d, rs, static_cast<GpuRegister>(ft), imm16);
+}
+
+void Mips64Assembler::Break() {
+  EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
+        static_cast<GpuRegister>(0), 0, 0xD);
+}
+
+void Mips64Assembler::Nop() {
+  EmitR(0x0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0),
+        static_cast<GpuRegister>(0), 0, 0x0);
+}
+
+void Mips64Assembler::Move(GpuRegister rt, GpuRegister rs) {
+  EmitI(0x19, rs, rt, 0);   // Daddiu
+}
+
+void Mips64Assembler::Clear(GpuRegister rt) {
+  EmitR(0, static_cast<GpuRegister>(0), static_cast<GpuRegister>(0), rt, 0, 0x20);
+}
+
+void Mips64Assembler::Not(GpuRegister rt, GpuRegister rs) {
+  EmitR(0, static_cast<GpuRegister>(0), rs, rt, 0, 0x27);
+}
+
+void Mips64Assembler::Mul(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  Mult(rs, rt);
+  Mflo(rd);
+}
+
+void Mips64Assembler::Div(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  Div(rs, rt);
+  Mflo(rd);
+}
+
+void Mips64Assembler::Rem(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+  Div(rs, rt);
+  Mfhi(rd);
+}
+
+void Mips64Assembler::AddConstant64(GpuRegister rt, GpuRegister rs, int32_t value) {
+  CHECK((value >= -32768) && (value <= 32766));
+  Daddiu(rt, rs, value);
+}
+
+void Mips64Assembler::LoadImmediate64(GpuRegister rt, int32_t value) {
+  CHECK((value >= -32768) && (value <= 32766));
+  Daddiu(rt, ZERO, value);
+}
+
+void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
+                                     int32_t offset) {
+  switch (type) {
+    case kLoadSignedByte:
+      Lb(reg, base, offset);
+      break;
+    case kLoadUnsignedByte:
+      Lbu(reg, base, offset);
+      break;
+    case kLoadSignedHalfword:
+      Lh(reg, base, offset);
+      break;
+    case kLoadUnsignedHalfword:
+      Lhu(reg, base, offset);
+      break;
+    case kLoadWord:
+      Lw(reg, base, offset);
+      break;
+    case kLoadDoubleword:
+      // TODO: alignment issues ???
+      Ld(reg, base, offset);
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+  }
+}
+
+void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
+                                        int32_t offset) {
+  CHECK((offset >= -32768) && (offset <= 32766));
+  switch (type) {
+    case kLoadWord:
+      Lwc1(reg, base, offset);
+      break;
+    case kLoadDoubleword:
+      // TODO: alignment issues ???
+      Ldc1(reg, base, offset);
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+  }
+}
+
+void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset,
+                               size_t size) {
+  Mips64ManagedRegister dst = m_dst.AsMips64();
+  if (dst.IsNoRegister()) {
+    CHECK_EQ(0u, size) << dst;
+  } else if (dst.IsGpuRegister()) {
+    if (size == 4) {
+      CHECK_EQ(4u, size) << dst;
+      LoadFromOffset(kLoadWord, dst.AsGpuRegister(), src_register, src_offset);
+    } else if (size == 8) {
+      CHECK_EQ(8u, size) << dst;
+      LoadFromOffset(kLoadDoubleword, dst.AsGpuRegister(), src_register, src_offset);
+    } else {
+      UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
+    }
+  } else if (dst.IsFpuRegister()) {
+    if (size == 4) {
+      CHECK_EQ(4u, size) << dst;
+      LoadFpuFromOffset(kLoadWord, dst.AsFpuRegister(), src_register, src_offset);
+    } else if (size == 8) {
+      CHECK_EQ(8u, size) << dst;
+      LoadFpuFromOffset(kLoadDoubleword, dst.AsFpuRegister(), src_register, src_offset);
+    } else {
+      UNIMPLEMENTED(FATAL) << "We only support Load() of size 4 and 8";
+    }
+  }
+}
+
+void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
+                                    int32_t offset) {
+  switch (type) {
+    case kStoreByte:
+      Sb(reg, base, offset);
+      break;
+    case kStoreHalfword:
+      Sh(reg, base, offset);
+      break;
+    case kStoreWord:
+      Sw(reg, base, offset);
+      break;
+    case kStoreDoubleword:
+      // TODO: alignment issues ???
+      Sd(reg, base, offset);
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+  }
+}
+
+void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
+                                       int32_t offset) {
+  switch (type) {
+    case kStoreWord:
+      Swc1(reg, base, offset);
+      break;
+    case kStoreDoubleword:
+      Sdc1(reg, base, offset);
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+  }
+}
+
+constexpr size_t kFramePointerSize = 8;
+
+void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
+                                 const std::vector<ManagedRegister>& callee_save_regs,
+                                 const ManagedRegisterEntrySpills& entry_spills) {
+  CHECK_ALIGNED(frame_size, kStackAlignment);
+
+  // Increase frame to required size.
+  IncreaseFrameSize(frame_size);
+
+  // Push callee saves and return address
+  int stack_offset = frame_size - kFramePointerSize;
+  StoreToOffset(kStoreDoubleword, RA, SP, stack_offset);
+  for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
+    stack_offset -= kFramePointerSize;
+    GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
+    StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
+  }
+
+  // Write out Method*.
+  StoreToOffset(kStoreWord, method_reg.AsMips64().AsGpuRegister(), SP, 0);
+
+  // Write out entry spills.
+  int32_t offset = frame_size + sizeof(StackReference<mirror::ArtMethod>);
+  for (size_t i = 0; i < entry_spills.size(); ++i) {
+    Mips64ManagedRegister reg = entry_spills.at(i).AsMips64();
+    ManagedRegisterSpill spill = entry_spills.at(i);
+    int32_t size = spill.getSize();
+    if (reg.IsNoRegister()) {
+      // only increment stack offset.
+      offset += size;
+    } else if (reg.IsFpuRegister()) {
+      StoreFpuToOffset((size == 4) ? kStoreWord : kStoreDoubleword, reg.AsFpuRegister(), SP, offset);
+      offset += size;
+    } else if (reg.IsGpuRegister()) {
+      StoreToOffset((size == 4) ? kStoreWord : kStoreDoubleword, reg.AsGpuRegister(), SP, offset);
+      offset += size;
+    }
+  }
+}
+
+void Mips64Assembler::RemoveFrame(size_t frame_size,
+                                  const std::vector<ManagedRegister>& callee_save_regs) {
+  CHECK_ALIGNED(frame_size, kStackAlignment);
+
+  // Pop callee saves and return address
+  int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
+  for (size_t i = 0; i < callee_save_regs.size(); ++i) {
+    GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
+    LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
+    stack_offset += kFramePointerSize;
+  }
+  LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset);
+
+  // Decrease frame to required size.
+  DecreaseFrameSize(frame_size);
+
+  // Then jump to the return address.
+  Jr(RA);
+}
+
+void Mips64Assembler::IncreaseFrameSize(size_t adjust) {
+  CHECK_ALIGNED(adjust, kStackAlignment);
+  AddConstant64(SP, SP, -adjust);
+}
+
+void Mips64Assembler::DecreaseFrameSize(size_t adjust) {
+  CHECK_ALIGNED(adjust, kStackAlignment);
+  AddConstant64(SP, SP, adjust);
+}
+
+void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
+  Mips64ManagedRegister src = msrc.AsMips64();
+  if (src.IsNoRegister()) {
+    CHECK_EQ(0u, size);
+  } else if (src.IsGpuRegister()) {
+    CHECK(size == 4 || size == 8) << size;
+    if (size == 8) {
+      StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
+    } else if (size == 4) {
+      StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
+    } else {
+      UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
+    }
+  } else if (src.IsFpuRegister()) {
+    CHECK(size == 4 || size == 8) << size;
+    if (size == 8) {
+      StoreFpuToOffset(kStoreDoubleword, src.AsFpuRegister(), SP, dest.Int32Value());
+    } else if (size == 4) {
+      StoreFpuToOffset(kStoreWord, src.AsFpuRegister(), SP, dest.Int32Value());
+    } else {
+      UNIMPLEMENTED(FATAL) << "We only support Store() of size 4 and 8";
+    }
+  }
+}
+
+void Mips64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
+  Mips64ManagedRegister src = msrc.AsMips64();
+  CHECK(src.IsGpuRegister());
+  StoreToOffset(kStoreWord, src.AsGpuRegister(), SP, dest.Int32Value());
+}
+
+void Mips64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
+  Mips64ManagedRegister src = msrc.AsMips64();
+  CHECK(src.IsGpuRegister());
+  StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
+}
+
+void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
+                                            ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  LoadImmediate64(scratch.AsGpuRegister(), imm);
+  StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
+}
+
+void Mips64Assembler::StoreImmediateToThread64(ThreadOffset<8> dest, uint32_t imm,
+                                               ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  LoadImmediate64(scratch.AsGpuRegister(), imm);
+  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, dest.Int32Value());
+}
+
+void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<8> thr_offs,
+                                                 FrameOffset fr_offs,
+                                                 ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  AddConstant64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
+  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
+}
+
+void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<8> thr_offs) {
+  StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
+}
+
+void Mips64Assembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
+                                    FrameOffset in_off, ManagedRegister mscratch) {
+  Mips64ManagedRegister src = msrc.AsMips64();
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  StoreToOffset(kStoreDoubleword, src.AsGpuRegister(), SP, dest.Int32Value());
+  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, in_off.Int32Value());
+  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value() + 8);
+}
+
+void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
+  return EmitLoad(mdest, SP, src.Int32Value(), size);
+}
+
+void Mips64Assembler::LoadFromThread64(ManagedRegister mdest, ThreadOffset<8> src, size_t size) {
+  return EmitLoad(mdest, S1, src.Int32Value(), size);
+}
+
+void Mips64Assembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
+  Mips64ManagedRegister dest = mdest.AsMips64();
+  CHECK(dest.IsGpuRegister());
+  LoadFromOffset(kLoadWord, dest.AsGpuRegister(), SP, src.Int32Value());
+}
+
+void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base,
+                            MemberOffset offs) {
+  Mips64ManagedRegister dest = mdest.AsMips64();
+  CHECK(dest.IsGpuRegister() && dest.IsGpuRegister());
+  LoadFromOffset(kLoadWord, dest.AsGpuRegister(),
+                 base.AsMips64().AsGpuRegister(), offs.Int32Value());
+  if (kPoisonHeapReferences) {
+    Subu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
+  }
+}
+
+void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
+                               Offset offs) {
+  Mips64ManagedRegister dest = mdest.AsMips64();
+  CHECK(dest.IsGpuRegister() && dest.IsGpuRegister()) << dest;
+  LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(),
+                 base.AsMips64().AsGpuRegister(), offs.Int32Value());
+}
+
+void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest,
+                                         ThreadOffset<8> offs) {
+  Mips64ManagedRegister dest = mdest.AsMips64();
+  CHECK(dest.IsGpuRegister());
+  LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
+}
+
+void Mips64Assembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
+  UNIMPLEMENTED(FATAL) << "no sign extension necessary for mips";
+}
+
+void Mips64Assembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
+  UNIMPLEMENTED(FATAL) << "no zero extension necessary for mips";
+}
+
+void Mips64Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
+  Mips64ManagedRegister dest = mdest.AsMips64();
+  Mips64ManagedRegister src = msrc.AsMips64();
+  if (!dest.Equals(src)) {
+    if (dest.IsGpuRegister()) {
+      CHECK(src.IsGpuRegister()) << src;
+      Move(dest.AsGpuRegister(), src.AsGpuRegister());
+    } else if (dest.IsFpuRegister()) {
+      CHECK(src.IsFpuRegister()) << src;
+      if (size == 4) {
+        MovS(dest.AsFpuRegister(), src.AsFpuRegister());
+      } else if (size == 8) {
+        MovD(dest.AsFpuRegister(), src.AsFpuRegister());
+      } else {
+        UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
+      }
+    }
+  }
+}
+
+void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
+                              ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
+  StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
+}
+
+void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
+                                             ThreadOffset<8> thr_offs,
+                                             ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
+  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
+}
+
+void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<8> thr_offs,
+                                           FrameOffset fr_offs,
+                                           ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
+                 SP, fr_offs.Int32Value());
+  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(),
+                S1, thr_offs.Int32Value());
+}
+
+void Mips64Assembler::Copy(FrameOffset dest, FrameOffset src,
+                           ManagedRegister mscratch, size_t size) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  CHECK(size == 4 || size == 8) << size;
+  if (size == 4) {
+    LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
+    StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
+  } else if (size == 8) {
+    LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
+  } else {
+    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
+  }
+}
+
+void Mips64Assembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
+                         ManagedRegister mscratch, size_t size) {
+  GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
+  CHECK(size == 4 || size == 8) << size;
+  if (size == 4) {
+    LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
+                   src_offset.Int32Value());
+    StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
+  } else if (size == 8) {
+    LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
+                   src_offset.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
+  } else {
+    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
+  }
+}
+
+void Mips64Assembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
+                         ManagedRegister mscratch, size_t size) {
+  GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
+  CHECK(size == 4 || size == 8) << size;
+  if (size == 4) {
+    LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
+    StoreToOffset(kStoreWord, scratch, dest_base.AsMips64().AsGpuRegister(),
+                  dest_offset.Int32Value());
+  } else if (size == 8) {
+    LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
+                  dest_offset.Int32Value());
+  } else {
+    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
+  }
+}
+
+void Mips64Assembler::Copy(FrameOffset /*dest*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
+                         ManagedRegister /*mscratch*/, size_t /*size*/) {
+  UNIMPLEMENTED(FATAL) << "no mips64 implementation";
+}
+
+void Mips64Assembler::Copy(ManagedRegister dest, Offset dest_offset,
+                         ManagedRegister src, Offset src_offset,
+                         ManagedRegister mscratch, size_t size) {
+  GpuRegister scratch = mscratch.AsMips64().AsGpuRegister();
+  CHECK(size == 4 || size == 8) << size;
+  if (size == 4) {
+    LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
+    StoreToOffset(kStoreWord, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
+  } else if (size == 8) {
+    LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
+                   src_offset.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(),
+                  dest_offset.Int32Value());
+  } else {
+    UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
+  }
+}
+
+void Mips64Assembler::Copy(FrameOffset /*dest*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset
+/*src_offset*/,
+                         ManagedRegister /*mscratch*/, size_t /*size*/) {
+  UNIMPLEMENTED(FATAL) << "no mips64 implementation";
+}
+
+void Mips64Assembler::MemoryBarrier(ManagedRegister) {
+  UNIMPLEMENTED(FATAL) << "no mips64 implementation";
+}
+
+void Mips64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
+                                    FrameOffset handle_scope_offset,
+                                    ManagedRegister min_reg, bool null_allowed) {
+  Mips64ManagedRegister out_reg = mout_reg.AsMips64();
+  Mips64ManagedRegister in_reg = min_reg.AsMips64();
+  CHECK(in_reg.IsNoRegister() || in_reg.IsGpuRegister()) << in_reg;
+  CHECK(out_reg.IsGpuRegister()) << out_reg;
+  if (null_allowed) {
+    Label null_arg;
+    // 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()) {
+      LoadFromOffset(kLoadWord, out_reg.AsGpuRegister(),
+                     SP, handle_scope_offset.Int32Value());
+      in_reg = out_reg;
+    }
+    if (!out_reg.Equals(in_reg)) {
+      LoadImmediate64(out_reg.AsGpuRegister(), 0);
+    }
+    EmitBranch(in_reg.AsGpuRegister(), ZERO, &null_arg, true);
+    AddConstant64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
+    Bind(&null_arg, false);
+  } else {
+    AddConstant64(out_reg.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
+  }
+}
+
+void Mips64Assembler::CreateHandleScopeEntry(FrameOffset out_off,
+                                    FrameOffset handle_scope_offset,
+                                    ManagedRegister mscratch,
+                                    bool null_allowed) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  if (null_allowed) {
+    Label null_arg;
+    LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), 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)
+    EmitBranch(scratch.AsGpuRegister(), ZERO, &null_arg, true);
+    AddConstant64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
+    Bind(&null_arg, false);
+  } else {
+    AddConstant64(scratch.AsGpuRegister(), SP, handle_scope_offset.Int32Value());
+  }
+  StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, out_off.Int32Value());
+}
+
+// Given a handle scope entry, load the associated reference.
+void Mips64Assembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
+                                          ManagedRegister min_reg) {
+  Mips64ManagedRegister out_reg = mout_reg.AsMips64();
+  Mips64ManagedRegister in_reg = min_reg.AsMips64();
+  CHECK(out_reg.IsGpuRegister()) << out_reg;
+  CHECK(in_reg.IsGpuRegister()) << in_reg;
+  Label null_arg;
+  if (!out_reg.Equals(in_reg)) {
+    LoadImmediate64(out_reg.AsGpuRegister(), 0);
+  }
+  EmitBranch(in_reg.AsGpuRegister(), ZERO, &null_arg, true);
+  LoadFromOffset(kLoadDoubleword, out_reg.AsGpuRegister(),
+                 in_reg.AsGpuRegister(), 0);
+  Bind(&null_arg, false);
+}
+
+void Mips64Assembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
+  // TODO: not validating references
+}
+
+void Mips64Assembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
+  // TODO: not validating references
+}
+
+void Mips64Assembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister mscratch) {
+  Mips64ManagedRegister base = mbase.AsMips64();
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(base.IsGpuRegister()) << base;
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
+                 base.AsGpuRegister(), offset.Int32Value());
+  Jalr(scratch.AsGpuRegister());
+  // TODO: place reference map on call
+}
+
+void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  CHECK(scratch.IsGpuRegister()) << scratch;
+  // Call *(*(SP + base) + offset)
+  LoadFromOffset(kLoadWord, scratch.AsGpuRegister(),
+                 SP, base.Int32Value());
+  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
+                 scratch.AsGpuRegister(), offset.Int32Value());
+  Jalr(scratch.AsGpuRegister());
+  // TODO: place reference map on call
+}
+
+void Mips64Assembler::CallFromThread64(ThreadOffset<8> /*offset*/, ManagedRegister /*mscratch*/) {
+  UNIMPLEMENTED(FATAL) << "no mips64 implementation";
+}
+
+void Mips64Assembler::GetCurrentThread(ManagedRegister tr) {
+  Move(tr.AsMips64().AsGpuRegister(), S1);
+}
+
+void Mips64Assembler::GetCurrentThread(FrameOffset offset,
+                                     ManagedRegister /*mscratch*/) {
+  StoreToOffset(kStoreDoubleword, S1, SP, offset.Int32Value());
+}
+
+void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
+  Mips64ManagedRegister scratch = mscratch.AsMips64();
+  Mips64ExceptionSlowPath* slow = new Mips64ExceptionSlowPath(scratch, stack_adjust);
+  buffer_.EnqueueSlowPath(slow);
+  LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
+                 S1, Thread::ExceptionOffset<8>().Int32Value());
+  EmitBranch(scratch.AsGpuRegister(), ZERO, slow->Entry(), false);
+}
+
+void Mips64ExceptionSlowPath::Emit(Assembler* sasm) {
+  Mips64Assembler* sp_asm = down_cast<Mips64Assembler*>(sasm);
+#define __ sp_asm->
+  __ Bind(&entry_, false);
+  if (stack_adjust_ != 0) {  // Fix up the frame.
+    __ DecreaseFrameSize(stack_adjust_);
+  }
+  // Pass exception object as argument
+  // Don't care about preserving A0 as this call won't return
+  __ Move(A0, scratch_.AsGpuRegister());
+  // Set up call to Thread::Current()->pDeliverException
+  __ LoadFromOffset(kLoadDoubleword, T9, S1,
+                    QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
+  __ Jr(T9);
+  // Call never returns
+  __ Break();
+#undef __
+}
+
+}  // namespace mips64
+}  // namespace art
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
new file mode 100644
index 0000000..36e74d7
--- /dev/null
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -0,0 +1,294 @@
+/*
+ * 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_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
+#define ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "constants_mips64.h"
+#include "globals.h"
+#include "managed_register_mips64.h"
+#include "utils/assembler.h"
+#include "offsets.h"
+#include "utils.h"
+
+namespace art {
+namespace mips64 {
+
+enum LoadOperandType {
+  kLoadSignedByte,
+  kLoadUnsignedByte,
+  kLoadSignedHalfword,
+  kLoadUnsignedHalfword,
+  kLoadWord,
+  kLoadDoubleword
+};
+
+enum StoreOperandType {
+  kStoreByte,
+  kStoreHalfword,
+  kStoreWord,
+  kStoreDoubleword
+};
+
+class Mips64Assembler FINAL : public Assembler {
+ public:
+  Mips64Assembler() {}
+  virtual ~Mips64Assembler() {}
+
+  // Emit Machine Instructions.
+  void Add(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Addi(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Sub(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Mult(GpuRegister rs, GpuRegister rt);
+  void Multu(GpuRegister rs, GpuRegister rt);
+  void Div(GpuRegister rs, GpuRegister rt);
+  void Divu(GpuRegister rs, GpuRegister rt);
+
+  void And(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Or(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+
+  void Sll(GpuRegister rd, GpuRegister rs, int shamt);
+  void Srl(GpuRegister rd, GpuRegister rs, int shamt);
+  void Sra(GpuRegister rd, GpuRegister rs, int shamt);
+  void Sllv(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Srlv(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Srav(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+
+  void Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Lui(GpuRegister rt, uint16_t imm16);
+  void Mfhi(GpuRegister rd);
+  void Mflo(GpuRegister rd);
+
+  void Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+
+  void Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+
+  void Beq(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void Bne(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+  void J(uint32_t address);
+  void Jal(uint32_t address);
+  void Jr(GpuRegister rs);
+  void Jalr(GpuRegister rs);
+
+  void AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+  void MovS(FpuRegister fd, FpuRegister fs);
+  void MovD(FpuRegister fd, FpuRegister fs);
+
+  void Mfc1(GpuRegister rt, FpuRegister fs);
+  void Mtc1(FpuRegister ft, GpuRegister rs);
+  void Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
+  void Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
+  void Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
+  void Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
+
+  void Break();
+  void Nop();
+  void Move(GpuRegister rt, GpuRegister rs);
+  void Clear(GpuRegister rt);
+  void Not(GpuRegister rt, GpuRegister rs);
+  void Mul(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Div(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+  void Rem(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+
+  void AddConstant64(GpuRegister rt, GpuRegister rs, int32_t value);
+  void LoadImmediate64(GpuRegister rt, int32_t value);
+
+  void EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset, size_t size);
+  void LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base, int32_t offset);
+  void LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base, int32_t offset);
+  void StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base, int32_t offset);
+  void StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base, int32_t offset);
+
+  // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
+  void Emit(int32_t value);
+  void EmitBranch(GpuRegister rt, GpuRegister rs, Label* label, bool equal);
+  void EmitJump(Label* label, bool link);
+  void Bind(Label* label, bool is_jump);
+
+  //
+  // Overridden common assembler high-level functionality
+  //
+
+  // Emit code that will create an activation on the stack
+  void BuildFrame(size_t frame_size, ManagedRegister method_reg,
+                  const std::vector<ManagedRegister>& callee_save_regs,
+                  const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
+
+  // Emit code that will remove an activation from the stack
+  void RemoveFrame(size_t frame_size,
+                   const std::vector<ManagedRegister>& callee_save_regs) OVERRIDE;
+
+  void IncreaseFrameSize(size_t adjust) OVERRIDE;
+  void DecreaseFrameSize(size_t adjust) OVERRIDE;
+
+  // Store routines
+  void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
+  void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
+  void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
+
+  void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
+
+  void StoreImmediateToThread64(ThreadOffset<8> dest, uint32_t imm,
+                                ManagedRegister mscratch) OVERRIDE;
+
+  void StoreStackOffsetToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs,
+                                  ManagedRegister mscratch) OVERRIDE;
+
+  void StoreStackPointerToThread64(ThreadOffset<8> thr_offs) OVERRIDE;
+
+  void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
+                     ManagedRegister mscratch) OVERRIDE;
+
+  // Load routines
+  void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
+
+  void LoadFromThread64(ManagedRegister mdest, ThreadOffset<8> src, size_t size) OVERRIDE;
+
+  void LoadRef(ManagedRegister dest, FrameOffset  src) OVERRIDE;
+
+  void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs) OVERRIDE;
+
+  void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
+
+  void LoadRawPtrFromThread64(ManagedRegister mdest, ThreadOffset<8> offs) OVERRIDE;
+
+  // Copying routines
+  void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
+
+  void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<8> thr_offs,
+                              ManagedRegister mscratch) OVERRIDE;
+
+  void CopyRawPtrToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs,
+                            ManagedRegister mscratch) OVERRIDE;
+
+  void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
+
+  void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
+
+  void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch,
+            size_t size) OVERRIDE;
+
+  void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
+            ManagedRegister mscratch, size_t size) OVERRIDE;
+
+  void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch,
+            size_t size) OVERRIDE;
+
+  void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
+            ManagedRegister mscratch, size_t size) OVERRIDE;
+
+  void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
+            ManagedRegister mscratch, size_t size) OVERRIDE;
+
+  void MemoryBarrier(ManagedRegister) OVERRIDE;
+
+  // Sign extension
+  void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
+
+  // Zero extension
+  void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
+
+  // Exploit fast access in managed code to Thread::Current()
+  void GetCurrentThread(ManagedRegister tr) OVERRIDE;
+  void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
+
+  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
+  // value is null and null_allowed. in_reg holds a possibly stale reference
+  // that can be used to avoid loading the handle scope entry to see if the value is
+  // NULL.
+  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
+                              ManagedRegister in_reg, bool null_allowed) OVERRIDE;
+
+  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
+  // value is null and null_allowed.
+  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister
+                              mscratch, bool null_allowed) OVERRIDE;
+
+  // src holds a handle scope entry (Object**) load this into dst
+  void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
+
+  // Heap::VerifyObject on src. In some cases (such as a reference to this) we
+  // know that src may not be null.
+  void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
+  void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
+
+  // Call to address held at [base+offset]
+  void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
+  void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
+  void CallFromThread64(ThreadOffset<8> offset, ManagedRegister mscratch) OVERRIDE;
+
+  // Generate code to check if Thread::Current()->exception_ is non-null
+  // and branch to a ExceptionSlowPath if it is.
+  void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
+
+ private:
+  void EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd, int shamt, int funct);
+  void EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm);
+  void EmitJ(int opcode, int address);
+  void EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, int funct);
+  void EmitFI(int opcode, int fmt, FpuRegister rt, uint16_t imm);
+
+  int32_t EncodeBranchOffset(int offset, int32_t inst, bool is_jump);
+  int DecodeBranchOffset(int32_t inst, bool is_jump);
+
+  DISALLOW_COPY_AND_ASSIGN(Mips64Assembler);
+};
+
+// Slowpath entered when Thread::Current()->_exception is non-null
+class Mips64ExceptionSlowPath FINAL : public SlowPath {
+ public:
+  explicit Mips64ExceptionSlowPath(Mips64ManagedRegister scratch, size_t stack_adjust)
+      : scratch_(scratch), stack_adjust_(stack_adjust) {}
+  virtual void Emit(Assembler *sp_asm) OVERRIDE;
+ private:
+  const Mips64ManagedRegister scratch_;
+  const size_t stack_adjust_;
+};
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
diff --git a/compiler/utils/mips64/constants_mips64.h b/compiler/utils/mips64/constants_mips64.h
new file mode 100644
index 0000000..8b7697c
--- /dev/null
+++ b/compiler/utils/mips64/constants_mips64.h
@@ -0,0 +1,86 @@
+/*
+ * 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_UTILS_MIPS64_CONSTANTS_MIPS64_H_
+#define ART_COMPILER_UTILS_MIPS64_CONSTANTS_MIPS64_H_
+
+#include <iosfwd>
+
+#include "arch/mips64/registers_mips64.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "globals.h"
+
+namespace art {
+namespace mips64 {
+
+// Constants used for the decoding or encoding of the individual fields of instructions.
+enum InstructionFields {
+  kOpcodeShift = 26,
+  kOpcodeBits = 6,
+  kRsShift = 21,
+  kRsBits = 5,
+  kRtShift = 16,
+  kRtBits = 5,
+  kRdShift = 11,
+  kRdBits = 5,
+  kShamtShift = 6,
+  kShamtBits = 5,
+  kFunctShift = 0,
+  kFunctBits = 6,
+
+  kFmtShift = 21,
+  kFmtBits = 5,
+  kFtShift = 16,
+  kFtBits = 5,
+  kFsShift = 11,
+  kFsBits = 5,
+  kFdShift = 6,
+  kFdBits = 5,
+
+  kBranchOffsetMask = 0x0000ffff,
+  kJumpOffsetMask = 0x03ffffff,
+};
+
+enum ScaleFactor {
+  TIMES_1 = 0,
+  TIMES_2 = 1,
+  TIMES_4 = 2,
+  TIMES_8 = 3
+};
+
+class Instr {
+ public:
+  static const uint32_t kBreakPointInstruction = 0x0000000D;
+
+  bool IsBreakPoint() {
+    return ((*reinterpret_cast<const uint32_t*>(this)) & 0xFC0000CF) == kBreakPointInstruction;
+  }
+
+  // Instructions are read out of a code stream. The only way to get a
+  // reference to an instruction is to convert a pointer. There is no way
+  // to allocate or create instances of class Instr.
+  // Use the At(pc) function to create references to Instr.
+  static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
+};
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_MIPS64_CONSTANTS_MIPS64_H_
diff --git a/compiler/utils/mips64/managed_register_mips64.cc b/compiler/utils/mips64/managed_register_mips64.cc
new file mode 100644
index 0000000..dea396e
--- /dev/null
+++ b/compiler/utils/mips64/managed_register_mips64.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "managed_register_mips64.h"
+
+#include "globals.h"
+
+namespace art {
+namespace mips64 {
+
+bool Mips64ManagedRegister::Overlaps(const Mips64ManagedRegister& other) const {
+  if (IsNoRegister() || other.IsNoRegister()) return false;
+  CHECK(IsValidManagedRegister());
+  CHECK(other.IsValidManagedRegister());
+  if (Equals(other)) return true;
+  return false;
+}
+
+void Mips64ManagedRegister::Print(std::ostream& os) const {
+  if (!IsValidManagedRegister()) {
+    os << "No Register";
+  } else if (IsGpuRegister()) {
+    os << "GPU: " << static_cast<int>(AsGpuRegister());
+  } else if (IsFpuRegister()) {
+     os << "FpuRegister: " << static_cast<int>(AsFpuRegister());
+  } else {
+    os << "??: " << RegId();
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, const Mips64ManagedRegister& reg) {
+  reg.Print(os);
+  return os;
+}
+
+}  // namespace mips64
+}  // namespace art
diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h
new file mode 100644
index 0000000..924a928
--- /dev/null
+++ b/compiler/utils/mips64/managed_register_mips64.h
@@ -0,0 +1,121 @@
+/*
+ * 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_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_
+#define ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_
+
+#include "constants_mips64.h"
+#include "utils/managed_register.h"
+
+namespace art {
+namespace mips64 {
+
+const int kNumberOfGpuRegIds = kNumberOfGpuRegisters;
+const int kNumberOfGpuAllocIds = kNumberOfGpuRegisters;
+
+const int kNumberOfFpuRegIds = kNumberOfFpuRegisters;
+const int kNumberOfFpuAllocIds = kNumberOfFpuRegisters;
+
+const int kNumberOfRegIds = kNumberOfGpuRegIds + kNumberOfFpuRegIds;
+const int kNumberOfAllocIds = kNumberOfGpuAllocIds + kNumberOfFpuAllocIds;
+
+// An instance of class 'ManagedRegister' represents a single GPU register (enum
+// Register) or a double precision FP register (enum FpuRegister)
+// 'ManagedRegister::NoRegister()' provides an invalid register.
+// There is a one-to-one mapping between ManagedRegister and register id.
+class Mips64ManagedRegister : public ManagedRegister {
+ public:
+  GpuRegister AsGpuRegister() const {
+    CHECK(IsGpuRegister());
+    return static_cast<GpuRegister>(id_);
+  }
+
+  FpuRegister AsFpuRegister() const {
+    CHECK(IsFpuRegister());
+    return static_cast<FpuRegister>(id_ - kNumberOfGpuRegIds);
+  }
+
+  bool IsGpuRegister() const {
+    CHECK(IsValidManagedRegister());
+    return (0 <= id_) && (id_ < kNumberOfGpuRegIds);
+  }
+
+  bool IsFpuRegister() const {
+    CHECK(IsValidManagedRegister());
+    const int test = id_ - kNumberOfGpuRegIds;
+    return (0 <= test) && (test < kNumberOfFpuRegIds);
+  }
+
+  void Print(std::ostream& os) const;
+
+  // Returns true if the two managed-registers ('this' and 'other') overlap.
+  // Either managed-register may be the NoRegister. If both are the NoRegister
+  // then false is returned.
+  bool Overlaps(const Mips64ManagedRegister& other) const;
+
+  static Mips64ManagedRegister FromGpuRegister(GpuRegister r) {
+    CHECK_NE(r, kNoGpuRegister);
+    return FromRegId(r);
+  }
+
+  static Mips64ManagedRegister FromFpuRegister(FpuRegister r) {
+    CHECK_NE(r, kNoFpuRegister);
+    return FromRegId(r + kNumberOfGpuRegIds);
+  }
+
+ private:
+  bool IsValidManagedRegister() const {
+    return (0 <= id_) && (id_ < kNumberOfRegIds);
+  }
+
+  int RegId() const {
+    CHECK(!IsNoRegister());
+    return id_;
+  }
+
+  int AllocId() const {
+    CHECK(IsValidManagedRegister());
+    CHECK_LT(id_, kNumberOfAllocIds);
+    return id_;
+  }
+
+  int AllocIdLow() const;
+  int AllocIdHigh() const;
+
+  friend class ManagedRegister;
+
+  explicit Mips64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+
+  static Mips64ManagedRegister FromRegId(int reg_id) {
+    Mips64ManagedRegister reg(reg_id);
+    CHECK(reg.IsValidManagedRegister());
+    return reg;
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, const Mips64ManagedRegister& reg);
+
+}  // namespace mips64
+
+inline mips64::Mips64ManagedRegister ManagedRegister::AsMips64() const {
+  mips64::Mips64ManagedRegister reg(id_);
+  CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
+  return reg;
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_
diff --git a/compiler/utils/scoped_arena_allocator.cc b/compiler/utils/scoped_arena_allocator.cc
index aeb2f76..d9e0619 100644
--- a/compiler/utils/scoped_arena_allocator.cc
+++ b/compiler/utils/scoped_arena_allocator.cc
@@ -96,6 +96,7 @@
   uint8_t* ptr = top_ptr_;
   if (UNLIKELY(static_cast<size_t>(top_end_ - ptr) < rounded_bytes)) {
     ptr = AllocateFromNextArena(rounded_bytes);
+    CHECK(ptr != nullptr) << "Failed to allocate memory";
   }
   CurrentStats()->RecordAlloc(bytes, kind);
   top_ptr_ = ptr + rounded_bytes;
@@ -115,10 +116,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/scoped_arena_containers.h b/compiler/utils/scoped_arena_containers.h
index 0de7403..df93b27 100644
--- a/compiler/utils/scoped_arena_containers.h
+++ b/compiler/utils/scoped_arena_containers.h
@@ -140,12 +140,15 @@
   const_pointer address(const_reference x) const { return &x; }
 
   pointer allocate(size_type n, ScopedArenaAllocatorAdapter<void>::pointer hint = nullptr) {
+    UNUSED(hint);
     DCHECK_LE(n, max_size());
     DebugStackIndirectTopRef::CheckTop();
     return reinterpret_cast<T*>(arena_stack_->Alloc(n * sizeof(T),
                                                     ArenaAllocatorAdapterKind::Kind()));
   }
   void deallocate(pointer p, size_type n) {
+    UNUSED(p);
+    UNUSED(n);
     DebugStackIndirectTopRef::CheckTop();
   }
 
diff --git a/compiler/utils/scoped_hashtable.h b/compiler/utils/scoped_hashtable.h
deleted file mode 100644
index bf8dd1f..0000000
--- a/compiler/utils/scoped_hashtable.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
-
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stddef.h>
-#include <map>
-#include <list>
-
-#ifndef ART_COMPILER_UTILS_SCOPED_HASHTABLE_H_
-#define ART_COMPILER_UTILS_SCOPED_HASHTABLE_H_
-
-namespace utils {
-template <typename K, typename V>
-class ScopedHashtable {
- public:
-  explicit ScopedHashtable():scopes() {
-  }
-
-  void OpenScope() {
-    scopes.push_front(std::map<K, V>());
-  }
-
-  // Lookups entry K starting from the current (topmost) scope
-  // and returns its value if found or NULL.
-  V Lookup(K k) const {
-    for (typename std::list<std::map<K, V>>::const_iterator scopes_it = scopes.begin();
-        scopes_it != scopes.end(); scopes_it++) {
-      typename std::map<K, V>::const_iterator result_it = (*scopes_it).find(k);
-      if (result_it != (*scopes_it).end()) {
-        return (*result_it).second;
-      }
-    }
-    return NULL;
-  }
-
-  // Adds a new entry in the current (topmost) scope.
-  void Add(K k, V v) {
-    scopes.front().erase(k);
-    scopes.front().insert(std::pair< K, V >(k, v));
-  }
-
-  // Removes the topmost scope.
-  bool CloseScope() {
-    // Added check to uniformly handle undefined behavior
-    // when removing scope and the list of scopes is empty.
-    if (scopes.size() > 0) {
-      scopes.pop_front();
-      return true;
-    }
-    return false;
-  }
-
- private:
-  std::list<std::map<K, V>> scopes;
-};
-}  // namespace utils
-
-#endif  // ART_COMPILER_UTILS_SCOPED_HASHTABLE_H_
diff --git a/compiler/utils/scoped_hashtable_test.cc b/compiler/utils/scoped_hashtable_test.cc
deleted file mode 100644
index 1c843eb..0000000
--- a/compiler/utils/scoped_hashtable_test.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "scoped_hashtable.h"
-
-#include "common_runtime_test.h"
-
-using utils::ScopedHashtable;
-
-namespace art {
-
-class Value {
- public:
-  explicit Value(int v):value_(v) {}
-  int value_;
-};
-
-class ScopedHashtableTest : public testing::Test {};
-
-TEST_F(ScopedHashtableTest, Basics) {
-  ScopedHashtable<int, Value*> sht;
-  // Check table is empty when no scope is open.
-  EXPECT_TRUE(NULL == sht.Lookup(1));
-
-  // Check table is empty when scope open.
-  sht.OpenScope();
-  EXPECT_TRUE(NULL == sht.Lookup(1));
-  // Check table is empty after closing scope.
-  EXPECT_EQ(sht.CloseScope(), true);
-  // Check closing scope on empty table is no-op.
-  EXPECT_EQ(sht.CloseScope(), false);
-  // Check that find in current scope works.
-  sht.OpenScope();
-  sht.Add(1, new Value(1));
-  EXPECT_EQ(sht.Lookup(1)->value_, 1);
-  // Check that updating values in current scope works.
-  sht.Add(1, new Value(2));
-  EXPECT_EQ(sht.Lookup(1)->value_, 2);
-  // Check that find works in previous scope.
-  sht.OpenScope();
-  EXPECT_EQ(sht.Lookup(1)->value_, 2);
-  // Check that shadowing scopes works.
-  sht.Add(1, new Value(3));
-  EXPECT_EQ(sht.Lookup(1)->value_, 3);
-  // Check that having multiple keys work correctly.
-  sht.Add(2, new Value(4));
-  EXPECT_EQ(sht.Lookup(1)->value_, 3);
-  EXPECT_EQ(sht.Lookup(2)->value_, 4);
-  // Check that scope removal works corectly.
-  sht.CloseScope();
-  EXPECT_EQ(sht.Lookup(1)->value_, 2);
-  EXPECT_TRUE(NULL == sht.Lookup(2));
-}
-
-}  // namespace art
diff --git a/compiler/utils/stack_checks.h b/compiler/utils/stack_checks.h
index ce01077..c348f2c 100644
--- a/compiler/utils/stack_checks.h
+++ b/compiler/utils/stack_checks.h
@@ -17,7 +17,7 @@
 #ifndef ART_COMPILER_UTILS_STACK_CHECKS_H_
 #define ART_COMPILER_UTILS_STACK_CHECKS_H_
 
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
 
 namespace art {
 
@@ -34,7 +34,7 @@
 // stack overflow check on method entry.
 //
 // A frame is considered large when it's above kLargeFrameSize.
-static inline bool FrameNeedsStackCheck(size_t size, InstructionSet isa) {
+static inline bool FrameNeedsStackCheck(size_t size, InstructionSet isa ATTRIBUTE_UNUSED) {
   return size >= kLargeFrameSize;
 }
 
diff --git a/compiler/utils/swap_space.cc b/compiler/utils/swap_space.cc
new file mode 100644
index 0000000..325ee4f
--- /dev/null
+++ b/compiler/utils/swap_space.cc
@@ -0,0 +1,211 @@
+/*
+ * 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 "swap_space.h"
+
+#include <algorithm>
+#include <numeric>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "thread-inl.h"
+
+namespace art {
+
+// The chunk size by which the swap file is increased and mapped.
+static constexpr size_t kMininumMapSize = 16 * MB;
+
+static constexpr bool kCheckFreeMaps = false;
+
+template <typename FreeBySizeSet>
+static void DumpFreeMap(const FreeBySizeSet& free_by_size) {
+  size_t last_size = static_cast<size_t>(-1);
+  for (const auto& entry : free_by_size) {
+    if (last_size != entry.first) {
+      last_size = entry.first;
+      LOG(INFO) << "Size " << last_size;
+    }
+    LOG(INFO) << "  0x" << std::hex << entry.second->Start()
+        << " size=" << std::dec << entry.second->size;
+  }
+}
+
+template <typename FreeByStartSet, typename FreeBySizeSet>
+static void RemoveChunk(FreeByStartSet* free_by_start,
+                        FreeBySizeSet* free_by_size,
+                        typename FreeBySizeSet::const_iterator free_by_size_pos) {
+  auto free_by_start_pos = free_by_size_pos->second;
+  free_by_size->erase(free_by_size_pos);
+  free_by_start->erase(free_by_start_pos);
+}
+
+template <typename FreeByStartSet, typename FreeBySizeSet>
+static void InsertChunk(FreeByStartSet* free_by_start,
+                        FreeBySizeSet* free_by_size,
+                        const SpaceChunk& chunk) {
+  DCHECK_NE(chunk.size, 0u);
+  auto insert_result = free_by_start->insert(chunk);
+  DCHECK(insert_result.second);
+  free_by_size->emplace(chunk.size, insert_result.first);
+}
+
+SwapSpace::SwapSpace(int fd, size_t initial_size)
+    : fd_(fd),
+      size_(0),
+      lock_("SwapSpace lock", static_cast<LockLevel>(LockLevel::kDefaultMutexLevel - 1)) {
+  // Assume that the file is unlinked.
+
+  InsertChunk(&free_by_start_, &free_by_size_, NewFileChunk(initial_size));
+}
+
+SwapSpace::~SwapSpace() {
+  // All arenas are backed by the same file. Just close the descriptor.
+  close(fd_);
+}
+
+template <typename FreeByStartSet, typename FreeBySizeSet>
+static size_t CollectFree(const FreeByStartSet& free_by_start, const FreeBySizeSet& free_by_size) {
+  if (free_by_start.size() != free_by_size.size()) {
+    LOG(FATAL) << "Size: " << free_by_start.size() << " vs " << free_by_size.size();
+  }
+
+  // Calculate over free_by_size.
+  size_t sum1 = 0;
+  for (const auto& entry : free_by_size) {
+    sum1 += entry.second->size;
+  }
+
+  // Calculate over free_by_start.
+  size_t sum2 = 0;
+  for (const auto& entry : free_by_start) {
+    sum2 += entry.size;
+  }
+
+  if (sum1 != sum2) {
+    LOG(FATAL) << "Sum: " << sum1 << " vs " << sum2;
+  }
+  return sum1;
+}
+
+void* SwapSpace::Alloc(size_t size) {
+  MutexLock lock(Thread::Current(), lock_);
+  size = RoundUp(size, 8U);
+
+  // Check the free list for something that fits.
+  // TODO: Smarter implementation. Global biggest chunk, ...
+  SpaceChunk old_chunk;
+  auto it = free_by_start_.empty()
+      ? free_by_size_.end()
+      : free_by_size_.lower_bound(FreeBySizeEntry { size, free_by_start_.begin() });
+  if (it != free_by_size_.end()) {
+    old_chunk = *it->second;
+    RemoveChunk(&free_by_start_, &free_by_size_, it);
+  } else {
+    // Not a big enough free chunk, need to increase file size.
+    old_chunk = NewFileChunk(size);
+  }
+
+  void* ret = old_chunk.ptr;
+
+  if (old_chunk.size != size) {
+    // Insert the remainder.
+    SpaceChunk new_chunk = { old_chunk.ptr + size, old_chunk.size - size };
+    InsertChunk(&free_by_start_, &free_by_size_, new_chunk);
+  }
+
+  return ret;
+}
+
+SpaceChunk SwapSpace::NewFileChunk(size_t min_size) {
+#if !defined(__APPLE__)
+  size_t next_part = std::max(RoundUp(min_size, kPageSize), RoundUp(kMininumMapSize, kPageSize));
+  int result = TEMP_FAILURE_RETRY(ftruncate64(fd_, size_ + next_part));
+  if (result != 0) {
+    PLOG(FATAL) << "Unable to increase swap file.";
+  }
+  uint8_t* ptr = reinterpret_cast<uint8_t*>(
+      mmap(nullptr, next_part, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, size_));
+  if (ptr == MAP_FAILED) {
+    LOG(ERROR) << "Unable to mmap new swap file chunk.";
+    LOG(ERROR) << "Current size: " << size_ << " requested: " << next_part << "/" << min_size;
+    LOG(ERROR) << "Free list:";
+    MutexLock lock(Thread::Current(), lock_);
+    DumpFreeMap(free_by_size_);
+    LOG(ERROR) << "In free list: " << CollectFree(free_by_start_, free_by_size_);
+    LOG(FATAL) << "Aborting...";
+  }
+  size_ += next_part;
+  SpaceChunk new_chunk = {ptr, next_part};
+  maps_.push_back(new_chunk);
+  return new_chunk;
+#else
+  UNUSED(min_size, kMininumMapSize);
+  LOG(FATAL) << "No swap file support on the Mac.";
+  UNREACHABLE();
+#endif
+}
+
+// TODO: Full coalescing.
+void SwapSpace::Free(void* ptrV, size_t size) {
+  MutexLock lock(Thread::Current(), lock_);
+  size = RoundUp(size, 8U);
+
+  size_t free_before = 0;
+  if (kCheckFreeMaps) {
+    free_before = CollectFree(free_by_start_, free_by_size_);
+  }
+
+  SpaceChunk chunk = { reinterpret_cast<uint8_t*>(ptrV), size };
+  auto it = free_by_start_.lower_bound(chunk);
+  if (it != free_by_start_.begin()) {
+    auto prev = it;
+    --prev;
+    CHECK_LE(prev->End(), chunk.Start());
+    if (prev->End() == chunk.Start()) {
+      // Merge *prev with this chunk.
+      chunk.size += prev->size;
+      chunk.ptr -= prev->size;
+      auto erase_pos = free_by_size_.find(FreeBySizeEntry { prev->size, prev });
+      DCHECK(erase_pos != free_by_size_.end());
+      RemoveChunk(&free_by_start_, &free_by_size_, erase_pos);
+      // "prev" is invalidated but "it" remains valid.
+    }
+  }
+  if (it != free_by_start_.end()) {
+    CHECK_LE(chunk.End(), it->Start());
+    if (chunk.End() == it->Start()) {
+      // Merge *it with this chunk.
+      chunk.size += it->size;
+      auto erase_pos = free_by_size_.find(FreeBySizeEntry { it->size, it });
+      DCHECK(erase_pos != free_by_size_.end());
+      RemoveChunk(&free_by_start_, &free_by_size_, erase_pos);
+      // "it" is invalidated but we don't need it anymore.
+    }
+  }
+  InsertChunk(&free_by_start_, &free_by_size_, chunk);
+
+  if (kCheckFreeMaps) {
+    size_t free_after = CollectFree(free_by_start_, free_by_size_);
+
+    if (free_after != free_before + size) {
+      DumpFreeMap(free_by_size_);
+      CHECK_EQ(free_after, free_before + size) << "Should be " << size << " difference from " << free_before;
+    }
+  }
+}
+
+}  // namespace art
diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h
new file mode 100644
index 0000000..2d0d77a
--- /dev/null
+++ b/compiler/utils/swap_space.h
@@ -0,0 +1,212 @@
+/*
+ * 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_UTILS_SWAP_SPACE_H_
+#define ART_COMPILER_UTILS_SWAP_SPACE_H_
+
+#include <cstdlib>
+#include <list>
+#include <set>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "mem_map.h"
+#include "utils.h"
+#include "utils/debug_stack.h"
+
+namespace art {
+
+// Chunk of space.
+struct SpaceChunk {
+  uint8_t* ptr;
+  size_t size;
+
+  uintptr_t Start() const {
+    return reinterpret_cast<uintptr_t>(ptr);
+  }
+  uintptr_t End() const {
+    return reinterpret_cast<uintptr_t>(ptr) + size;
+  }
+};
+
+inline bool operator==(const SpaceChunk& lhs, const SpaceChunk& rhs) {
+  return (lhs.size == rhs.size) && (lhs.ptr == rhs.ptr);
+}
+
+class SortChunkByPtr {
+ public:
+  bool operator()(const SpaceChunk& a, const SpaceChunk& b) const {
+    return reinterpret_cast<uintptr_t>(a.ptr) < reinterpret_cast<uintptr_t>(b.ptr);
+  }
+};
+
+// An arena pool that creates arenas backed by an mmaped file.
+class SwapSpace {
+ public:
+  SwapSpace(int fd, size_t initial_size);
+  ~SwapSpace();
+  void* Alloc(size_t size) LOCKS_EXCLUDED(lock_);
+  void Free(void* ptr, size_t size) LOCKS_EXCLUDED(lock_);
+
+  size_t GetSize() {
+    return size_;
+  }
+
+ private:
+  SpaceChunk NewFileChunk(size_t min_size);
+
+  int fd_;
+  size_t size_;
+  std::list<SpaceChunk> maps_;
+
+  // NOTE: Boost.Bimap would be useful for the two following members.
+
+  // Map start of a free chunk to its size.
+  typedef std::set<SpaceChunk, SortChunkByPtr> FreeByStartSet;
+  FreeByStartSet free_by_start_ GUARDED_BY(lock_);
+
+  // Map size to an iterator to free_by_start_'s entry.
+  typedef std::pair<size_t, FreeByStartSet::const_iterator> FreeBySizeEntry;
+  struct FreeBySizeComparator {
+    bool operator()(const FreeBySizeEntry& lhs, const FreeBySizeEntry& rhs) {
+      if (lhs.first != rhs.first) {
+        return lhs.first < rhs.first;
+      } else {
+        return lhs.second->Start() < rhs.second->Start();
+      }
+    }
+  };
+  typedef std::set<FreeBySizeEntry, FreeBySizeComparator> FreeBySizeSet;
+  FreeBySizeSet free_by_size_ GUARDED_BY(lock_);
+
+  mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  DISALLOW_COPY_AND_ASSIGN(SwapSpace);
+};
+
+template <typename T> class SwapAllocator;
+
+template <>
+class SwapAllocator<void> {
+ public:
+  typedef void value_type;
+  typedef void* pointer;
+  typedef const void* const_pointer;
+
+  template <typename U>
+  struct rebind {
+    typedef SwapAllocator<U> other;
+  };
+
+  explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {}
+
+  template <typename U>
+  SwapAllocator(const SwapAllocator<U>& other) : swap_space_(other.swap_space_) {}
+
+  SwapAllocator(const SwapAllocator& other) = default;
+  SwapAllocator& operator=(const SwapAllocator& other) = default;
+  ~SwapAllocator() = default;
+
+ private:
+  SwapSpace* swap_space_;
+
+  template <typename U>
+  friend class SwapAllocator;
+};
+
+template <typename T>
+class SwapAllocator {
+ public:
+  typedef T value_type;
+  typedef T* pointer;
+  typedef T& reference;
+  typedef const T* const_pointer;
+  typedef const T& const_reference;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+
+  template <typename U>
+  struct rebind {
+    typedef SwapAllocator<U> other;
+  };
+
+  explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {}
+
+  template <typename U>
+  SwapAllocator(const SwapAllocator<U>& other) : swap_space_(other.swap_space_) {}
+
+  SwapAllocator(const SwapAllocator& other) = default;
+  SwapAllocator& operator=(const SwapAllocator& other) = default;
+  ~SwapAllocator() = default;
+
+  size_type max_size() const {
+    return static_cast<size_type>(-1) / sizeof(T);
+  }
+
+  pointer address(reference x) const { return &x; }
+  const_pointer address(const_reference x) const { return &x; }
+
+  pointer allocate(size_type n, SwapAllocator<void>::pointer hint ATTRIBUTE_UNUSED = nullptr) {
+    DCHECK_LE(n, max_size());
+    if (swap_space_ == nullptr) {
+      return reinterpret_cast<T*>(malloc(n * sizeof(T)));
+    } else {
+      return reinterpret_cast<T*>(swap_space_->Alloc(n * sizeof(T)));
+    }
+  }
+  void deallocate(pointer p, size_type n) {
+    if (swap_space_ == nullptr) {
+      free(p);
+    } else {
+      swap_space_->Free(p, n * sizeof(T));
+    }
+  }
+
+  void construct(pointer p, const_reference val) {
+    new (static_cast<void*>(p)) value_type(val);
+  }
+  template <class U, class... Args>
+  void construct(U* p, Args&&... args) {
+    ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
+  }
+  void destroy(pointer p) {
+    p->~value_type();
+  }
+
+  inline bool operator==(SwapAllocator const& other) {
+    return swap_space_ == other.swap_space_;
+  }
+  inline bool operator!=(SwapAllocator const& other) {
+    return !operator==(other);
+  }
+
+ private:
+  SwapSpace* swap_space_;
+
+  template <typename U>
+  friend class SwapAllocator;
+};
+
+template <typename T>
+using SwapVector = std::vector<T, SwapAllocator<T>>;
+template <typename T, typename Comparator>
+using SwapSet = std::set<T, Comparator, SwapAllocator<T>>;
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_SWAP_SPACE_H_
diff --git a/compiler/utils/swap_space_test.cc b/compiler/utils/swap_space_test.cc
new file mode 100644
index 0000000..bf50ac3
--- /dev/null
+++ b/compiler/utils/swap_space_test.cc
@@ -0,0 +1,81 @@
+/*
+ * 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 "utils/swap_space.h"
+
+#include <cstdio>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "gtest/gtest.h"
+
+#include "base/unix_file/fd_file.h"
+#include "common_runtime_test.h"
+#include "os.h"
+
+namespace art {
+
+class SwapSpaceTest : public CommonRuntimeTest {
+};
+
+static void SwapTest(bool use_file) {
+  ScratchFile scratch;
+  int fd = scratch.GetFd();
+  unlink(scratch.GetFilename().c_str());
+
+  SwapSpace pool(fd, 1 * MB);
+  SwapAllocator<void> alloc(use_file ? &pool : nullptr);
+
+  SwapVector<int32_t> v(alloc);
+  v.reserve(1000000);
+  for (int32_t i = 0; i < 1000000; ++i) {
+    v.push_back(i);
+    EXPECT_EQ(i, v[i]);
+  }
+
+  SwapVector<int32_t> v2(alloc);
+  v2.reserve(1000000);
+  for (int32_t i = 0; i < 1000000; ++i) {
+    v2.push_back(i);
+    EXPECT_EQ(i, v2[i]);
+  }
+
+  SwapVector<int32_t> v3(alloc);
+  v3.reserve(500000);
+  for (int32_t i = 0; i < 1000000; ++i) {
+    v3.push_back(i);
+    EXPECT_EQ(i, v2[i]);
+  }
+
+  // Verify contents.
+  for (int32_t i = 0; i < 1000000; ++i) {
+    EXPECT_EQ(i, v[i]);
+    EXPECT_EQ(i, v2[i]);
+    EXPECT_EQ(i, v3[i]);
+  }
+
+  scratch.Close();
+}
+
+TEST_F(SwapSpaceTest, Memory) {
+  SwapTest(false);
+}
+
+TEST_F(SwapSpaceTest, Swap) {
+  SwapTest(true);
+}
+
+}  // namespace art
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index f888d46..3f266fe 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -243,6 +243,17 @@
 }
 
 
+void X86Assembler::movw(const Address& dst, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOperandSizeOverride();
+  EmitUint8(0xC7);
+  EmitOperand(0, dst);
+  CHECK(imm.is_uint16() || imm.is_int16());
+  EmitUint8(imm.value() & 0xFF);
+  EmitUint8(imm.value() >> 8);
+}
+
+
 void X86Assembler::leal(Register dst, const Address& src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x8D);
@@ -266,6 +277,14 @@
 }
 
 
+void X86Assembler::movaps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x28);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
 void X86Assembler::movss(XmmRegister dst, const Address& src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF3);
@@ -390,6 +409,13 @@
 }
 
 
+void X86Assembler::fsts(const Address& dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xD9);
+  EmitOperand(2, dst);
+}
+
+
 void X86Assembler::fstps(const Address& dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xD9);
@@ -424,6 +450,27 @@
 }
 
 
+void X86Assembler::psrlq(XmmRegister reg, const Immediate& shift_count) {
+  DCHECK(shift_count.is_uint8());
+
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x73);
+  EmitXmmRegisterOperand(2, reg);
+  EmitUint8(shift_count.value());
+}
+
+
+void X86Assembler::punpckldq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x62);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
 void X86Assembler::addsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
@@ -594,6 +641,23 @@
 }
 
 
+void X86Assembler::ucomiss(XmmRegister a, XmmRegister b) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x2E);
+  EmitXmmRegisterOperand(a, b);
+}
+
+
+void X86Assembler::ucomisd(XmmRegister a, XmmRegister b) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitUint8(0x0F);
+  EmitUint8(0x2E);
+  EmitXmmRegisterOperand(a, b);
+}
+
+
 void X86Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
@@ -662,6 +726,13 @@
 }
 
 
+void X86Assembler::fstl(const Address& dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xDD);
+  EmitOperand(2, dst);
+}
+
+
 void X86Assembler::fstpl(const Address& dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xDD);
@@ -669,6 +740,14 @@
 }
 
 
+void X86Assembler::fstsw() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x9B);
+  EmitUint8(0xDF);
+  EmitUint8(0xE0);
+}
+
+
 void X86Assembler::fnstcw(const Address& dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xD9);
@@ -740,6 +819,20 @@
 }
 
 
+void X86Assembler::fucompp() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xDA);
+  EmitUint8(0xE9);
+}
+
+
+void X86Assembler::fprem() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xD9);
+  EmitUint8(0xF8);
+}
+
+
 void X86Assembler::xchgl(Register dst, Register src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x87);
@@ -854,6 +947,13 @@
 }
 
 
+void X86Assembler::andl(Register reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x23);
+  EmitOperand(reg, address);
+}
+
+
 void X86Assembler::andl(Register dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitComplex(4, Operand(dst), imm);
@@ -867,6 +967,13 @@
 }
 
 
+void X86Assembler::orl(Register reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0B);
+  EmitOperand(reg, address);
+}
+
+
 void X86Assembler::orl(Register dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitComplex(1, Operand(dst), imm);
@@ -879,11 +986,20 @@
   EmitOperand(dst, Operand(src));
 }
 
+
+void X86Assembler::xorl(Register reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x33);
+  EmitOperand(reg, address);
+}
+
+
 void X86Assembler::xorl(Register dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitComplex(6, Operand(dst), imm);
 }
 
+
 void X86Assembler::addl(Register reg, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitComplex(0, Operand(reg), imm);
@@ -1084,7 +1200,8 @@
 }
 
 
-void X86Assembler::shld(Register dst, Register src) {
+void X86Assembler::shld(Register dst, Register src, Register shifter) {
+  DCHECK_EQ(ECX, shifter);
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x0F);
   EmitUint8(0xA5);
@@ -1092,6 +1209,15 @@
 }
 
 
+void X86Assembler::shrd(Register dst, Register src, Register shifter) {
+  DCHECK_EQ(ECX, shifter);
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xAD);
+  EmitRegisterOperand(src, dst);
+}
+
+
 void X86Assembler::negl(Register reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF7);
@@ -1266,45 +1392,19 @@
 }
 
 
+void X86Assembler::LoadLongConstant(XmmRegister dst, int64_t value) {
+  // TODO: Need to have a code constants table.
+  pushl(Immediate(High32Bits(value)));
+  pushl(Immediate(Low32Bits(value)));
+  movsd(dst, Address(ESP, 0));
+  addl(ESP, Immediate(2 * sizeof(int32_t)));
+}
+
+
 void X86Assembler::LoadDoubleConstant(XmmRegister dst, double value) {
   // TODO: Need to have a code constants table.
   int64_t constant = bit_cast<int64_t, double>(value);
-  pushl(Immediate(High32Bits(constant)));
-  pushl(Immediate(Low32Bits(constant)));
-  movsd(dst, Address(ESP, 0));
-  addl(ESP, Immediate(2 * kWordSize));
-}
-
-
-void X86Assembler::FloatNegate(XmmRegister f) {
-  static const struct {
-    uint32_t a;
-    uint32_t b;
-    uint32_t c;
-    uint32_t d;
-  } float_negate_constant __attribute__((aligned(16))) =
-      { 0x80000000, 0x00000000, 0x80000000, 0x00000000 };
-  xorps(f, Address::Absolute(reinterpret_cast<uword>(&float_negate_constant)));
-}
-
-
-void X86Assembler::DoubleNegate(XmmRegister d) {
-  static const struct {
-    uint64_t a;
-    uint64_t b;
-  } double_negate_constant __attribute__((aligned(16))) =
-      {0x8000000000000000LL, 0x8000000000000000LL};
-  xorpd(d, Address::Absolute(reinterpret_cast<uword>(&double_negate_constant)));
-}
-
-
-void X86Assembler::DoubleAbs(XmmRegister reg) {
-  static const struct {
-    uint64_t a;
-    uint64_t b;
-  } double_abs_constant __attribute__((aligned(16))) =
-      {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
-  andpd(reg, Address::Absolute(reinterpret_cast<uword>(&double_abs_constant)));
+  LoadLongConstant(dst, constant);
 }
 
 
@@ -1788,9 +1888,7 @@
 }
 
 void X86Assembler::MemoryBarrier(ManagedRegister) {
-#if ANDROID_SMP != 0
   mfence();
-#endif
 }
 
 void X86Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index ec983d9..3a44ace 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -29,24 +29,23 @@
 namespace art {
 namespace x86 {
 
-class Immediate {
+class Immediate : public ValueObject {
  public:
-  explicit Immediate(int32_t value) : value_(value) {}
+  explicit Immediate(int32_t value_in) : value_(value_in) {}
 
   int32_t value() const { return value_; }
 
   bool is_int8() const { return IsInt(8, value_); }
   bool is_uint8() const { return IsUint(8, value_); }
+  bool is_int16() const { return IsInt(16, value_); }
   bool is_uint16() const { return IsUint(16, value_); }
 
  private:
   const int32_t value_;
-
-  DISALLOW_COPY_AND_ASSIGN(Immediate);
 };
 
 
-class Operand {
+class Operand : public ValueObject {
  public:
   uint8_t mod() const {
     return (encoding_at(0) >> 6) & 3;
@@ -89,16 +88,16 @@
   // Operand can be sub classed (e.g: Address).
   Operand() : length_(0) { }
 
-  void SetModRM(int mod, Register rm) {
-    CHECK_EQ(mod & ~3, 0);
-    encoding_[0] = (mod << 6) | rm;
+  void SetModRM(int mod_in, Register rm_in) {
+    CHECK_EQ(mod_in & ~3, 0);
+    encoding_[0] = (mod_in << 6) | rm_in;
     length_ = 1;
   }
 
-  void SetSIB(ScaleFactor scale, Register index, Register base) {
+  void SetSIB(ScaleFactor scale_in, Register index_in, Register base_in) {
     CHECK_EQ(length_, 1);
-    CHECK_EQ(scale & ~3, 0);
-    encoding_[1] = (scale << 6) | (index << 3) | base;
+    CHECK_EQ(scale_in & ~3, 0);
+    encoding_[1] = (scale_in << 6) | (index_in << 3) | base_in;
     length_ = 2;
   }
 
@@ -115,83 +114,80 @@
   }
 
  private:
-  byte length_;
-  byte encoding_[6];
+  uint8_t length_;
+  uint8_t encoding_[6];
 
   explicit Operand(Register reg) { SetModRM(3, reg); }
 
   // Get the operand encoding byte at the given index.
-  uint8_t encoding_at(int index) const {
-    CHECK_GE(index, 0);
-    CHECK_LT(index, length_);
-    return encoding_[index];
+  uint8_t encoding_at(int index_in) const {
+    CHECK_GE(index_in, 0);
+    CHECK_LT(index_in, length_);
+    return encoding_[index_in];
   }
 
   friend class X86Assembler;
-
-  DISALLOW_COPY_AND_ASSIGN(Operand);
 };
 
 
 class Address : public Operand {
  public:
-  Address(Register base, int32_t disp) {
-    Init(base, disp);
+  Address(Register base_in, int32_t disp) {
+    Init(base_in, disp);
   }
 
-  Address(Register base, Offset disp) {
-    Init(base, disp.Int32Value());
+  Address(Register base_in, Offset disp) {
+    Init(base_in, disp.Int32Value());
   }
 
-  Address(Register base, FrameOffset disp) {
-    CHECK_EQ(base, ESP);
+  Address(Register base_in, FrameOffset disp) {
+    CHECK_EQ(base_in, ESP);
     Init(ESP, disp.Int32Value());
   }
 
-  Address(Register base, MemberOffset disp) {
-    Init(base, disp.Int32Value());
+  Address(Register base_in, MemberOffset disp) {
+    Init(base_in, disp.Int32Value());
   }
 
-  void Init(Register base, int32_t disp) {
-    if (disp == 0 && base != EBP) {
-      SetModRM(0, base);
-      if (base == ESP) SetSIB(TIMES_1, ESP, base);
+  void Init(Register base_in, int32_t disp) {
+    if (disp == 0 && base_in != EBP) {
+      SetModRM(0, base_in);
+      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
     } else if (disp >= -128 && disp <= 127) {
-      SetModRM(1, base);
-      if (base == ESP) SetSIB(TIMES_1, ESP, base);
+      SetModRM(1, base_in);
+      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
       SetDisp8(disp);
     } else {
-      SetModRM(2, base);
-      if (base == ESP) SetSIB(TIMES_1, ESP, base);
+      SetModRM(2, base_in);
+      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
       SetDisp32(disp);
     }
   }
 
-
-  Address(Register index, ScaleFactor scale, int32_t disp) {
-    CHECK_NE(index, ESP);  // Illegal addressing mode.
+  Address(Register index_in, ScaleFactor scale_in, int32_t disp) {
+    CHECK_NE(index_in, ESP);  // Illegal addressing mode.
     SetModRM(0, ESP);
-    SetSIB(scale, index, EBP);
+    SetSIB(scale_in, index_in, EBP);
     SetDisp32(disp);
   }
 
-  Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
-    CHECK_NE(index, ESP);  // Illegal addressing mode.
-    if (disp == 0 && base != EBP) {
+  Address(Register base_in, Register index_in, ScaleFactor scale_in, int32_t disp) {
+    CHECK_NE(index_in, ESP);  // Illegal addressing mode.
+    if (disp == 0 && base_in != EBP) {
       SetModRM(0, ESP);
-      SetSIB(scale, index, base);
+      SetSIB(scale_in, index_in, base_in);
     } else if (disp >= -128 && disp <= 127) {
       SetModRM(1, ESP);
-      SetSIB(scale, index, base);
+      SetSIB(scale_in, index_in, base_in);
       SetDisp8(disp);
     } else {
       SetModRM(2, ESP);
-      SetSIB(scale, index, base);
+      SetSIB(scale_in, index_in, base_in);
       SetDisp32(disp);
     }
   }
 
-  static Address Absolute(uword addr) {
+  static Address Absolute(uintptr_t addr) {
     Address result;
     result.SetModRM(0, EBP);
     result.SetDisp32(addr);
@@ -204,14 +200,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() {}
 
   /*
@@ -251,6 +245,7 @@
   void movsxw(Register dst, const Address& src);
   void movw(Register dst, const Address& src);
   void movw(const Address& dst, Register src);
+  void movw(const Address& dst, const Immediate& imm);
 
   void leal(Register dst, const Address& src);
 
@@ -258,6 +253,7 @@
 
   void setb(Condition condition, Register dst);
 
+  void movaps(XmmRegister dst, XmmRegister src);
   void movss(XmmRegister dst, const Address& src);
   void movss(const Address& dst, XmmRegister src);
   void movss(XmmRegister dst, XmmRegister src);
@@ -278,6 +274,9 @@
   void movsd(const Address& dst, XmmRegister src);
   void movsd(XmmRegister dst, XmmRegister src);
 
+  void psrlq(XmmRegister reg, const Immediate& shift_count);
+  void punpckldq(XmmRegister dst, XmmRegister src);
+
   void addsd(XmmRegister dst, XmmRegister src);
   void addsd(XmmRegister dst, const Address& src);
   void subsd(XmmRegister dst, XmmRegister src);
@@ -303,6 +302,8 @@
 
   void comiss(XmmRegister a, XmmRegister b);
   void comisd(XmmRegister a, XmmRegister b);
+  void ucomiss(XmmRegister a, XmmRegister b);
+  void ucomisd(XmmRegister a, XmmRegister b);
 
   void sqrtsd(XmmRegister dst, XmmRegister src);
   void sqrtss(XmmRegister dst, XmmRegister src);
@@ -316,9 +317,15 @@
 
   void flds(const Address& src);
   void fstps(const Address& dst);
+  void fsts(const Address& dst);
 
   void fldl(const Address& src);
   void fstpl(const Address& dst);
+  void fstl(const Address& dst);
+
+  void fstsw();
+
+  void fucompp();
 
   void fnstcw(const Address& dst);
   void fldcw(const Address& src);
@@ -333,6 +340,7 @@
   void fsin();
   void fcos();
   void fptan();
+  void fprem();
 
   void xchgl(Register dst, Register src);
   void xchgl(Register reg, const Address& address);
@@ -352,12 +360,15 @@
 
   void andl(Register dst, const Immediate& imm);
   void andl(Register dst, Register src);
+  void andl(Register dst, const Address& address);
 
   void orl(Register dst, const Immediate& imm);
   void orl(Register dst, Register src);
+  void orl(Register dst, const Address& address);
 
   void xorl(Register dst, Register src);
   void xorl(Register dst, const Immediate& imm);
+  void xorl(Register dst, const Address& address);
 
   void addl(Register dst, Register src);
   void addl(Register reg, const Immediate& imm);
@@ -404,7 +415,8 @@
   void shrl(Register operand, Register shifter);
   void sarl(Register reg, const Immediate& imm);
   void sarl(Register operand, Register shifter);
-  void shld(Register dst, Register src);
+  void shld(Register dst, Register src, Register shifter);
+  void shrd(Register dst, Register src, Register shifter);
 
   void negl(Register reg);
   void notl(Register reg);
@@ -439,13 +451,9 @@
 
   void AddImmediate(Register reg, const Immediate& imm);
 
+  void LoadLongConstant(XmmRegister dst, int64_t value);
   void LoadDoubleConstant(XmmRegister dst, double value);
 
-  void DoubleNegate(XmmRegister d);
-  void FloatNegate(XmmRegister f);
-
-  void DoubleAbs(XmmRegister reg);
-
   void LockCmpxchgl(const Address& address, Register reg) {
     lock()->cmpxchgl(address, reg);
   }
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 5d8a3b1..fccb510 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -16,7 +16,8 @@
 
 #include "assembler_x86.h"
 
-#include "gtest/gtest.h"
+#include "base/stl_util.h"
+#include "utils/assembler_test.h"
 
 namespace art {
 
@@ -29,4 +30,101 @@
   ASSERT_EQ(static_cast<size_t>(5), buffer.Size());
 }
 
+class AssemblerX86Test : public AssemblerTest<x86::X86Assembler, x86::Register,
+                                              x86::XmmRegister, x86::Immediate> {
+ protected:
+  std::string GetArchitectureString() OVERRIDE {
+    return "x86";
+  }
+
+  std::string GetAssemblerParameters() OVERRIDE {
+    return " --32";
+  }
+
+  std::string GetDisassembleParameters() OVERRIDE {
+    return " -D -bbinary -mi386 --no-show-raw-insn";
+  }
+
+  void SetUpHelpers() OVERRIDE {
+    if (registers_.size() == 0) {
+      registers_.insert(end(registers_),
+                        {  // NOLINT(whitespace/braces)
+                          new x86::Register(x86::EAX),
+                          new x86::Register(x86::EBX),
+                          new x86::Register(x86::ECX),
+                          new x86::Register(x86::EDX),
+                          new x86::Register(x86::EBP),
+                          new x86::Register(x86::ESP),
+                          new x86::Register(x86::ESI),
+                          new x86::Register(x86::EDI)
+                        });
+    }
+
+    if (fp_registers_.size() == 0) {
+      fp_registers_.insert(end(fp_registers_),
+                           {  // NOLINT(whitespace/braces)
+                             new x86::XmmRegister(x86::XMM0),
+                             new x86::XmmRegister(x86::XMM1),
+                             new x86::XmmRegister(x86::XMM2),
+                             new x86::XmmRegister(x86::XMM3),
+                             new x86::XmmRegister(x86::XMM4),
+                             new x86::XmmRegister(x86::XMM5),
+                             new x86::XmmRegister(x86::XMM6),
+                             new x86::XmmRegister(x86::XMM7)
+                           });
+    }
+  }
+
+  void TearDown() OVERRIDE {
+    AssemblerTest::TearDown();
+    STLDeleteElements(&registers_);
+    STLDeleteElements(&fp_registers_);
+  }
+
+  std::vector<x86::Register*> GetRegisters() OVERRIDE {
+    return registers_;
+  }
+
+  std::vector<x86::XmmRegister*> GetFPRegisters() OVERRIDE {
+    return fp_registers_;
+  }
+
+  x86::Immediate CreateImmediate(int64_t imm_value) OVERRIDE {
+    return x86::Immediate(imm_value);
+  }
+
+ private:
+  std::vector<x86::Register*> registers_;
+  std::vector<x86::XmmRegister*> fp_registers_;
+};
+
+
+TEST_F(AssemblerX86Test, Movl) {
+  GetAssembler()->movl(x86::EAX, x86::EBX);
+  const char* expected = "mov %ebx, %eax\n";
+  DriverStr(expected, "movl");
+}
+
+TEST_F(AssemblerX86Test, psrlq) {
+  GetAssembler()->psrlq(x86::XMM0, CreateImmediate(32));
+  const char* expected = "psrlq $0x20, %xmm0\n";
+  DriverStr(expected, "psrlq");
+}
+
+TEST_F(AssemblerX86Test, punpckldq) {
+  GetAssembler()->punpckldq(x86::XMM0, x86::XMM1);
+  const char* expected = "punpckldq %xmm1, %xmm0\n";
+  DriverStr(expected, "punpckldq");
+}
+
+TEST_F(AssemblerX86Test, LoadLongConstant) {
+  GetAssembler()->LoadLongConstant(x86::XMM0, 51);
+  const char* expected =
+      "push $0x0\n"
+      "push $0x33\n"
+      "movsd 0(%esp), %xmm0\n"
+      "add $8, %esp\n";
+  DriverStr(expected, "LoadLongConstant");
+}
+
 }  // namespace art
diff --git a/compiler/utils/x86/constants_x86.h b/compiler/utils/x86/constants_x86.h
index 45c3834..2dfb65c 100644
--- a/compiler/utils/x86/constants_x86.h
+++ b/compiler/utils/x86/constants_x86.h
@@ -96,7 +96,8 @@
   kZero         = kEqual,
   kNotZero      = kNotEqual,
   kNegative     = kSign,
-  kPositive     = kNotSign
+  kPositive     = kNotSign,
+  kUnordered    = kParityEven
 };
 
 
diff --git a/compiler/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc
index 021fe88..69e6fce 100644
--- a/compiler/utils/x86/managed_register_x86.cc
+++ b/compiler/utils/x86/managed_register_x86.cc
@@ -51,7 +51,11 @@
 };
 
 std::ostream& operator<<(std::ostream& os, const RegisterPair& reg) {
-  os << X86ManagedRegister::FromRegisterPair(reg);
+  if (reg == kNoRegisterPair) {
+    os << "kNoRegisterPair";
+  } else {
+    os << X86ManagedRegister::FromRegisterPair(reg);
+  }
   return os;
 }
 
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index f432e66..5afa603 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -120,6 +120,7 @@
 
 
 void X86_64Assembler::movl(CpuRegister dst, const Immediate& imm) {
+  CHECK(imm.is_int32());
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst);
   EmitUint8(0xB8 + dst.LowBits());
@@ -183,6 +184,20 @@
   EmitImmediate(imm);
 }
 
+
+void X86_64Assembler::cmov(Condition c, CpuRegister dst, CpuRegister src) {
+  cmov(c, dst, src, true);
+}
+
+void X86_64Assembler::cmov(Condition c, CpuRegister dst, CpuRegister src, bool is64bit) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex(false, is64bit, dst.NeedsRex(), false, src.NeedsRex());
+  EmitUint8(0x0F);
+  EmitUint8(0x40 + c);
+  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+
 void X86_64Assembler::movzxb(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalByteRegNormalizingRex32(dst, src);
@@ -234,6 +249,7 @@
 
 void X86_64Assembler::movb(const Address& dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst);
   EmitUint8(0xC6);
   EmitOperand(Register::RAX, dst);
   CHECK(imm.is_int8());
@@ -291,6 +307,18 @@
 }
 
 
+void X86_64Assembler::movw(const Address& dst, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOperandSizeOverride();
+  EmitOptionalRex32(dst);
+  EmitUint8(0xC7);
+  EmitOperand(Register::RAX, dst);
+  CHECK(imm.is_uint16() || imm.is_int16());
+  EmitUint8(imm.value() & 0xFF);
+  EmitUint8(imm.value() >> 8);
+}
+
+
 void X86_64Assembler::leaq(CpuRegister dst, const Address& src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRex64(dst, src);
@@ -299,6 +327,15 @@
 }
 
 
+void X86_64Assembler::movaps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x28);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
 void X86_64Assembler::movss(XmmRegister dst, const Address& src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF3);
@@ -322,27 +359,50 @@
 void X86_64Assembler::movss(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF3);
-  EmitOptionalRex32(dst, src);
+  EmitOptionalRex32(src, dst);  // Movss is MR encoding instead of the usual RM.
   EmitUint8(0x0F);
   EmitUint8(0x11);
   EmitXmmRegisterOperand(src.LowBits(), dst);
 }
 
 
+void X86_64Assembler::movsxd(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x63);
+  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+
+void X86_64Assembler::movsxd(CpuRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst);
+  EmitUint8(0x63);
+  EmitOperand(dst.LowBits(), src);
+}
+
+
 void X86_64Assembler::movd(XmmRegister dst, CpuRegister src) {
+  movd(dst, src, true);
+}
+
+void X86_64Assembler::movd(CpuRegister dst, XmmRegister src) {
+  movd(dst, src, true);
+}
+
+void X86_64Assembler::movd(XmmRegister dst, CpuRegister src, bool is64bit) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
-  EmitOptionalRex32(dst, src);
+  EmitOptionalRex(false, is64bit, dst.NeedsRex(), false, src.NeedsRex());
   EmitUint8(0x0F);
   EmitUint8(0x6E);
   EmitOperand(dst.LowBits(), Operand(src));
 }
 
-
-void X86_64Assembler::movd(CpuRegister dst, XmmRegister src) {
+void X86_64Assembler::movd(CpuRegister dst, XmmRegister src, bool is64bit) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
-  EmitOptionalRex32(src, dst);
+  EmitOptionalRex(false, is64bit, src.NeedsRex(), false, dst.NeedsRex());
   EmitUint8(0x0F);
   EmitUint8(0x7E);
   EmitOperand(src.LowBits(), Operand(dst));
@@ -436,6 +496,13 @@
 }
 
 
+void X86_64Assembler::fsts(const Address& dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xD9);
+  EmitOperand(2, dst);
+}
+
+
 void X86_64Assembler::fstps(const Address& dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xD9);
@@ -466,7 +533,7 @@
 void X86_64Assembler::movsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
-  EmitOptionalRex32(dst, src);
+  EmitOptionalRex32(src, dst);  // Movsd is MR encoding instead of the usual RM.
   EmitUint8(0x0F);
   EmitUint8(0x11);
   EmitXmmRegisterOperand(src.LowBits(), dst);
@@ -554,9 +621,19 @@
 
 
 void X86_64Assembler::cvtsi2ss(XmmRegister dst, CpuRegister src) {
+  cvtsi2ss(dst, src, false);
+}
+
+
+void X86_64Assembler::cvtsi2ss(XmmRegister dst, CpuRegister src, bool is64bit) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF3);
-  EmitOptionalRex32(dst, src);
+  if (is64bit) {
+    // Emit a REX.W prefix if the operand size is 64 bits.
+    EmitRex64(dst, src);
+  } else {
+    EmitOptionalRex32(dst, src);
+  }
   EmitUint8(0x0F);
   EmitUint8(0x2A);
   EmitOperand(dst.LowBits(), Operand(src));
@@ -564,9 +641,19 @@
 
 
 void X86_64Assembler::cvtsi2sd(XmmRegister dst, CpuRegister src) {
+  cvtsi2sd(dst, src, false);
+}
+
+
+void X86_64Assembler::cvtsi2sd(XmmRegister dst, CpuRegister src, bool is64bit) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
-  EmitOptionalRex32(dst, src);
+  if (is64bit) {
+    // Emit a REX.W prefix if the operand size is 64 bits.
+    EmitRex64(dst, src);
+  } else {
+    EmitOptionalRex32(dst, src);
+  }
   EmitUint8(0x0F);
   EmitUint8(0x2A);
   EmitOperand(dst.LowBits(), Operand(src));
@@ -604,9 +691,19 @@
 
 
 void X86_64Assembler::cvttss2si(CpuRegister dst, XmmRegister src) {
+  cvttss2si(dst, src, false);
+}
+
+
+void X86_64Assembler::cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF3);
-  EmitOptionalRex32(dst, src);
+  if (is64bit) {
+    // Emit a REX.W prefix if the operand size is 64 bits.
+    EmitRex64(dst, src);
+  } else {
+    EmitOptionalRex32(dst, src);
+  }
   EmitUint8(0x0F);
   EmitUint8(0x2C);
   EmitXmmRegisterOperand(dst.LowBits(), src);
@@ -614,9 +711,19 @@
 
 
 void X86_64Assembler::cvttsd2si(CpuRegister dst, XmmRegister src) {
+  cvttsd2si(dst, src, false);
+}
+
+
+void X86_64Assembler::cvttsd2si(CpuRegister dst, XmmRegister src, bool is64bit) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
-  EmitOptionalRex32(dst, src);
+  if (is64bit) {
+    // Emit a REX.W prefix if the operand size is 64 bits.
+    EmitRex64(dst, src);
+  } else {
+    EmitOptionalRex32(dst, src);
+  }
   EmitUint8(0x0F);
   EmitUint8(0x2C);
   EmitXmmRegisterOperand(dst.LowBits(), src);
@@ -661,6 +768,24 @@
   EmitXmmRegisterOperand(a.LowBits(), b);
 }
 
+void X86_64Assembler::ucomiss(XmmRegister a, XmmRegister b) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(a, b);
+  EmitUint8(0x0F);
+  EmitUint8(0x2E);
+  EmitXmmRegisterOperand(a.LowBits(), b);
+}
+
+
+void X86_64Assembler::ucomisd(XmmRegister a, XmmRegister b) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(a, b);
+  EmitUint8(0x0F);
+  EmitUint8(0x2E);
+  EmitXmmRegisterOperand(a.LowBits(), b);
+}
+
 
 void X86_64Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -729,6 +854,39 @@
   EmitOperand(dst.LowBits(), src);
 }
 
+void X86_64Assembler::andpd(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x54);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::andps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x54);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::orpd(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x66);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x56);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::orps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x56);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
+}
 
 void X86_64Assembler::fldl(const Address& src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -737,6 +895,13 @@
 }
 
 
+void X86_64Assembler::fstl(const Address& dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xDD);
+  EmitOperand(2, dst);
+}
+
+
 void X86_64Assembler::fstpl(const Address& dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xDD);
@@ -744,6 +909,14 @@
 }
 
 
+void X86_64Assembler::fstsw() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x9B);
+  EmitUint8(0xDF);
+  EmitUint8(0xE0);
+}
+
+
 void X86_64Assembler::fnstcw(const Address& dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xD9);
@@ -814,20 +987,62 @@
   EmitUint8(0xF2);
 }
 
+void X86_64Assembler::fucompp() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xDA);
+  EmitUint8(0xE9);
+}
+
+
+void X86_64Assembler::fprem() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xD9);
+  EmitUint8(0xF8);
+}
+
 
 void X86_64Assembler::xchgl(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitOptionalRex32(dst, src);
+  // There is a short version for rax.
+  // It's a bit awkward, as CpuRegister has a const field, so assignment and thus swapping doesn't
+  // work.
+  const bool src_rax = src.AsRegister() == RAX;
+  const bool dst_rax = dst.AsRegister() == RAX;
+  if (src_rax || dst_rax) {
+    EmitOptionalRex32(src_rax ? dst : src);
+    EmitUint8(0x90 + (src_rax ? dst.LowBits() : src.LowBits()));
+    return;
+  }
+
+  // General case.
+  EmitOptionalRex32(src, dst);
   EmitUint8(0x87);
-  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+  EmitRegisterOperand(src.LowBits(), dst.LowBits());
 }
 
 
 void X86_64Assembler::xchgq(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitRex64(dst, src);
+  // There is a short version for rax.
+  // It's a bit awkward, as CpuRegister has a const field, so assignment and thus swapping doesn't
+  // work.
+  const bool src_rax = src.AsRegister() == RAX;
+  const bool dst_rax = dst.AsRegister() == RAX;
+  if (src_rax || dst_rax) {
+    // If src == target, emit a nop instead.
+    if (src_rax && dst_rax) {
+      EmitUint8(0x90);
+    } else {
+      EmitRex64(src_rax ? dst : src);
+      EmitUint8(0x90 + (src_rax ? dst.LowBits() : src.LowBits()));
+    }
+    return;
+  }
+
+  // General case.
+  EmitRex64(src, dst);
   EmitUint8(0x87);
-  EmitOperand(dst.LowBits(), Operand(src));
+  EmitRegisterOperand(src.LowBits(), dst.LowBits());
 }
 
 
@@ -870,6 +1085,21 @@
 }
 
 
+void X86_64Assembler::cmpl(const Address& address, CpuRegister reg) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x39);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
+void X86_64Assembler::cmpl(const Address& address, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(address);
+  EmitComplex(7, address, imm);
+}
+
+
 void X86_64Assembler::cmpq(CpuRegister reg0, CpuRegister reg1) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRex64(reg0, reg1);
@@ -894,6 +1124,14 @@
 }
 
 
+void X86_64Assembler::cmpq(const Address& address, const Immediate& imm) {
+  CHECK(imm.is_int32());  // cmpq only supports 32b immediate.
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(address);
+  EmitComplex(7, address, imm);
+}
+
+
 void X86_64Assembler::addl(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst, src);
@@ -910,21 +1148,6 @@
 }
 
 
-void X86_64Assembler::cmpl(const Address& address, CpuRegister reg) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitOptionalRex32(reg, address);
-  EmitUint8(0x39);
-  EmitOperand(reg.LowBits(), address);
-}
-
-
-void X86_64Assembler::cmpl(const Address& address, const Immediate& imm) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitOptionalRex32(address);
-  EmitComplex(7, address, imm);
-}
-
-
 void X86_64Assembler::testl(CpuRegister reg1, CpuRegister reg2) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(reg1, reg2);
@@ -933,6 +1156,14 @@
 }
 
 
+void X86_64Assembler::testl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x85);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
 void X86_64Assembler::testl(CpuRegister reg, const Immediate& immediate) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   // For registers that have a byte variant (RAX, RBX, RCX, and RDX)
@@ -959,6 +1190,14 @@
 }
 
 
+void X86_64Assembler::testq(CpuRegister reg1, CpuRegister reg2) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(reg1, reg2);
+  EmitUint8(0x85);
+  EmitRegisterOperand(reg1.LowBits(), reg2.LowBits());
+}
+
+
 void X86_64Assembler::testq(CpuRegister reg, const Address& address) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRex64(reg);
@@ -975,6 +1214,14 @@
 }
 
 
+void X86_64Assembler::andl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x23);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
 void X86_64Assembler::andl(CpuRegister dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst);
@@ -990,6 +1237,14 @@
 }
 
 
+void X86_64Assembler::andq(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x23);
+  EmitOperand(dst.LowBits(), Operand(src));
+}
+
+
 void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst, src);
@@ -998,6 +1253,14 @@
 }
 
 
+void X86_64Assembler::orl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x0B);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
 void X86_64Assembler::orl(CpuRegister dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst);
@@ -1005,6 +1268,14 @@
 }
 
 
+void X86_64Assembler::orq(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x0B);
+  EmitOperand(dst.LowBits(), Operand(src));
+}
+
+
 void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst, src);
@@ -1013,6 +1284,21 @@
 }
 
 
+void X86_64Assembler::xorl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x33);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
+void X86_64Assembler::xorl(CpuRegister dst, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst);
+  EmitComplex(6, Operand(dst), imm);
+}
+
+
 void X86_64Assembler::xorq(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRex64(dst, src);
@@ -1181,6 +1467,13 @@
 }
 
 
+void X86_64Assembler::cqo() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64();
+  EmitUint8(0x99);
+}
+
+
 void X86_64Assembler::idivl(CpuRegister reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(reg);
@@ -1189,6 +1482,14 @@
 }
 
 
+void X86_64Assembler::idivq(CpuRegister reg) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(reg);
+  EmitUint8(0xF7);
+  EmitUint8(0xF8 | reg.LowBits());
+}
+
+
 void X86_64Assembler::imull(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst, src);
@@ -1197,13 +1498,25 @@
   EmitOperand(dst.LowBits(), Operand(src));
 }
 
-
 void X86_64Assembler::imull(CpuRegister reg, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitOptionalRex32(reg);
-  EmitUint8(0x69);
-  EmitOperand(reg.LowBits(), Operand(reg));
-  EmitImmediate(imm);
+  CHECK(imm.is_int32());  // imull only supports 32b immediate.
+
+  EmitOptionalRex32(reg, reg);
+
+  // See whether imm can be represented as a sign-extended 8bit value.
+  int32_t v32 = static_cast<int32_t>(imm.value());
+  if (IsInt32(8, v32)) {
+    // Sign-extension works.
+    EmitUint8(0x6B);
+    EmitOperand(reg.LowBits(), Operand(reg));
+    EmitUint8(static_cast<uint8_t>(v32 & 0xFF));
+  } else {
+    // Not representable, use full immediate.
+    EmitUint8(0x69);
+    EmitOperand(reg.LowBits(), Operand(reg));
+    EmitImmediate(imm);
+  }
 }
 
 
@@ -1216,6 +1529,46 @@
 }
 
 
+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, reg);
+
+  // See whether imm can be represented as a sign-extended 8bit value.
+  int64_t v64 = imm.value();
+  if (IsInt64(8, v64)) {
+    // Sign-extension works.
+    EmitUint8(0x6B);
+    EmitOperand(reg.LowBits(), Operand(reg));
+    EmitUint8(static_cast<uint8_t>(v64 & 0xFF));
+  } else {
+    // Not representable, use full immediate.
+    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);
@@ -1248,14 +1601,23 @@
 }
 
 
-
 void X86_64Assembler::shll(CpuRegister reg, const Immediate& imm) {
   EmitGenericShift(false, 4, reg, imm);
 }
 
 
+void X86_64Assembler::shlq(CpuRegister reg, const Immediate& imm) {
+  EmitGenericShift(true, 4, reg, imm);
+}
+
+
 void X86_64Assembler::shll(CpuRegister operand, CpuRegister shifter) {
-  EmitGenericShift(4, operand, shifter);
+  EmitGenericShift(false, 4, operand, shifter);
+}
+
+
+void X86_64Assembler::shlq(CpuRegister operand, CpuRegister shifter) {
+  EmitGenericShift(true, 4, operand, shifter);
 }
 
 
@@ -1270,7 +1632,12 @@
 
 
 void X86_64Assembler::shrl(CpuRegister operand, CpuRegister shifter) {
-  EmitGenericShift(5, operand, shifter);
+  EmitGenericShift(false, 5, operand, shifter);
+}
+
+
+void X86_64Assembler::shrq(CpuRegister operand, CpuRegister shifter) {
+  EmitGenericShift(true, 5, operand, shifter);
 }
 
 
@@ -1280,7 +1647,17 @@
 
 
 void X86_64Assembler::sarl(CpuRegister operand, CpuRegister shifter) {
-  EmitGenericShift(7, operand, shifter);
+  EmitGenericShift(false, 7, operand, shifter);
+}
+
+
+void X86_64Assembler::sarq(CpuRegister reg, const Immediate& imm) {
+  EmitGenericShift(true, 7, reg, imm);
+}
+
+
+void X86_64Assembler::sarq(CpuRegister operand, CpuRegister shifter) {
+  EmitGenericShift(true, 7, operand, shifter);
 }
 
 
@@ -1292,6 +1669,14 @@
 }
 
 
+void X86_64Assembler::negq(CpuRegister reg) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(reg);
+  EmitUint8(0xF7);
+  EmitOperand(3, Operand(reg));
+}
+
+
 void X86_64Assembler::notl(CpuRegister reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(reg);
@@ -1300,6 +1685,14 @@
 }
 
 
+void X86_64Assembler::notq(CpuRegister reg) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(reg);
+  EmitUint8(0xF7);
+  EmitOperand(2, Operand(reg));
+}
+
+
 void X86_64Assembler::enter(const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xC8);
@@ -1461,6 +1854,20 @@
   EmitUint8(0xC0 + dst.LowBits());
 }
 
+void X86_64Assembler::bswapl(CpuRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex(false, false, false, false, dst.NeedsRex());
+  EmitUint8(0x0F);
+  EmitUint8(0xC8 + dst.LowBits());
+}
+
+void X86_64Assembler::bswapq(CpuRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex(false, true, false, false, dst.NeedsRex());
+  EmitUint8(0x0F);
+  EmitUint8(0xC8 + dst.LowBits());
+}
+
 
 void X86_64Assembler::LoadDoubleConstant(XmmRegister dst, double value) {
   // TODO: Need to have a code constants table.
@@ -1468,39 +1875,7 @@
   pushq(Immediate(High32Bits(constant)));
   pushq(Immediate(Low32Bits(constant)));
   movsd(dst, Address(CpuRegister(RSP), 0));
-  addq(CpuRegister(RSP), Immediate(2 * kWordSize));
-}
-
-
-void X86_64Assembler::FloatNegate(XmmRegister f) {
-  static const struct {
-    uint32_t a;
-    uint32_t b;
-    uint32_t c;
-    uint32_t d;
-  } float_negate_constant __attribute__((aligned(16))) =
-      { 0x80000000, 0x00000000, 0x80000000, 0x00000000 };
-  xorps(f, Address::Absolute(reinterpret_cast<uword>(&float_negate_constant)));
-}
-
-
-void X86_64Assembler::DoubleNegate(XmmRegister d) {
-  static const struct {
-    uint64_t a;
-    uint64_t b;
-  } double_negate_constant __attribute__((aligned(16))) =
-      {0x8000000000000000LL, 0x8000000000000000LL};
-  xorpd(d, Address::Absolute(reinterpret_cast<uword>(&double_negate_constant)));
-}
-
-
-void X86_64Assembler::DoubleAbs(XmmRegister reg) {
-  static const struct {
-    uint64_t a;
-    uint64_t b;
-  } double_abs_constant __attribute__((aligned(16))) =
-      {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
-  andpd(reg, Address::Absolute(reinterpret_cast<uword>(&double_abs_constant)));
+  addq(CpuRegister(RSP), Immediate(2 * sizeof(intptr_t)));
 }
 
 
@@ -1599,6 +1974,8 @@
   CHECK(imm.is_int8());
   if (wide) {
     EmitRex64(reg);
+  } else {
+    EmitOptionalRex32(reg);
   }
   if (imm.value() == 1) {
     EmitUint8(0xD1);
@@ -1611,11 +1988,17 @@
 }
 
 
-void X86_64Assembler::EmitGenericShift(int reg_or_opcode,
+void X86_64Assembler::EmitGenericShift(bool wide,
+                                       int reg_or_opcode,
                                        CpuRegister operand,
                                        CpuRegister shifter) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   CHECK_EQ(shifter.AsRegister(), RCX);
+  if (wide) {
+    EmitRex64(operand);
+  } else {
+    EmitOptionalRex32(operand);
+  }
   EmitUint8(0xD3);
   EmitOperand(reg_or_opcode, Operand(operand));
 }
@@ -1691,14 +2074,32 @@
   }
 }
 
+void X86_64Assembler::EmitRex64() {
+  EmitOptionalRex(false, true, false, false, false);
+}
+
 void X86_64Assembler::EmitRex64(CpuRegister reg) {
   EmitOptionalRex(false, true, false, false, reg.NeedsRex());
 }
 
+void X86_64Assembler::EmitRex64(const Operand& operand) {
+  uint8_t rex = operand.rex();
+  rex |= 0x48;  // REX.W000
+  EmitUint8(rex);
+}
+
 void X86_64Assembler::EmitRex64(CpuRegister dst, CpuRegister src) {
   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, XmmRegister 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()) {
@@ -2141,9 +2542,7 @@
 }
 
 void X86_64Assembler::MemoryBarrier(ManagedRegister) {
-#if ANDROID_SMP != 0
   mfence();
-#endif
 }
 
 void X86_64Assembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 1fd65c2..e24fa1b 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -36,14 +36,15 @@
 //
 // 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) {}
+  explicit Immediate(int64_t value_in) : value_(value_in) {}
 
   int64_t value() const { return value_; }
 
   bool is_int8() const { return IsInt(8, value_); }
   bool is_uint8() const { return IsUint(8, value_); }
+  bool is_int16() const { return IsInt(16, value_); }
   bool is_uint16() const { return IsUint(16, value_); }
   bool is_int32() const {
     // This does not work on 32b machines: return IsInt(32, value_);
@@ -53,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;
@@ -106,26 +105,26 @@
   // Operand can be sub classed (e.g: Address).
   Operand() : rex_(0), length_(0) { }
 
-  void SetModRM(uint8_t mod, CpuRegister rm) {
-    CHECK_EQ(mod & ~3, 0);
-    if (rm.NeedsRex()) {
+  void SetModRM(uint8_t mod_in, CpuRegister rm_in) {
+    CHECK_EQ(mod_in & ~3, 0);
+    if (rm_in.NeedsRex()) {
       rex_ |= 0x41;  // REX.000B
     }
-    encoding_[0] = (mod << 6) | rm.LowBits();
+    encoding_[0] = (mod_in << 6) | rm_in.LowBits();
     length_ = 1;
   }
 
-  void SetSIB(ScaleFactor scale, CpuRegister index, CpuRegister base) {
+  void SetSIB(ScaleFactor scale_in, CpuRegister index_in, CpuRegister base_in) {
     CHECK_EQ(length_, 1);
-    CHECK_EQ(scale & ~3, 0);
-    if (base.NeedsRex()) {
+    CHECK_EQ(scale_in & ~3, 0);
+    if (base_in.NeedsRex()) {
       rex_ |= 0x41;  // REX.000B
     }
-    if (index.NeedsRex()) {
+    if (index_in.NeedsRex()) {
       rex_ |= 0x42;  // REX.00X0
     }
-    encoding_[1] = (scale << 6) | (static_cast<uint8_t>(index.LowBits()) << 3) |
-        static_cast<uint8_t>(base.LowBits());
+    encoding_[1] = (scale_in << 6) | (static_cast<uint8_t>(index_in.LowBits()) << 3) |
+        static_cast<uint8_t>(base_in.LowBits());
     length_ = 2;
   }
 
@@ -149,84 +148,82 @@
   explicit Operand(CpuRegister reg) : rex_(0), length_(0) { SetModRM(3, reg); }
 
   // Get the operand encoding byte at the given index.
-  uint8_t encoding_at(int index) const {
-    CHECK_GE(index, 0);
-    CHECK_LT(index, length_);
-    return encoding_[index];
+  uint8_t encoding_at(int index_in) const {
+    CHECK_GE(index_in, 0);
+    CHECK_LT(index_in, length_);
+    return encoding_[index_in];
   }
 
   friend class X86_64Assembler;
-
-  DISALLOW_COPY_AND_ASSIGN(Operand);
 };
 
 
 class Address : public Operand {
  public:
-  Address(CpuRegister base, int32_t disp) {
-    Init(base, disp);
+  Address(CpuRegister base_in, int32_t disp) {
+    Init(base_in, disp);
   }
 
-  Address(CpuRegister base, Offset disp) {
-    Init(base, disp.Int32Value());
+  Address(CpuRegister base_in, Offset disp) {
+    Init(base_in, disp.Int32Value());
   }
 
-  Address(CpuRegister base, FrameOffset disp) {
-    CHECK_EQ(base.AsRegister(), RSP);
+  Address(CpuRegister base_in, FrameOffset disp) {
+    CHECK_EQ(base_in.AsRegister(), RSP);
     Init(CpuRegister(RSP), disp.Int32Value());
   }
 
-  Address(CpuRegister base, MemberOffset disp) {
-    Init(base, disp.Int32Value());
+  Address(CpuRegister base_in, MemberOffset disp) {
+    Init(base_in, disp.Int32Value());
   }
 
-  void Init(CpuRegister base, int32_t disp) {
-    if (disp == 0 && base.AsRegister() != RBP) {
-      SetModRM(0, base);
-      if (base.AsRegister() == RSP) {
-        SetSIB(TIMES_1, CpuRegister(RSP), base);
+  void Init(CpuRegister base_in, int32_t disp) {
+    if (disp == 0 && base_in.LowBits() != RBP) {
+      SetModRM(0, base_in);
+      if (base_in.AsRegister() == RSP) {
+        SetSIB(TIMES_1, CpuRegister(RSP), base_in);
       }
     } else if (disp >= -128 && disp <= 127) {
-      SetModRM(1, base);
-      if (base.AsRegister() == RSP) {
-        SetSIB(TIMES_1, CpuRegister(RSP), base);
+      SetModRM(1, base_in);
+      if (base_in.AsRegister() == RSP) {
+        SetSIB(TIMES_1, CpuRegister(RSP), base_in);
       }
       SetDisp8(disp);
     } else {
-      SetModRM(2, base);
-      if (base.AsRegister() == RSP) {
-        SetSIB(TIMES_1, CpuRegister(RSP), base);
+      SetModRM(2, base_in);
+      if (base_in.AsRegister() == RSP) {
+        SetSIB(TIMES_1, CpuRegister(RSP), base_in);
       }
       SetDisp32(disp);
     }
   }
 
 
-  Address(CpuRegister index, ScaleFactor scale, int32_t disp) {
-    CHECK_NE(index.AsRegister(), RSP);  // Illegal addressing mode.
+  Address(CpuRegister index_in, ScaleFactor scale_in, int32_t disp) {
+    CHECK_NE(index_in.AsRegister(), RSP);  // Illegal addressing mode.
     SetModRM(0, CpuRegister(RSP));
-    SetSIB(scale, index, CpuRegister(RBP));
+    SetSIB(scale_in, index_in, CpuRegister(RBP));
     SetDisp32(disp);
   }
 
-  Address(CpuRegister base, CpuRegister index, ScaleFactor scale, int32_t disp) {
-    CHECK_NE(index.AsRegister(), RSP);  // Illegal addressing mode.
-    if (disp == 0 && base.AsRegister() != RBP) {
+  Address(CpuRegister base_in, CpuRegister index_in, ScaleFactor scale_in, int32_t disp) {
+    CHECK_NE(index_in.AsRegister(), RSP);  // Illegal addressing mode.
+    if (disp == 0 && base_in.LowBits() != RBP) {
       SetModRM(0, CpuRegister(RSP));
-      SetSIB(scale, index, base);
+      SetSIB(scale_in, index_in, base_in);
     } else if (disp >= -128 && disp <= 127) {
       SetModRM(1, CpuRegister(RSP));
-      SetSIB(scale, index, base);
+      SetSIB(scale_in, index_in, base_in);
       SetDisp8(disp);
     } else {
       SetModRM(2, CpuRegister(RSP));
-      SetSIB(scale, index, base);
+      SetSIB(scale_in, index_in, base_in);
       SetDisp32(disp);
     }
   }
 
   // If no_rip is true then the Absolute address isn't RIP relative.
-  static Address Absolute(uword addr, bool no_rip = false) {
+  static Address Absolute(uintptr_t addr, bool no_rip = false) {
     Address result;
     if (no_rip) {
       result.SetModRM(0, CpuRegister(RSP));
@@ -246,8 +243,6 @@
 
  private:
   Address() {}
-
-  DISALLOW_COPY_AND_ASSIGN(Address);
 };
 
 
@@ -281,6 +276,9 @@
   void movl(const Address& dst, CpuRegister src);
   void movl(const Address& dst, const Immediate& imm);
 
+  void cmov(Condition c, CpuRegister dst, CpuRegister src);  // This is the 64b version.
+  void cmov(Condition c, CpuRegister dst, CpuRegister src, bool is64bit);
+
   void movzxb(CpuRegister dst, CpuRegister src);
   void movzxb(CpuRegister dst, const Address& src);
   void movsxb(CpuRegister dst, CpuRegister src);
@@ -295,15 +293,23 @@
   void movsxw(CpuRegister dst, const Address& src);
   void movw(CpuRegister dst, const Address& src);
   void movw(const Address& dst, CpuRegister src);
+  void movw(const Address& dst, const Immediate& imm);
 
   void leaq(CpuRegister dst, const Address& src);
 
+  void movaps(XmmRegister dst, XmmRegister src);
+
   void movss(XmmRegister dst, const Address& src);
   void movss(const Address& dst, XmmRegister src);
   void movss(XmmRegister dst, XmmRegister src);
 
-  void movd(XmmRegister dst, CpuRegister src);
-  void movd(CpuRegister dst, XmmRegister src);
+  void movsxd(CpuRegister dst, CpuRegister src);
+  void movsxd(CpuRegister dst, const Address& src);
+
+  void movd(XmmRegister dst, CpuRegister src);  // Note: this is the r64 version, formally movq.
+  void movd(CpuRegister dst, XmmRegister src);  // Note: this is the r64 version, formally movq.
+  void movd(XmmRegister dst, CpuRegister src, bool is64bit);
+  void movd(CpuRegister dst, XmmRegister src, bool is64bit);
 
   void addss(XmmRegister dst, XmmRegister src);
   void addss(XmmRegister dst, const Address& src);
@@ -327,22 +333,28 @@
   void divsd(XmmRegister dst, XmmRegister src);
   void divsd(XmmRegister dst, const Address& src);
 
-  void cvtsi2ss(XmmRegister dst, CpuRegister src);
-  void cvtsi2sd(XmmRegister dst, CpuRegister src);
+  void cvtsi2ss(XmmRegister dst, CpuRegister src);  // Note: this is the r/m32 version.
+  void cvtsi2ss(XmmRegister dst, CpuRegister src, bool is64bit);
+  void cvtsi2sd(XmmRegister dst, CpuRegister src);  // Note: this is the r/m32 version.
+  void cvtsi2sd(XmmRegister dst, CpuRegister src, bool is64bit);
 
-  void cvtss2si(CpuRegister dst, XmmRegister src);
+  void cvtss2si(CpuRegister dst, XmmRegister src);  // Note: this is the r32 version.
   void cvtss2sd(XmmRegister dst, XmmRegister src);
 
-  void cvtsd2si(CpuRegister dst, XmmRegister src);
+  void cvtsd2si(CpuRegister dst, XmmRegister src);  // Note: this is the r32 version.
   void cvtsd2ss(XmmRegister dst, XmmRegister src);
 
-  void cvttss2si(CpuRegister dst, XmmRegister src);
-  void cvttsd2si(CpuRegister dst, XmmRegister src);
+  void cvttss2si(CpuRegister dst, XmmRegister src);  // Note: this is the r32 version.
+  void cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit);
+  void cvttsd2si(CpuRegister dst, XmmRegister src);  // Note: this is the r32 version.
+  void cvttsd2si(CpuRegister dst, XmmRegister src, bool is64bit);
 
   void cvtdq2pd(XmmRegister dst, XmmRegister src);
 
   void comiss(XmmRegister a, XmmRegister b);
   void comisd(XmmRegister a, XmmRegister b);
+  void ucomiss(XmmRegister a, XmmRegister b);
+  void ucomisd(XmmRegister a, XmmRegister b);
 
   void sqrtsd(XmmRegister dst, XmmRegister src);
   void sqrtss(XmmRegister dst, XmmRegister src);
@@ -353,12 +365,23 @@
   void xorps(XmmRegister dst, XmmRegister src);
 
   void andpd(XmmRegister dst, const Address& src);
+  void andpd(XmmRegister dst, XmmRegister src);
+  void andps(XmmRegister dst, XmmRegister src);
+
+  void orpd(XmmRegister dst, XmmRegister src);
+  void orps(XmmRegister dst, XmmRegister src);
 
   void flds(const Address& src);
   void fstps(const Address& dst);
+  void fsts(const Address& dst);
 
   void fldl(const Address& src);
   void fstpl(const Address& dst);
+  void fstl(const Address& dst);
+
+  void fstsw();
+
+  void fucompp();
 
   void fnstcw(const Address& dst);
   void fldcw(const Address& src);
@@ -373,6 +396,7 @@
   void fsin();
   void fcos();
   void fptan();
+  void fprem();
 
   void xchgl(CpuRegister dst, CpuRegister src);
   void xchgq(CpuRegister dst, CpuRegister src);
@@ -389,20 +413,29 @@
   void cmpq(CpuRegister reg0, CpuRegister reg1);
   void cmpq(CpuRegister reg0, const Immediate& imm);
   void cmpq(CpuRegister reg0, const Address& address);
+  void cmpq(const Address& address, const Immediate& imm);
 
   void testl(CpuRegister reg1, CpuRegister reg2);
+  void testl(CpuRegister reg, const Address& address);
   void testl(CpuRegister reg, const Immediate& imm);
 
+  void testq(CpuRegister reg1, CpuRegister reg2);
   void testq(CpuRegister reg, const Address& address);
 
   void andl(CpuRegister dst, const Immediate& imm);
   void andl(CpuRegister dst, CpuRegister src);
+  void andl(CpuRegister reg, const Address& address);
   void andq(CpuRegister dst, const Immediate& imm);
+  void andq(CpuRegister dst, CpuRegister src);
 
   void orl(CpuRegister dst, const Immediate& imm);
   void orl(CpuRegister dst, CpuRegister src);
+  void orl(CpuRegister reg, const Address& address);
+  void orq(CpuRegister dst, CpuRegister src);
 
   void xorl(CpuRegister dst, CpuRegister src);
+  void xorl(CpuRegister dst, const Immediate& imm);
+  void xorl(CpuRegister reg, const Address& address);
   void xorq(CpuRegister dst, const Immediate& imm);
   void xorq(CpuRegister dst, CpuRegister src);
 
@@ -425,13 +458,19 @@
   void subq(CpuRegister dst, const Address& address);
 
   void cdq();
+  void cqo();
 
   void idivl(CpuRegister reg);
+  void idivq(CpuRegister reg);
 
   void imull(CpuRegister dst, CpuRegister src);
   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);
 
@@ -445,10 +484,18 @@
   void sarl(CpuRegister reg, const Immediate& imm);
   void sarl(CpuRegister operand, CpuRegister shifter);
 
+  void shlq(CpuRegister reg, const Immediate& imm);
+  void shlq(CpuRegister operand, CpuRegister shifter);
   void shrq(CpuRegister reg, const Immediate& imm);
+  void shrq(CpuRegister operand, CpuRegister shifter);
+  void sarq(CpuRegister reg, const Immediate& imm);
+  void sarq(CpuRegister operand, CpuRegister shifter);
 
   void negl(CpuRegister reg);
+  void negq(CpuRegister reg);
+
   void notl(CpuRegister reg);
+  void notq(CpuRegister reg);
 
   void enter(const Immediate& imm);
   void leave();
@@ -475,6 +522,9 @@
 
   void setcc(Condition condition, CpuRegister dst);
 
+  void bswapl(CpuRegister dst);
+  void bswapq(CpuRegister dst);
+
   //
   // Macros for High-level operations.
   //
@@ -483,11 +533,6 @@
 
   void LoadDoubleConstant(XmmRegister dst, double value);
 
-  void DoubleNegate(XmmRegister d);
-  void FloatNegate(XmmRegister f);
-
-  void DoubleAbs(XmmRegister reg);
-
   void LockCmpxchgl(const Address& address, CpuRegister reg) {
     lock()->cmpxchgl(address, reg);
   }
@@ -639,7 +684,7 @@
   void EmitNearLabelLink(Label* label);
 
   void EmitGenericShift(bool wide, int rm, CpuRegister reg, const Immediate& imm);
-  void EmitGenericShift(int rm, CpuRegister operand, CpuRegister shifter);
+  void EmitGenericShift(bool wide, int rm, CpuRegister operand, CpuRegister shifter);
 
   // If any input is not false, output the necessary rex prefix.
   void EmitOptionalRex(bool force, bool w, bool r, bool x, bool b);
@@ -655,9 +700,13 @@
   void EmitOptionalRex32(XmmRegister dst, const Operand& operand);
 
   // Emit a REX.W prefix plus necessary register bit encodings.
+  void EmitRex64();
   void EmitRex64(CpuRegister reg);
+  void EmitRex64(const Operand& operand);
   void EmitRex64(CpuRegister dst, CpuRegister src);
   void EmitRex64(CpuRegister dst, const Operand& operand);
+  void EmitRex64(XmmRegister dst, CpuRegister src);
+  void EmitRex64(CpuRegister dst, XmmRegister src);
 
   // Emit a REX prefix to normalize byte registers plus necessary register bit encodings.
   void EmitOptionalByteRegNormalizingRex32(CpuRegister dst, CpuRegister src);
@@ -678,13 +727,17 @@
 }
 
 inline void X86_64Assembler::EmitInt64(int64_t value) {
-  buffer_.Emit<int64_t>(value);
+  // Write this 64-bit value as two 32-bit words for alignment reasons
+  // (this is essentially when running on ARM, which does not allow
+  // 64-bit unaligned accesses).  We assume little-endianness here.
+  EmitInt32(Low32Bits(value));
+  EmitInt32(High32Bits(value));
 }
 
 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..6df4144 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -16,8 +16,13 @@
 
 #include "assembler_x86_64.h"
 
+#include <inttypes.h>
+#include <map>
+#include <random>
+
 #include "base/stl_util.h"
 #include "utils/assembler_test.h"
+#include "utils.h"
 
 namespace art {
 
@@ -30,8 +35,88 @@
   ASSERT_EQ(static_cast<size_t>(5), buffer.Size());
 }
 
+#ifdef HAVE_ANDROID_OS
+static constexpr size_t kRandomIterations = 1000;  // Devices might be puny, don't stress them...
+#else
+static constexpr size_t kRandomIterations = 100000;  // Hosts are pretty powerful.
+#endif
+
+TEST(AssemblerX86_64, SignExtension) {
+  // 32bit.
+  for (int32_t i = 0; i < 128; i++) {
+    EXPECT_TRUE(IsInt32(8, i)) << i;
+  }
+  for (int32_t i = 128; i < 255; i++) {
+    EXPECT_FALSE(IsInt32(8, i)) << i;
+  }
+  // Do some higher ones randomly.
+  std::random_device rd;
+  std::default_random_engine e1(rd());
+  std::uniform_int_distribution<int32_t> uniform_dist(256, INT32_MAX);
+  for (size_t i = 0; i < kRandomIterations; i++) {
+    int32_t value = uniform_dist(e1);
+    EXPECT_FALSE(IsInt32(8, value)) << value;
+  }
+
+  // Negative ones.
+  for (int32_t i = -1; i >= -128; i--) {
+    EXPECT_TRUE(IsInt32(8, i)) << i;
+  }
+
+  for (int32_t i = -129; i > -256; i--) {
+    EXPECT_FALSE(IsInt32(8, i)) << i;
+  }
+
+  // Do some lower ones randomly.
+  std::uniform_int_distribution<int32_t> uniform_dist2(INT32_MIN, -256);
+  for (size_t i = 0; i < 100; i++) {
+    int32_t value = uniform_dist2(e1);
+    EXPECT_FALSE(IsInt32(8, value)) << value;
+  }
+
+  // 64bit.
+  for (int64_t i = 0; i < 128; i++) {
+    EXPECT_TRUE(IsInt64(8, i)) << i;
+  }
+  for (int32_t i = 128; i < 255; i++) {
+    EXPECT_FALSE(IsInt64(8, i)) << i;
+  }
+  // Do some higher ones randomly.
+  std::uniform_int_distribution<int64_t> uniform_dist3(256, INT64_MAX);
+  for (size_t i = 0; i < 100; i++) {
+    int64_t value = uniform_dist3(e1);
+    EXPECT_FALSE(IsInt64(8, value)) << value;
+  }
+
+  // Negative ones.
+  for (int64_t i = -1; i >= -128; i--) {
+    EXPECT_TRUE(IsInt64(8, i)) << i;
+  }
+
+  for (int64_t i = -129; i > -256; i--) {
+    EXPECT_FALSE(IsInt64(8, i)) << i;
+  }
+
+  // Do some lower ones randomly.
+  std::uniform_int_distribution<int64_t> uniform_dist4(INT64_MIN, -256);
+  for (size_t i = 0; i < kRandomIterations; i++) {
+    int64_t value = uniform_dist4(e1);
+    EXPECT_FALSE(IsInt64(8, value)) << value;
+  }
+}
+
+struct X86_64CpuRegisterCompare {
+    bool operator()(const x86_64::CpuRegister& a, const x86_64::CpuRegister& b) const {
+        return a.AsRegister() < b.AsRegister();
+    }
+};
+
 class AssemblerX86_64Test : public AssemblerTest<x86_64::X86_64Assembler, x86_64::CpuRegister,
-                                                 x86_64::Immediate> {
+                                                 x86_64::XmmRegister, x86_64::Immediate> {
+ public:
+  typedef AssemblerTest<x86_64::X86_64Assembler, x86_64::CpuRegister,
+                        x86_64::XmmRegister, x86_64::Immediate> Base;
+
  protected:
   // Get the typically used name for this architecture, e.g., aarch64, x86-64, ...
   std::string GetArchitectureString() OVERRIDE {
@@ -60,24 +145,71 @@
       registers_.push_back(new x86_64::CpuRegister(x86_64::R13));
       registers_.push_back(new x86_64::CpuRegister(x86_64::R14));
       registers_.push_back(new x86_64::CpuRegister(x86_64::R15));
+
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RAX), "eax");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RBX), "ebx");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RCX), "ecx");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RDX), "edx");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RBP), "ebp");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RSP), "esp");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RSI), "esi");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::RDI), "edi");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R8), "r8d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R9), "r9d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R10), "r10d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R11), "r11d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R12), "r12d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R13), "r13d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R14), "r14d");
+      secondary_register_names_.emplace(x86_64::CpuRegister(x86_64::R15), "r15d");
+
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM0));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM1));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM2));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM3));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM4));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM5));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM6));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM7));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM8));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM9));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM10));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM11));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM12));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM13));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM14));
+      fp_registers_.push_back(new x86_64::XmmRegister(x86_64::XMM15));
     }
   }
 
   void TearDown() OVERRIDE {
     AssemblerTest::TearDown();
     STLDeleteElements(&registers_);
+    STLDeleteElements(&fp_registers_);
   }
 
   std::vector<x86_64::CpuRegister*> GetRegisters() OVERRIDE {
     return registers_;
   }
 
-  x86_64::Immediate* CreateImmediate(int64_t imm_value) OVERRIDE {
-    return new x86_64::Immediate(imm_value);
+  std::vector<x86_64::XmmRegister*> GetFPRegisters() OVERRIDE {
+    return fp_registers_;
+  }
+
+  x86_64::Immediate CreateImmediate(int64_t imm_value) OVERRIDE {
+    return x86_64::Immediate(imm_value);
+  }
+
+  std::string GetSecondaryRegisterName(const x86_64::CpuRegister& reg) OVERRIDE {
+    CHECK(secondary_register_names_.find(reg) != secondary_register_names_.end());
+    return secondary_register_names_[reg];
   }
 
  private:
   std::vector<x86_64::CpuRegister*> registers_;
+  std::map<x86_64::CpuRegister, std::string, X86_64CpuRegisterCompare> secondary_register_names_;
+
+  std::vector<x86_64::XmmRegister*> fp_registers_;
 };
 
 
@@ -94,7 +226,6 @@
   DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, 4U, "pushq ${imm}"), "pushqi");
 }
 
-
 TEST_F(AssemblerX86_64Test, MovqRegs) {
   DriverStr(RepeatRR(&x86_64::X86_64Assembler::movq, "movq %{reg2}, %{reg1}"), "movq");
 }
@@ -103,6 +234,13 @@
   DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, 8U, "movq ${imm}, %{reg}"), "movqi");
 }
 
+TEST_F(AssemblerX86_64Test, MovlRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::movl, "mov %{reg2}, %{reg1}"), "movl");
+}
+
+TEST_F(AssemblerX86_64Test, MovlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::movl, 4U, "mov ${imm}, %{reg}"), "movli");
+}
 
 TEST_F(AssemblerX86_64Test, AddqRegs) {
   DriverStr(RepeatRR(&x86_64::X86_64Assembler::addq, "addq %{reg2}, %{reg1}"), "addq");
@@ -112,6 +250,35 @@
   DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi");
 }
 
+TEST_F(AssemblerX86_64Test, AddlRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::addl, "add %{reg2}, %{reg1}"), "addl");
+}
+
+TEST_F(AssemblerX86_64Test, AddlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::addl, 4U, "add ${imm}, %{reg}"), "addli");
+}
+
+TEST_F(AssemblerX86_64Test, ImulqRegs) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::imulq, "imulq %{reg2}, %{reg1}"), "imulq");
+}
+
+TEST_F(AssemblerX86_64Test, ImulqImm) {
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::imulq, 4U, "imulq ${imm}, %{reg}, %{reg}"),
+            "imulqi");
+}
+
+TEST_F(AssemblerX86_64Test, ImullRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::imull, "imul %{reg2}, %{reg1}"), "imull");
+}
+
+TEST_F(AssemblerX86_64Test, ImullImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::imull, 4U, "imull ${imm}, %{reg}, %{reg}"),
+            "imulli");
+}
+
+TEST_F(AssemblerX86_64Test, Mull) {
+  DriverStr(Repeatr(&x86_64::X86_64Assembler::mull, "mull %{reg}"), "mull");
+}
 
 TEST_F(AssemblerX86_64Test, SubqRegs) {
   DriverStr(RepeatRR(&x86_64::X86_64Assembler::subq, "subq %{reg2}, %{reg1}"), "subq");
@@ -121,31 +288,263 @@
   DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, 4U, "subq ${imm}, %{reg}"), "subqi");
 }
 
+TEST_F(AssemblerX86_64Test, SublRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::subl, "sub %{reg2}, %{reg1}"), "subl");
+}
+
+TEST_F(AssemblerX86_64Test, SublImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::subl, 4U, "sub ${imm}, %{reg}"), "subli");
+}
+
+// Shll only allows CL as the shift count.
+std::string shll_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+  x86_64::CpuRegister shifter(x86_64::RCX);
+  for (auto reg : registers) {
+    assembler->shll(*reg, shifter);
+    str << "shll %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
+  }
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, ShllReg) {
+  DriverFn(&shll_fn, "shll");
+}
+
+TEST_F(AssemblerX86_64Test, ShllImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::shll, 1U, "shll ${imm}, %{reg}"), "shlli");
+}
+
+// Shlq only allows CL as the shift count.
+std::string shlq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+  x86_64::CpuRegister shifter(x86_64::RCX);
+  for (auto reg : registers) {
+    assembler->shlq(*reg, shifter);
+    str << "shlq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+  }
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, ShlqReg) {
+  DriverFn(&shlq_fn, "shlq");
+}
+
+TEST_F(AssemblerX86_64Test, ShlqImm) {
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::shlq, 1U, "shlq ${imm}, %{reg}"), "shlqi");
+}
+
+// Shrl only allows CL as the shift count.
+std::string shrl_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+  x86_64::CpuRegister shifter(x86_64::RCX);
+  for (auto reg : registers) {
+    assembler->shrl(*reg, shifter);
+    str << "shrl %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
+  }
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, ShrlReg) {
+  DriverFn(&shrl_fn, "shrl");
+}
+
+TEST_F(AssemblerX86_64Test, ShrlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::shrl, 1U, "shrl ${imm}, %{reg}"), "shrli");
+}
+
+// Shrq only allows CL as the shift count.
+std::string shrq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+  x86_64::CpuRegister shifter(x86_64::RCX);
+  for (auto reg : registers) {
+    assembler->shrq(*reg, shifter);
+    str << "shrq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+  }
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, ShrqReg) {
+  DriverFn(&shrq_fn, "shrq");
+}
+
+TEST_F(AssemblerX86_64Test, ShrqImm) {
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::shrq, 1U, "shrq ${imm}, %{reg}"), "shrqi");
+}
+
+// Sarl only allows CL as the shift count.
+std::string sarl_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+  x86_64::CpuRegister shifter(x86_64::RCX);
+  for (auto reg : registers) {
+    assembler->sarl(*reg, shifter);
+    str << "sarl %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
+  }
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, SarlReg) {
+  DriverFn(&sarl_fn, "sarl");
+}
+
+TEST_F(AssemblerX86_64Test, SarlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::sarl, 1U, "sarl ${imm}, %{reg}"), "sarli");
+}
+
+// Sarq only allows CL as the shift count.
+std::string sarq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+  x86_64::CpuRegister shifter(x86_64::RCX);
+  for (auto reg : registers) {
+    assembler->sarq(*reg, shifter);
+    str << "sarq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+  }
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, SarqReg) {
+  DriverFn(&sarq_fn, "sarq");
+}
+
+TEST_F(AssemblerX86_64Test, SarqImm) {
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::sarq, 1U, "sarq ${imm}, %{reg}"), "sarqi");
+}
 
 TEST_F(AssemblerX86_64Test, CmpqRegs) {
   DriverStr(RepeatRR(&x86_64::X86_64Assembler::cmpq, "cmpq %{reg2}, %{reg1}"), "cmpq");
 }
 
+TEST_F(AssemblerX86_64Test, CmpqImm) {
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::cmpq, 4U  /* cmpq only supports 32b imm */,
+                     "cmpq ${imm}, %{reg}"), "cmpqi");
+}
+
+TEST_F(AssemblerX86_64Test, CmplRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::cmpl, "cmp %{reg2}, %{reg1}"), "cmpl");
+}
+
+TEST_F(AssemblerX86_64Test, CmplImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::cmpl, 4U, "cmpl ${imm}, %{reg}"), "cmpli");
+}
+
+TEST_F(AssemblerX86_64Test, Testl) {
+  // Note: uses different order for GCC than usual. This makes GCC happy, and doesn't have an
+  // impact on functional correctness.
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::testl, "testl %{reg1}, %{reg2}"), "testl");
+}
+
+TEST_F(AssemblerX86_64Test, Negq) {
+  DriverStr(RepeatR(&x86_64::X86_64Assembler::negq, "negq %{reg}"), "negq");
+}
+
+TEST_F(AssemblerX86_64Test, Negl) {
+  DriverStr(Repeatr(&x86_64::X86_64Assembler::negl, "negl %{reg}"), "negl");
+}
+
+TEST_F(AssemblerX86_64Test, Notq) {
+  DriverStr(RepeatR(&x86_64::X86_64Assembler::notq, "notq %{reg}"), "notq");
+}
+
+TEST_F(AssemblerX86_64Test, Notl) {
+  DriverStr(Repeatr(&x86_64::X86_64Assembler::notl, "notl %{reg}"), "notl");
+}
+
+TEST_F(AssemblerX86_64Test, AndqRegs) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::andq, "andq %{reg2}, %{reg1}"), "andq");
+}
+
+TEST_F(AssemblerX86_64Test, AndqImm) {
+  DriverStr(RepeatRI(&x86_64::X86_64Assembler::andq, 4U  /* andq only supports 32b imm */,
+                     "andq ${imm}, %{reg}"), "andqi");
+}
+
+TEST_F(AssemblerX86_64Test, AndlRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::andl, "andl %{reg2}, %{reg1}"), "andl");
+}
+
+TEST_F(AssemblerX86_64Test, AndlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::andl, 4U, "andl ${imm}, %{reg}"), "andli");
+}
+
+TEST_F(AssemblerX86_64Test, OrqRegs) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::orq, "orq %{reg2}, %{reg1}"), "orq");
+}
+
+TEST_F(AssemblerX86_64Test, OrlRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::orl, "orl %{reg2}, %{reg1}"), "orl");
+}
+
+TEST_F(AssemblerX86_64Test, OrlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::orl, 4U, "orl ${imm}, %{reg}"), "orli");
+}
+
+TEST_F(AssemblerX86_64Test, XorqRegs) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::xorq, "xorq %{reg2}, %{reg1}"), "xorq");
+}
 
 TEST_F(AssemblerX86_64Test, XorqImm) {
   DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi");
 }
 
+TEST_F(AssemblerX86_64Test, XorlRegs) {
+  DriverStr(Repeatrr(&x86_64::X86_64Assembler::xorl, "xor %{reg2}, %{reg1}"), "xorl");
+}
+
+TEST_F(AssemblerX86_64Test, XorlImm) {
+  DriverStr(Repeatri(&x86_64::X86_64Assembler::xorl, 4U, "xor ${imm}, %{reg}"), "xorli");
+}
+
+TEST_F(AssemblerX86_64Test, Xchgq) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::xchgq, "xchgq %{reg2}, %{reg1}"), "xchgq");
+}
+
+TEST_F(AssemblerX86_64Test, Xchgl) {
+  // Test is disabled because GCC generates 0x87 0xC0 for xchgl eax, eax. All other cases are the
+  // same. Anyone know why it doesn't emit a simple 0x90? It does so for xchgq rax, rax...
+  // DriverStr(Repeatrr(&x86_64::X86_64Assembler::xchgl, "xchgl %{reg2}, %{reg1}"), "xchgl");
+}
+
 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));
   GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
       x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
   GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
       x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
   GetAssembler()->movl(x86_64::CpuRegister(x86_64::R8), x86_64::Address(
       x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), 0));
+  GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
   const char* expected =
-    "movl %R11d, %R8d\n"
-    "movl %R11d, %EAX\n"
     "movl 0xc(%RDI,%RBX,4), %EAX\n"
     "movl 0xc(%RDI,%R9,4), %EAX\n"
-    "movl 0xc(%RDI,%R9,4), %R8d\n";
+    "movl 0xc(%RDI,%R9,4), %R8d\n"
+    "movl (%R13), %EAX\n"
+    "movl (%R13,%R9,1), %EAX\n";
 
   DriverStr(expected, "movl");
 }
@@ -157,8 +556,233 @@
   DriverStr(expected, "movw");
 }
 
+TEST_F(AssemblerX86_64Test, Movsxd) {
+  DriverStr(RepeatRr(&x86_64::X86_64Assembler::movsxd, "movsxd %{reg2}, %{reg1}"), "movsxd");
+}
 
-std::string setcc_test_fn(x86_64::X86_64Assembler* assembler) {
+///////////////////
+// FP Operations //
+///////////////////
+
+TEST_F(AssemblerX86_64Test, Movaps) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps");
+}
+
+TEST_F(AssemblerX86_64Test, Movss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::movss, "movss %{reg2}, %{reg1}"), "movss");
+}
+
+TEST_F(AssemblerX86_64Test, Movsd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::movsd, "movsd %{reg2}, %{reg1}"), "movsd");
+}
+
+TEST_F(AssemblerX86_64Test, Movd1) {
+  DriverStr(RepeatFR(&x86_64::X86_64Assembler::movd, "movd %{reg2}, %{reg1}"), "movd.1");
+}
+
+TEST_F(AssemblerX86_64Test, Movd2) {
+  DriverStr(RepeatRF(&x86_64::X86_64Assembler::movd, "movd %{reg2}, %{reg1}"), "movd.2");
+}
+
+TEST_F(AssemblerX86_64Test, Addss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::addss, "addss %{reg2}, %{reg1}"), "addss");
+}
+
+TEST_F(AssemblerX86_64Test, Addsd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::addsd, "addsd %{reg2}, %{reg1}"), "addsd");
+}
+
+TEST_F(AssemblerX86_64Test, Subss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::subss, "subss %{reg2}, %{reg1}"), "subss");
+}
+
+TEST_F(AssemblerX86_64Test, Subsd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::subsd, "subsd %{reg2}, %{reg1}"), "subsd");
+}
+
+TEST_F(AssemblerX86_64Test, Mulss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulss, "mulss %{reg2}, %{reg1}"), "mulss");
+}
+
+TEST_F(AssemblerX86_64Test, Mulsd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::mulsd, "mulsd %{reg2}, %{reg1}"), "mulsd");
+}
+
+TEST_F(AssemblerX86_64Test, Divss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::divss, "divss %{reg2}, %{reg1}"), "divss");
+}
+
+TEST_F(AssemblerX86_64Test, Divsd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::divsd, "divsd %{reg2}, %{reg1}"), "divsd");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtsi2ss) {
+  DriverStr(RepeatFr(&x86_64::X86_64Assembler::cvtsi2ss, "cvtsi2ss %{reg2}, %{reg1}"), "cvtsi2ss");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtsi2sd) {
+  DriverStr(RepeatFr(&x86_64::X86_64Assembler::cvtsi2sd, "cvtsi2sd %{reg2}, %{reg1}"), "cvtsi2sd");
+}
+
+
+TEST_F(AssemblerX86_64Test, Cvtss2si) {
+  DriverStr(RepeatrF(&x86_64::X86_64Assembler::cvtss2si, "cvtss2si %{reg2}, %{reg1}"), "cvtss2si");
+}
+
+
+TEST_F(AssemblerX86_64Test, Cvtss2sd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::cvtss2sd, "cvtss2sd %{reg2}, %{reg1}"), "cvtss2sd");
+}
+
+
+TEST_F(AssemblerX86_64Test, Cvtsd2si) {
+  DriverStr(RepeatrF(&x86_64::X86_64Assembler::cvtsd2si, "cvtsd2si %{reg2}, %{reg1}"), "cvtsd2si");
+}
+
+TEST_F(AssemblerX86_64Test, Cvttss2si) {
+  DriverStr(RepeatrF(&x86_64::X86_64Assembler::cvttss2si, "cvttss2si %{reg2}, %{reg1}"),
+            "cvttss2si");
+}
+
+TEST_F(AssemblerX86_64Test, Cvttsd2si) {
+  DriverStr(RepeatrF(&x86_64::X86_64Assembler::cvttsd2si, "cvttsd2si %{reg2}, %{reg1}"),
+            "cvttsd2si");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtsd2ss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::cvtsd2ss, "cvtsd2ss %{reg2}, %{reg1}"), "cvtsd2ss");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtdq2pd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::cvtdq2pd, "cvtdq2pd %{reg2}, %{reg1}"), "cvtdq2pd");
+}
+
+TEST_F(AssemblerX86_64Test, Comiss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::comiss, "comiss %{reg2}, %{reg1}"), "comiss");
+}
+
+TEST_F(AssemblerX86_64Test, Comisd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::comisd, "comisd %{reg2}, %{reg1}"), "comisd");
+}
+
+TEST_F(AssemblerX86_64Test, Ucomiss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::ucomiss, "ucomiss %{reg2}, %{reg1}"), "ucomiss");
+}
+
+TEST_F(AssemblerX86_64Test, Ucomisd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::ucomisd, "ucomisd %{reg2}, %{reg1}"), "ucomisd");
+}
+
+TEST_F(AssemblerX86_64Test, Sqrtss) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::sqrtss, "sqrtss %{reg2}, %{reg1}"), "sqrtss");
+}
+
+TEST_F(AssemblerX86_64Test, Sqrtsd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::sqrtsd, "sqrtsd %{reg2}, %{reg1}"), "sqrtsd");
+}
+
+TEST_F(AssemblerX86_64Test, Xorps) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::xorps, "xorps %{reg2}, %{reg1}"), "xorps");
+}
+
+TEST_F(AssemblerX86_64Test, Xorpd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::xorpd, "xorpd %{reg2}, %{reg1}"), "xorpd");
+}
+
+TEST_F(AssemblerX86_64Test, Andps) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::andps, "andps %{reg2}, %{reg1}"), "andps");
+}
+
+TEST_F(AssemblerX86_64Test, Andpd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::andpd, "andpd %{reg2}, %{reg1}"), "andpd");
+}
+
+TEST_F(AssemblerX86_64Test, Orps) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::orps, "orps %{reg2}, %{reg1}"), "orps");
+}
+
+TEST_F(AssemblerX86_64Test, Orpd) {
+  DriverStr(RepeatFF(&x86_64::X86_64Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd");
+}
+
+// X87
+
+std::string x87_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
+                   x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  assembler->fincstp();
+  str << "fincstp\n";
+
+  assembler->fsin();
+  str << "fsin\n";
+
+  assembler->fcos();
+  str << "fcos\n";
+
+  assembler->fptan();
+  str << "fptan\n";
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, X87) {
+  DriverFn(&x87_fn, "x87");
+}
+
+////////////////
+// CALL / JMP //
+////////////////
+
+TEST_F(AssemblerX86_64Test, Call) {
+  DriverStr(RepeatR(&x86_64::X86_64Assembler::call, "call *%{reg}"), "call");
+}
+
+TEST_F(AssemblerX86_64Test, Jmp) {
+  DriverStr(RepeatR(&x86_64::X86_64Assembler::jmp, "jmp *%{reg}"), "jmp");
+}
+
+TEST_F(AssemblerX86_64Test, Enter) {
+  DriverStr(RepeatI(&x86_64::X86_64Assembler::enter, 2U  /* 16b immediate */, "enter ${imm}, $0",
+                    true  /* Only non-negative number */), "enter");
+}
+
+TEST_F(AssemblerX86_64Test, RetImm) {
+  DriverStr(RepeatI(&x86_64::X86_64Assembler::ret, 2U  /* 16b immediate */, "ret ${imm}",
+                    true  /* Only non-negative number */), "reti");
+}
+
+std::string ret_and_leave_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
+                             x86_64::X86_64Assembler* assembler) {
+  std::ostringstream str;
+
+  assembler->ret();
+  str << "ret\n";
+
+  assembler->leave();
+  str << "leave\n";
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, RetAndLeave) {
+  DriverFn(&ret_and_leave_fn, "retleave");
+}
+
+//////////
+// MISC //
+//////////
+
+TEST_F(AssemblerX86_64Test, Bswapl) {
+  DriverStr(Repeatr(&x86_64::X86_64Assembler::bswapl, "bswap %{reg}"), "bswapl");
+}
+
+TEST_F(AssemblerX86_64Test, Bswapq) {
+  DriverStr(RepeatR(&x86_64::X86_64Assembler::bswapq, "bswap %{reg}"), "bswapq");
+}
+
+std::string setcc_test_fn(AssemblerX86_64Test::Base* assembler_test,
+                          x86_64::X86_64Assembler* assembler) {
   // From Condition
   /*
   kOverflow     =  0,
@@ -180,23 +804,7 @@
   std::string suffixes[15] = { "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "pe", "po",
                                "l", "ge", "le" };
 
-  std::vector<x86_64::CpuRegister*> registers;
-  registers.push_back(new x86_64::CpuRegister(x86_64::RAX));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RBX));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RCX));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RDX));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RBP));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RSP));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RSI));
-  registers.push_back(new x86_64::CpuRegister(x86_64::RDI));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R8));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R9));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R10));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R11));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R12));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R13));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R14));
-  registers.push_back(new x86_64::CpuRegister(x86_64::R15));
+  std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
 
   std::string byte_regs[16];
   byte_regs[x86_64::RAX] = "al";
@@ -225,7 +833,6 @@
     }
   }
 
-  STLDeleteElements(&registers);
   return str.str();
 }
 
@@ -241,7 +848,8 @@
   return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
 }
 
-std::string buildframe_test_fn(x86_64::X86_64Assembler* assembler) {
+std::string buildframe_test_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
+                               x86_64::X86_64Assembler* assembler) {
   // TODO: more interesting spill registers / entry spills.
 
   // Two random spill regs.
@@ -285,7 +893,8 @@
   DriverFn(&buildframe_test_fn, "BuildFrame");
 }
 
-std::string removeframe_test_fn(x86_64::X86_64Assembler* assembler) {
+std::string removeframe_test_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
+                                x86_64::X86_64Assembler* assembler) {
   // TODO: more interesting spill registers / entry spills.
 
   // Two random spill regs.
@@ -313,7 +922,8 @@
   DriverFn(&removeframe_test_fn, "RemoveFrame");
 }
 
-std::string increaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
+std::string increaseframe_test_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
+                                  x86_64::X86_64Assembler* assembler) {
   assembler->IncreaseFrameSize(0U);
   assembler->IncreaseFrameSize(kStackAlignment);
   assembler->IncreaseFrameSize(10 * kStackAlignment);
@@ -331,7 +941,8 @@
   DriverFn(&increaseframe_test_fn, "IncreaseFrame");
 }
 
-std::string decreaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
+std::string decreaseframe_test_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
+                                  x86_64::X86_64Assembler* assembler) {
   assembler->DecreaseFrameSize(0U);
   assembler->DecreaseFrameSize(kStackAlignment);
   assembler->DecreaseFrameSize(10 * kStackAlignment);
diff --git a/compiler/utils/x86_64/constants_x86_64.h b/compiler/utils/x86_64/constants_x86_64.h
index ca9eae3..0c782d4 100644
--- a/compiler/utils/x86_64/constants_x86_64.h
+++ b/compiler/utils/x86_64/constants_x86_64.h
@@ -48,6 +48,7 @@
 class XmmRegister {
  public:
   explicit XmmRegister(FloatRegister r) : reg_(r) {}
+  explicit XmmRegister(int r) : reg_(FloatRegister(r)) {}
   FloatRegister AsFloatRegister() const {
     return reg_;
   }
@@ -104,7 +105,8 @@
   kZero         = kEqual,
   kNotZero      = kNotEqual,
   kNegative     = kSign,
-  kPositive     = kNotSign
+  kPositive     = kNotSign,
+  kUnordered    = kParityEven
 };
 
 
diff --git a/compiler/vector_output_stream.cc b/compiler/vector_output_stream.cc
index e5ff729..3d33673 100644
--- a/compiler/vector_output_stream.cc
+++ b/compiler/vector_output_stream.cc
@@ -20,8 +20,8 @@
 
 namespace art {
 
-VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector)
-  : OutputStream(location), offset_(vector.size()), vector_(vector) {}
+VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>* vector)
+  : OutputStream(location), offset_(vector->size()), vector_(vector) {}
 
 off_t VectorOutputStream::Seek(off_t offset, Whence whence) {
   CHECK(whence == kSeekSet || whence == kSeekCurrent || whence == kSeekEnd) << whence;
@@ -36,7 +36,7 @@
       break;
     }
     case kSeekEnd: {
-      new_offset = vector_.size() + offset;
+      new_offset = vector_->size() + offset;
       break;
     }
   }
diff --git a/compiler/vector_output_stream.h b/compiler/vector_output_stream.h
index 09daa12..3c5877c 100644
--- a/compiler/vector_output_stream.h
+++ b/compiler/vector_output_stream.h
@@ -25,21 +25,21 @@
 
 namespace art {
 
-class VectorOutputStream : public OutputStream {
+class VectorOutputStream FINAL : public OutputStream {
  public:
-  VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector);
+  VectorOutputStream(const std::string& location, std::vector<uint8_t>* vector);
 
   virtual ~VectorOutputStream() {}
 
   bool WriteFully(const void* buffer, size_t byte_count) {
-    if (static_cast<size_t>(offset_) == vector_.size()) {
+    if (static_cast<size_t>(offset_) == vector_->size()) {
       const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer);
-      vector_.insert(vector_.end(), &start[0], &start[byte_count]);
+      vector_->insert(vector_->end(), &start[0], &start[byte_count]);
       offset_ += byte_count;
     } else {
       off_t new_offset = offset_ + byte_count;
       EnsureCapacity(new_offset);
-      memcpy(&vector_[offset_], buffer, byte_count);
+      memcpy(&(*vector_)[offset_], buffer, byte_count);
       offset_ = new_offset;
     }
     return true;
@@ -49,13 +49,13 @@
 
  private:
   void EnsureCapacity(off_t new_offset) {
-    if (new_offset > static_cast<off_t>(vector_.size())) {
-      vector_.resize(new_offset);
+    if (new_offset > static_cast<off_t>(vector_->size())) {
+      vector_->resize(new_offset);
     }
   }
 
   off_t offset_;
-  std::vector<uint8_t>& vector_;
+  std::vector<uint8_t>* const vector_;
 
   DISALLOW_COPY_AND_ASSIGN(VectorOutputStream);
 };
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/Android.mk b/dex2oat/Android.mk
index 2ef826b..3f15964 100644
--- a/dex2oat/Android.mk
+++ b/dex2oat/Android.mk
@@ -24,22 +24,30 @@
 # TODO: Remove this when the framework (installd) supports pushing the
 # right instruction-set parameter for the primary architecture.
 ifneq ($(filter ro.zygote=zygote64,$(PRODUCT_DEFAULT_PROPERTY_OVERRIDES)),)
-  dex2oat_arch := 64
+  dex2oat_target_arch := 64
 else
-  dex2oat_arch := 32
+  dex2oat_target_arch := 32
+endif
+
+# We need to explcitly give the arch, as giving 'both' will make the
+# build-art-executable rule compile dex2oat for 64bits.
+ifeq ($(HOST_PREFER_32_BIT),true)
+  dex2oat_host_arch := 32
+else
+  dex2oat_host_arch := both
 endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler,art/compiler,target,ndebug,$(dex2oat_arch)))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler,art/compiler,target,ndebug,$(dex2oat_target_arch)))
 endif
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler,art/compiler,target,debug,$(dex2oat_arch)))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler,art/compiler,target,debug,$(dex2oat_target_arch)))
 endif
 
 # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart-compiler,art/compiler,host,ndebug))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart-compiler libziparchive-host,art/compiler,host,ndebug,$(dex2oat_host_arch)))
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd-compiler,art/compiler,host,debug))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd-compiler libziparchive-host,art/compiler,host,debug,$(dex2oat_host_arch)))
 endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 09825e2..fe3a978 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -30,6 +30,12 @@
 #include <sys/utsname.h>
 #endif
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include <cutils/trace.h>
+
+#include "arch/instruction_set_features.h"
+#include "arch/mips/instruction_set_features_mips.h"
+#include "base/dumpable.h"
 #include "base/stl_util.h"
 #include "base/stringpiece.h"
 #include "base/timing_logger.h"
@@ -44,8 +50,8 @@
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
-#include "elf_fixup.h"
-#include "elf_stripper.h"
+#include "elf_file.h"
+#include "elf_writer.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
 #include "image_writer.h"
@@ -91,7 +97,7 @@
   va_end(ap);
 }
 
-static void Usage(const char* fmt, ...) {
+[[noreturn]] static void Usage(const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   UsageErrorV(fmt, ap);
@@ -125,9 +131,6 @@
   UsageError("  --oat-symbols=<file.oat>: specifies the oat output destination with full symbols.");
   UsageError("      Example: --oat-symbols=/symbols/system/framework/boot.oat");
   UsageError("");
-  UsageError("  --bitcode=<file.bc>: specifies the optional bitcode filename.");
-  UsageError("      Example: --bitcode=/system/framework/boot.bc");
-  UsageError("");
   UsageError("  --image=<file.art>: specifies the output image filename.");
   UsageError("      Example: --image=/system/framework/boot.art");
   UsageError("");
@@ -145,7 +148,7 @@
   UsageError("      Example: --android-root=out/host/linux-x86");
   UsageError("      Default: $ANDROID_ROOT");
   UsageError("");
-  UsageError("  --instruction-set=(arm|arm64|mips|x86|x86_64): compile for a particular");
+  UsageError("  --instruction-set=(arm|arm64|mips|mips64|x86|x86_64): compile for a particular");
   UsageError("      instruction set.");
   UsageError("      Example: --instruction-set=x86");
   UsageError("      Default: arm");
@@ -154,10 +157,17 @@
   UsageError("      Example: --instruction-set-features=div");
   UsageError("      Default: default");
   UsageError("");
-  UsageError("  --compiler-backend=(Quick|Optimizing|Portable): select compiler backend");
+  UsageError("  --compile-pic: Force indirect use of code, methods, and classes");
+  UsageError("      Default: disabled");
+  UsageError("");
+  UsageError("  --compiler-backend=(Quick|Optimizing): select compiler backend");
   UsageError("      set.");
-  UsageError("      Example: --compiler-backend=Portable");
-  UsageError("      Default: Quick");
+  UsageError("      Example: --compiler-backend=Optimizing");
+  if (kUseOptimizingCompiler) {
+    UsageError("      Default: Optimizing");
+  } else {
+    UsageError("      Default: Quick");
+  }
   UsageError("");
   UsageError("  --compiler-filter="
                 "(verify-none"
@@ -207,8 +217,6 @@
   UsageError("      Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold);
   UsageError("      Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold);
   UsageError("");
-  UsageError("  --host: used with Portable backend to link against host runtime libraries");
-  UsageError("");
   UsageError("  --dump-timing: display a breakdown of where time was spent");
   UsageError("");
   UsageError("  --include-patch-information: Include patching information so the generated code");
@@ -241,362 +249,21 @@
   UsageError("      Used to specify a pass specific option. The setting itself must be integer.");
   UsageError("      Separator used between options is a comma.");
   UsageError("");
+  UsageError("  --swap-file=<file-name>:  specifies a file to use for swap.");
+  UsageError("      Example: --swap-file=/data/tmp/swap.001");
+  UsageError("");
+  UsageError("  --swap-fd=<file-descriptor>:  specifies a file to use for swap (by descriptor).");
+  UsageError("      Example: --swap-fd=10");
+  UsageError("");
   std::cerr << "See log for usage error information\n";
   exit(EXIT_FAILURE);
 }
 
-class Dex2Oat {
- public:
-  static bool Create(Dex2Oat** p_dex2oat,
-                     const RuntimeOptions& runtime_options,
-                     const CompilerOptions& compiler_options,
-                     Compiler::Kind compiler_kind,
-                     InstructionSet instruction_set,
-                     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);
-    std::unique_ptr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
-                                                 compiler_kind,
-                                                 instruction_set,
-                                                 instruction_set_features,
-                                                 verification_results,
-                                                 method_inliner_map,
-                                                 thread_count));
-    if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {
-      *p_dex2oat = nullptr;
-      return false;
-    }
-    *p_dex2oat = dex2oat.release();
-    return true;
-  }
-
-  ~Dex2Oat() {
-    delete runtime_;
-    LogCompletionTime();
-  }
-
-  void LogCompletionTime() {
-    LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
-              << " (threads: " << thread_count_ << ")";
-  }
-
-
-  // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
-  std::set<std::string>* ReadImageClassesFromFile(const char* image_classes_filename) {
-    std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
-                                                                  std::ifstream::in));
-    if (image_classes_file.get() == nullptr) {
-      LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
-      return nullptr;
-    }
-    std::unique_ptr<std::set<std::string>> result(ReadImageClasses(*image_classes_file));
-    image_classes_file->close();
-    return result.release();
-  }
-
-  std::set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {
-    std::unique_ptr<std::set<std::string>> image_classes(new std::set<std::string>);
-    while (image_classes_stream.good()) {
-      std::string dot;
-      std::getline(image_classes_stream, dot);
-      if (StartsWith(dot, "#") || dot.empty()) {
-        continue;
-      }
-      std::string descriptor(DotToDescriptor(dot.c_str()));
-      image_classes->insert(descriptor);
-    }
-    return image_classes.release();
-  }
-
-  // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
-  std::set<std::string>* ReadImageClassesFromZip(const char* zip_filename,
-                                                         const char* image_classes_filename,
-                                                         std::string* error_msg) {
-    std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
-    if (zip_archive.get() == nullptr) {
-      return nullptr;
-    }
-    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
-    if (zip_entry.get() == nullptr) {
-      *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
-                                zip_filename, error_msg->c_str());
-      return nullptr;
-    }
-    std::unique_ptr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(zip_filename,
-                                                                          image_classes_filename,
-                                                                          error_msg));
-    if (image_classes_file.get() == nullptr) {
-      *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
-                                zip_filename, error_msg->c_str());
-      return nullptr;
-    }
-    const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
-                                           image_classes_file->Size());
-    std::istringstream image_classes_stream(image_classes_string);
-    return ReadImageClasses(image_classes_stream);
-  }
-
-  void Compile(const std::string& boot_image_option,
-               const std::vector<const DexFile*>& dex_files,
-               const std::string& bitcode_filename,
-               bool image,
-               std::unique_ptr<std::set<std::string>>& image_classes,
-               bool dump_stats,
-               bool dump_passes,
-               TimingLogger* timings,
-               CumulativeLogger* compiler_phases_timings,
-               const std::string& profile_file) {
-    // Handle and ClassLoader creation needs to come after Runtime::Create
-    jobject class_loader = nullptr;
-    Thread* self = Thread::Current();
-    if (!boot_image_option.empty()) {
-      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-      std::vector<const DexFile*> class_path_files(dex_files);
-      OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files);
-      ScopedObjectAccess soa(self);
-      for (size_t i = 0; i < class_path_files.size(); i++) {
-        class_linker->RegisterDexFile(*class_path_files[i]);
-      }
-      soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);
-      ScopedLocalRef<jobject> class_loader_local(soa.Env(),
-          soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
-      class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
-      Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
-    }
-
-    driver_.reset(new CompilerDriver(compiler_options_,
-                                     verification_results_,
-                                     method_inliner_map_,
-                                     compiler_kind_,
-                                     instruction_set_,
-                                     instruction_set_features_,
-                                     image,
-                                     image_classes.release(),
-                                     thread_count_,
-                                     dump_stats,
-                                     dump_passes,
-                                     compiler_phases_timings,
-                                     profile_file));
-
-    driver_->GetCompiler()->SetBitcodeFileName(*driver_, bitcode_filename);
-
-    driver_->CompileAll(class_loader, dex_files, timings);
-  }
-
-  void PrepareImageWriter(uintptr_t image_base) {
-    image_writer_.reset(new ImageWriter(*driver_, image_base));
-  }
-
-  bool CreateOatFile(const std::vector<const DexFile*>& dex_files,
-                     const std::string& android_root,
-                     bool is_host,
-                     File* oat_file,
-                     const std::string& oat_location,
-                     TimingLogger* timings,
-                     SafeMap<std::string, std::string>* key_value_store) {
-    CHECK(key_value_store != nullptr);
-
-    TimingLogger::ScopedTiming t2("dex2oat OatWriter", timings);
-    std::string image_file_location;
-    uint32_t image_file_location_oat_checksum = 0;
-    uintptr_t image_file_location_oat_data_begin = 0;
-    int32_t image_patch_delta = 0;
-    if (!driver_->IsImage()) {
-      TimingLogger::ScopedTiming t3("Loading image checksum", timings);
-      gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
-      image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
-      image_file_location_oat_data_begin =
-          reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin());
-      image_file_location = image_space->GetImageFilename();
-      image_patch_delta = image_space->GetImageHeader().GetPatchDelta();
-    }
-
-    if (!image_file_location.empty()) {
-      key_value_store->Put(OatHeader::kImageLocationKey, image_file_location);
-    }
-
-    OatWriter oat_writer(dex_files, image_file_location_oat_checksum,
-                         image_file_location_oat_data_begin,
-                         image_patch_delta,
-                         driver_.get(),
-                         image_writer_.get(),
-                         timings,
-                         key_value_store);
-
-    if (driver_->IsImage()) {
-      // The OatWriter constructor has already updated offsets in methods and we need to
-      // prepare method offsets in the image address space for direct method patching.
-      t2.NewTiming("Preparing image address space");
-      if (!image_writer_->PrepareImageAddressSpace()) {
-        LOG(ERROR) << "Failed to prepare image address space.";
-        return false;
-      }
-    }
-
-    t2.NewTiming("Writing ELF");
-    if (!driver_->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
-      LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
-      return false;
-    }
-
-    // Flush result to disk.
-    t2.NewTiming("Flushing ELF");
-    if (oat_file->Flush() != 0) {
-      LOG(ERROR) << "Failed to flush ELF file " << oat_file->GetPath();
-      return false;
-    }
-
-    return true;
-  }
-
-  bool CreateImageFile(const std::string& image_filename,
-                       const std::string& oat_filename,
-                       const std::string& oat_location)
-      LOCKS_EXCLUDED(Locks::mutator_lock_) {
-    CHECK(image_writer_ != nullptr);
-    if (!image_writer_->Write(image_filename, oat_filename, oat_location)) {
-      LOG(ERROR) << "Failed to create image file " << image_filename;
-      return false;
-    }
-    uintptr_t oat_data_begin = image_writer_->GetOatDataBegin();
-
-    // Destroy ImageWriter before doing FixupElf.
-    image_writer_.reset();
-
-    std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
-    if (oat_file.get() == nullptr) {
-      PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
-      return false;
-    }
-    if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
-      LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
-      return false;
-    }
-    return true;
-  }
-
- private:
-  explicit Dex2Oat(const CompilerOptions* compiler_options,
-                   Compiler::Kind compiler_kind,
-                   InstructionSet instruction_set,
-                   InstructionSetFeatures instruction_set_features,
-                   VerificationResults* verification_results,
-                   DexFileToMethodInlinerMap* method_inliner_map,
-                   size_t thread_count)
-      : compiler_options_(compiler_options),
-        compiler_kind_(compiler_kind),
-        instruction_set_(instruction_set),
-        instruction_set_features_(instruction_set_features),
-        verification_results_(verification_results),
-        method_inliner_map_(method_inliner_map),
-        runtime_(nullptr),
-        thread_count_(thread_count),
-        start_ns_(NanoTime()),
-        driver_(nullptr),
-        image_writer_(nullptr) {
-    CHECK(compiler_options != nullptr);
-    CHECK(verification_results != nullptr);
-    CHECK(method_inliner_map != nullptr);
-  }
-
-  bool CreateRuntime(const RuntimeOptions& runtime_options, InstructionSet instruction_set)
-      SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
-    if (!Runtime::Create(runtime_options, false)) {
-      LOG(ERROR) << "Failed to create runtime";
-      return false;
-    }
-    Runtime* runtime = Runtime::Current();
-    runtime->SetInstructionSet(instruction_set);
-    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
-      if (!runtime->HasCalleeSaveMethod(type)) {
-        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(type), type);
-      }
-    }
-    runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
-    runtime->GetClassLinker()->RunRootClinits();
-    runtime_ = runtime;
-    return true;
-  }
-
-  // Appends to dex_files any elements of class_path that it doesn't already
-  // contain. This will open those dex files as necessary.
-  static void OpenClassPathFiles(const std::string& class_path,
-                                 std::vector<const DexFile*>& dex_files) {
-    std::vector<std::string> 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) {
-      if (DexFilesContains(dex_files, parsed[i])) {
-        continue;
-      }
-      std::string error_msg;
-      if (!DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg, &dex_files)) {
-        LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "': " << error_msg;
-      }
-    }
-  }
-
-  // Returns true if dex_files has a dex with the named location.
-  static bool DexFilesContains(const std::vector<const DexFile*>& dex_files,
-                               const std::string& location) {
-    for (size_t i = 0; i < dex_files.size(); ++i) {
-      if (dex_files[i]->GetLocation() == location) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  const CompilerOptions* const compiler_options_;
-  const Compiler::Kind compiler_kind_;
-
-  const InstructionSet instruction_set_;
-  const InstructionSetFeatures instruction_set_features_;
-
-  VerificationResults* const verification_results_;
-  DexFileToMethodInlinerMap* const method_inliner_map_;
-  Runtime* runtime_;
-  size_t thread_count_;
-  uint64_t start_ns_;
-  std::unique_ptr<CompilerDriver> driver_;
-  std::unique_ptr<ImageWriter> image_writer_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
-};
-
-static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames,
-                           const std::vector<const char*>& dex_locations,
-                           std::vector<const DexFile*>& dex_files) {
-  size_t failure_count = 0;
-  for (size_t i = 0; i < dex_filenames.size(); i++) {
-    const char* dex_filename = dex_filenames[i];
-    const char* dex_location = dex_locations[i];
-    ATRACE_BEGIN(StringPrintf("Opening dex file '%s'", dex_filenames[i]).c_str());
-    std::string error_msg;
-    if (!OS::FileExists(dex_filename)) {
-      LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
-      continue;
-    }
-    if (!DexFile::Open(dex_filename, dex_location, &error_msg, &dex_files)) {
-      LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
-      ++failure_count;
-    }
-    ATRACE_END();
-  }
-  return failure_count;
-}
-
 // The primary goal of the watchdog is to prevent stuck build servers
 // during development when fatal aborts lead to a cascade of failures
 // that result in a deadlock.
 class WatchDog {
-// WatchDog defines its own CHECK_PTHREAD_CALL to avoid using Log which uses locks
+// WatchDog defines its own CHECK_PTHREAD_CALL to avoid using LOG which uses locks
 #undef CHECK_PTHREAD_CALL
 #define CHECK_WATCH_DOG_PTHREAD_CALL(call, args, what) \
   do { \
@@ -659,41 +326,23 @@
             message.c_str());
   }
 
-  static void Warn(const std::string& message) {
-    Message('W', message);
-  }
-
-  static void Fatal(const std::string& message) {
+  [[noreturn]] static void Fatal(const std::string& message) {
     Message('F', message);
     exit(1);
   }
 
   void Wait() {
-    bool warning = true;
-    CHECK_GT(kWatchDogTimeoutSeconds, kWatchDogWarningSeconds);
     // TODO: tune the multiplier for GC verification, the following is just to make the timeout
     //       large.
     int64_t multiplier = kVerifyObjectSupport > kVerifyObjectModeFast ? 100 : 1;
-    timespec warning_ts;
-    InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogWarningSeconds * 1000, 0, &warning_ts);
     timespec timeout_ts;
     InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
     const char* reason = "dex2oat watch dog thread waiting";
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
     while (!shutting_down_) {
-      int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &mutex_,
-                                                         warning ? &warning_ts
-                                                                 : &timeout_ts));
+      int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &mutex_, &timeout_ts));
       if (rc == ETIMEDOUT) {
-        std::string message(StringPrintf("dex2oat did not finish after %d seconds",
-                                         warning ? kWatchDogWarningSeconds
-                                                 : kWatchDogTimeoutSeconds));
-        if (warning) {
-          Warn(message.c_str());
-          warning = false;
-        } else {
-          Fatal(message.c_str());
-        }
+        Fatal(StringPrintf("dex2oat did not finish after %d seconds", kWatchDogTimeoutSeconds));
       } else if (rc != 0) {
         std::string message(StringPrintf("pthread_cond_timedwait failed: %s",
                                          strerror(errno)));
@@ -706,17 +355,9 @@
   // When setting timeouts, keep in mind that the build server may not be as fast as your desktop.
   // Debug builds are slower so they have larger timeouts.
   static const unsigned int kSlowdownFactor = kIsDebugBuild ? 5U : 1U;
-#if ART_USE_PORTABLE_COMPILER
-  // 2 minutes scaled by kSlowdownFactor.
-  static const unsigned int kWatchDogWarningSeconds = kSlowdownFactor * 2 * 60;
-  // 30 minutes scaled by kSlowdownFactor.
-  static const unsigned int kWatchDogTimeoutSeconds = kSlowdownFactor * 30 * 60;
-#else
-  // 1 minutes scaled by kSlowdownFactor.
-  static const unsigned int kWatchDogWarningSeconds = kSlowdownFactor * 1 * 60;
+
   // 6 minutes scaled by kSlowdownFactor.
   static const unsigned int kWatchDogTimeoutSeconds = kSlowdownFactor * 6 * 60;
-#endif
 
   bool is_watch_dog_enabled_;
   bool shutting_down_;
@@ -726,42 +367,8 @@
   pthread_attr_t attr_;
   pthread_t pthread_;
 };
-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) {
+static 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) {
     Usage("Missing char %c in option %s\n", c, s.c_str());
@@ -770,8 +377,8 @@
   *parsed_value = s.substr(colon + 1);
 }
 
-void ParseDouble(const std::string& option, char after_char,
-                 double min, double max, double* parsed_value) {
+static void ParseDouble(const std::string& option, char after_char, double min, double max,
+                        double* parsed_value) {
   std::string substring;
   ParseStringAfterChar(option, after_char, &substring);
   bool sane_val = true;
@@ -793,656 +400,852 @@
   *parsed_value = value;
 }
 
-static int dex2oat(int argc, char** argv) {
-#if defined(__linux__) && defined(__arm__)
-  int major, minor;
-  struct utsname uts;
-  if (uname(&uts) != -1 &&
-      sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
-      ((major < 3) || ((major == 3) && (minor < 4)))) {
-    // Kernels before 3.4 don't handle the ASLR well and we can run out of address
-    // space (http://b/13564922). Work around the issue by inhibiting further mmap() randomization.
-    int old_personality = personality(0xffffffff);
-    if ((old_personality & ADDR_NO_RANDOMIZE) == 0) {
-      int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
-      if (new_personality == -1) {
-        LOG(WARNING) << "personality(. | ADDR_NO_RANDOMIZE) failed.";
-      }
+static constexpr size_t kMinDexFilesForSwap = 2;
+static constexpr size_t kMinDexFileCumulativeSizeForSwap = 20 * MB;
+
+static bool UseSwap(bool is_image, std::vector<const DexFile*>& dex_files) {
+  if (is_image) {
+    // Don't use swap, we know generation should succeed, and we don't want to slow it down.
+    return false;
+  }
+  if (dex_files.size() < kMinDexFilesForSwap) {
+    // If there are less dex files than the threshold, assume it's gonna be fine.
+    return false;
+  }
+  size_t dex_files_size = 0;
+  for (const auto* dex_file : dex_files) {
+    dex_files_size += dex_file->GetHeader().file_size_;
+  }
+  return dex_files_size >= kMinDexFileCumulativeSizeForSwap;
+}
+
+class Dex2Oat FINAL {
+ public:
+  explicit Dex2Oat(TimingLogger* timings) :
+      compiler_kind_(kUseOptimizingCompiler ? Compiler::kOptimizing : Compiler::kQuick),
+      instruction_set_(kRuntimeISA),
+      // Take the default set of instruction features from the build.
+      method_inliner_map_(),
+      runtime_(nullptr),
+      thread_count_(sysconf(_SC_NPROCESSORS_CONF)),
+      start_ns_(NanoTime()),
+      oat_fd_(-1),
+      zip_fd_(-1),
+      image_base_(0U),
+      image_classes_zip_filename_(nullptr),
+      image_classes_filename_(nullptr),
+      compiled_classes_zip_filename_(nullptr),
+      compiled_classes_filename_(nullptr),
+      image_(false),
+      is_host_(false),
+      dump_stats_(false),
+      dump_passes_(false),
+      dump_timing_(false),
+      dump_slow_timing_(kIsDebugBuild),
+      swap_fd_(-1),
+      timings_(timings) {}
+
+  ~Dex2Oat() {
+    // Free opened dex files before deleting the runtime_, because ~DexFile
+    // uses MemMap, which is shut down by ~Runtime.
+    class_path_files_.clear();
+    opened_dex_files_.clear();
+
+    // Log completion time before deleting the runtime_, because this accesses
+    // the runtime.
+    LogCompletionTime();
+
+    if (kIsDebugBuild || (RUNNING_ON_VALGRIND != 0)) {
+      delete runtime_;  // See field declaration for why this is manual.
     }
   }
-#endif
 
-  original_argc = argc;
-  original_argv = argv;
+  // Parse the arguments from the command line. In case of an unrecognized option or impossible
+  // values/combinations, a usage error will be displayed and exit() is called. Thus, if the method
+  // returns, arguments have been successfully parsed.
+  void ParseArgs(int argc, char** argv) {
+    original_argc = argc;
+    original_argv = argv;
 
-  TimingLogger timings("compiler", false, false);
-  CumulativeLogger compiler_phases_timings("compilation times");
+    InitLogging(argv);
 
-  InitLogging(argv);
+    // Skip over argv[0].
+    argv++;
+    argc--;
 
-  // Skip over argv[0].
-  argv++;
-  argc--;
-
-  if (argc == 0) {
-    Usage("No arguments specified");
-  }
-
-  std::vector<const char*> dex_filenames;
-  std::vector<const char*> dex_locations;
-  int zip_fd = -1;
-  std::string zip_location;
-  std::string oat_filename;
-  std::string oat_symbols;
-  std::string oat_location;
-  int oat_fd = -1;
-  std::string bitcode_filename;
-  const char* image_classes_zip_filename = nullptr;
-  const char* image_classes_filename = nullptr;
-  std::string image_filename;
-  std::string boot_image_filename;
-  uintptr_t image_base = 0;
-  std::string android_root;
-  std::vector<const char*> runtime_args;
-  int thread_count = sysconf(_SC_NPROCESSORS_CONF);
-  Compiler::Kind compiler_kind = kUsePortableCompiler
-      ? Compiler::kPortable
-      : Compiler::kQuick;
-  const char* compiler_filter_string = nullptr;
-  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;
-
-  // Take the default set of instruction features from the build.
-  InstructionSetFeatures instruction_set_features =
-      ParseFeatureList(Runtime::GetDefaultInstructionSetFeatures());
-
-  InstructionSet instruction_set = kRuntimeISA;
-
-  // Profile file to use
-  std::string profile_file;
-  double top_k_profile_threshold = CompilerOptions::kDefaultTopKProfileThreshold;
-
-  bool is_host = false;
-  bool dump_stats = false;
-  bool dump_timing = false;
-  bool dump_passes = false;
-  bool print_pass_options = false;
-  bool include_patch_information = CompilerOptions::kDefaultIncludePatchInformation;
-  bool include_debug_symbols = kIsDebugBuild;
-  bool dump_slow_timing = kIsDebugBuild;
-  bool watch_dog_enabled = true;
-  bool generate_gdb_information = kIsDebugBuild;
-
-  // Checks are all explicit until we know the architecture.
-  bool implicit_null_checks = false;
-  bool implicit_so_checks = false;
-  bool implicit_suspend_checks = false;
-
-  for (int i = 0; i < argc; i++) {
-    const StringPiece option(argv[i]);
-    const bool log_options = false;
-    if (log_options) {
-      LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+    if (argc == 0) {
+      Usage("No arguments specified");
     }
-    if (option.starts_with("--dex-file=")) {
-      dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
-    } else if (option.starts_with("--dex-location=")) {
-      dex_locations.push_back(option.substr(strlen("--dex-location=")).data());
-    } else if (option.starts_with("--zip-fd=")) {
-      const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data();
-      if (!ParseInt(zip_fd_str, &zip_fd)) {
-        Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str);
-      }
-      if (zip_fd < 0) {
-        Usage("--zip-fd passed a negative value %d", zip_fd);
-      }
-    } else if (option.starts_with("--zip-location=")) {
-      zip_location = option.substr(strlen("--zip-location=")).data();
-    } else if (option.starts_with("--oat-file=")) {
-      oat_filename = option.substr(strlen("--oat-file=")).data();
-    } else if (option.starts_with("--oat-symbols=")) {
-      oat_symbols = option.substr(strlen("--oat-symbols=")).data();
-    } else if (option.starts_with("--oat-fd=")) {
-      const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data();
-      if (!ParseInt(oat_fd_str, &oat_fd)) {
-        Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str);
-      }
-      if (oat_fd < 0) {
-        Usage("--oat-fd passed a negative value %d", oat_fd);
-      }
-    } else if (option == "--watch-dog") {
-      watch_dog_enabled = true;
-    } else if (option == "--no-watch-dog") {
-      watch_dog_enabled = false;
-    } else if (option == "--gen-gdb-info") {
-      generate_gdb_information = true;
-      // Debug symbols are needed for gdb information.
-      include_debug_symbols = true;
-    } else if (option == "--no-gen-gdb-info") {
-      generate_gdb_information = false;
-    } else if (option.starts_with("-j")) {
-      const char* thread_count_str = option.substr(strlen("-j")).data();
-      if (!ParseInt(thread_count_str, &thread_count)) {
-        Usage("Failed to parse -j argument '%s' as an integer", thread_count_str);
-      }
-    } else if (option.starts_with("--oat-location=")) {
-      oat_location = option.substr(strlen("--oat-location=")).data();
-    } else if (option.starts_with("--bitcode=")) {
-      bitcode_filename = option.substr(strlen("--bitcode=")).data();
-    } else if (option.starts_with("--image=")) {
-      image_filename = option.substr(strlen("--image=")).data();
-    } else if (option.starts_with("--image-classes=")) {
-      image_classes_filename = option.substr(strlen("--image-classes=")).data();
-    } else if (option.starts_with("--image-classes-zip=")) {
-      image_classes_zip_filename = option.substr(strlen("--image-classes-zip=")).data();
-    } else if (option.starts_with("--base=")) {
-      const char* image_base_str = option.substr(strlen("--base=")).data();
-      char* end;
-      image_base = strtoul(image_base_str, &end, 16);
-      if (end == image_base_str || *end != '\0') {
-        Usage("Failed to parse hexadecimal value for option %s", option.data());
-      }
-    } else if (option.starts_with("--boot-image=")) {
-      boot_image_filename = option.substr(strlen("--boot-image=")).data();
-    } else if (option.starts_with("--android-root=")) {
-      android_root = option.substr(strlen("--android-root=")).data();
-    } else if (option.starts_with("--instruction-set=")) {
-      StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
-      if (instruction_set_str == "arm") {
-        instruction_set = kThumb2;
-      } else if (instruction_set_str == "arm64") {
-        instruction_set = kArm64;
-      } else if (instruction_set_str == "mips") {
-        instruction_set = kMips;
-      } else if (instruction_set_str == "x86") {
-        instruction_set = kX86;
-      } else if (instruction_set_str == "x86_64") {
-        instruction_set = kX86_64;
-      }
-    } else if (option.starts_with("--instruction-set-features=")) {
-      StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
-      instruction_set_features = ParseFeatureList(str.as_string());
-    } else if (option.starts_with("--compiler-backend=")) {
-      StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
-      if (backend_str == "Quick") {
-        compiler_kind = Compiler::kQuick;
-      } else if (backend_str == "Optimizing") {
-        compiler_kind = Compiler::kOptimizing;
-      } else if (backend_str == "Portable") {
-        compiler_kind = Compiler::kPortable;
-      }
-    } else if (option.starts_with("--compiler-filter=")) {
-      compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
-    } else if (option.starts_with("--huge-method-max=")) {
-      const char* threshold = option.substr(strlen("--huge-method-max=")).data();
-      if (!ParseInt(threshold, &huge_method_threshold)) {
-        Usage("Failed to parse --huge-method-max '%s' as an integer", threshold);
-      }
-      if (huge_method_threshold < 0) {
-        Usage("--huge-method-max passed a negative value %s", huge_method_threshold);
-      }
-    } else if (option.starts_with("--large-method-max=")) {
-      const char* threshold = option.substr(strlen("--large-method-max=")).data();
-      if (!ParseInt(threshold, &large_method_threshold)) {
-        Usage("Failed to parse --large-method-max '%s' as an integer", threshold);
-      }
-      if (large_method_threshold < 0) {
-        Usage("--large-method-max passed a negative value %s", large_method_threshold);
-      }
-    } else if (option.starts_with("--small-method-max=")) {
-      const char* threshold = option.substr(strlen("--small-method-max=")).data();
-      if (!ParseInt(threshold, &small_method_threshold)) {
-        Usage("Failed to parse --small-method-max '%s' as an integer", threshold);
-      }
-      if (small_method_threshold < 0) {
-        Usage("--small-method-max passed a negative value %s", small_method_threshold);
-      }
-    } else if (option.starts_with("--tiny-method-max=")) {
-      const char* threshold = option.substr(strlen("--tiny-method-max=")).data();
-      if (!ParseInt(threshold, &tiny_method_threshold)) {
-        Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold);
-      }
-      if (tiny_method_threshold < 0) {
-        Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold);
-      }
-    } else if (option.starts_with("--num-dex-methods=")) {
-      const char* threshold = option.substr(strlen("--num-dex-methods=")).data();
-      if (!ParseInt(threshold, &num_dex_methods_threshold)) {
-        Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold);
-      }
-      if (num_dex_methods_threshold < 0) {
-        Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold);
-      }
-    } else if (option == "--host") {
-      is_host = true;
-    } else if (option == "--runtime-arg") {
-      if (++i >= argc) {
-        Usage("Missing required argument for --runtime-arg");
-      }
+
+    std::string oat_symbols;
+    std::string boot_image_filename;
+    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;
+
+    // Profile file to use
+    double top_k_profile_threshold = CompilerOptions::kDefaultTopKProfileThreshold;
+
+    bool print_pass_options = false;
+    bool include_patch_information = CompilerOptions::kDefaultIncludePatchInformation;
+    bool include_debug_symbols = kIsDebugBuild;
+    bool watch_dog_enabled = true;
+    bool generate_gdb_information = kIsDebugBuild;
+
+    std::string error_msg;
+
+    for (int i = 0; i < argc; i++) {
+      const StringPiece option(argv[i]);
+      const bool log_options = false;
       if (log_options) {
         LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
       }
-      runtime_args.push_back(argv[i]);
-    } else if (option == "--dump-timing") {
-      dump_timing = true;
-    } else if (option == "--dump-passes") {
-      dump_passes = true;
-    } else if (option == "--dump-stats") {
-      dump_stats = true;
-    } else if (option == "--include-debug-symbols" || option == "--no-strip-symbols") {
-      include_debug_symbols = true;
-    } else if (option == "--no-include-debug-symbols" || option == "--strip-symbols") {
-      include_debug_symbols = false;
-      generate_gdb_information = false;  // Depends on debug symbols, see above.
-    } else if (option.starts_with("--profile-file=")) {
-      profile_file = option.substr(strlen("--profile-file=")).data();
-      VLOG(compiler) << "dex2oat: profile file is " << profile_file;
-    } else if (option == "--no-profile-file") {
-      // No profile
-    } else if (option.starts_with("--top-k-profile-threshold=")) {
-      ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold);
-    } else if (option == "--print-pass-names") {
-      PassDriverMEOpts::PrintPassNames();
-    } else if (option.starts_with("--disable-passes=")) {
-      std::string disable_passes = option.substr(strlen("--disable-passes=")).data();
-      PassDriverMEOpts::CreateDefaultPassList(disable_passes);
-    } else if (option.starts_with("--print-passes=")) {
-      std::string print_passes = option.substr(strlen("--print-passes=")).data();
-      PassDriverMEOpts::SetPrintPassList(print_passes);
-    } else if (option == "--print-all-passes") {
-      PassDriverMEOpts::SetPrintAllPasses();
-    } else if (option.starts_with("--dump-cfg-passes=")) {
-      std::string dump_passes = option.substr(strlen("--dump-cfg-passes=")).data();
-      PassDriverMEOpts::SetDumpPassList(dump_passes);
-    } else if (option == "--print-pass-options") {
-      print_pass_options = true;
-    } else if (option.starts_with("--pass-options=")) {
-      std::string options = option.substr(strlen("--pass-options=")).data();
-      PassDriverMEOpts::SetOverriddenPassOptions(options);
-    } else if (option == "--include-patch-information") {
-      include_patch_information = true;
-    } else if (option == "--no-include-patch-information") {
-      include_patch_information = false;
-    } else {
-      Usage("Unknown argument %s", option.data());
-    }
-  }
-
-  if (oat_filename.empty() && oat_fd == -1) {
-    Usage("Output must be supplied with either --oat-file or --oat-fd");
-  }
-
-  if (!oat_filename.empty() && oat_fd != -1) {
-    Usage("--oat-file should not be used with --oat-fd");
-  }
-
-  if (!oat_symbols.empty() && oat_fd != -1) {
-    Usage("--oat-symbols should not be used with --oat-fd");
-  }
-
-  if (!oat_symbols.empty() && is_host) {
-    Usage("--oat-symbols should not be used with --host");
-  }
-
-  if (oat_fd != -1 && !image_filename.empty()) {
-    Usage("--oat-fd should not be used with --image");
-  }
-
-  if (android_root.empty()) {
-    const char* android_root_env_var = getenv("ANDROID_ROOT");
-    if (android_root_env_var == nullptr) {
-      Usage("--android-root unspecified and ANDROID_ROOT not set");
-    }
-    android_root += android_root_env_var;
-  }
-
-  bool image = (!image_filename.empty());
-  if (!image && boot_image_filename.empty()) {
-    boot_image_filename += android_root;
-    boot_image_filename += "/framework/boot.art";
-  }
-  std::string boot_image_option;
-  if (!boot_image_filename.empty()) {
-    boot_image_option += "-Ximage:";
-    boot_image_option += boot_image_filename;
-  }
-
-  if (image_classes_filename != nullptr && !image) {
-    Usage("--image-classes should only be used with --image");
-  }
-
-  if (image_classes_filename != nullptr && !boot_image_option.empty()) {
-    Usage("--image-classes should not be used with --boot-image");
-  }
-
-  if (image_classes_zip_filename != nullptr && image_classes_filename == nullptr) {
-    Usage("--image-classes-zip should be used with --image-classes");
-  }
-
-  if (dex_filenames.empty() && zip_fd == -1) {
-    Usage("Input must be supplied with either --dex-file or --zip-fd");
-  }
-
-  if (!dex_filenames.empty() && zip_fd != -1) {
-    Usage("--dex-file should not be used with --zip-fd");
-  }
-
-  if (!dex_filenames.empty() && !zip_location.empty()) {
-    Usage("--dex-file should not be used with --zip-location");
-  }
-
-  if (dex_locations.empty()) {
-    for (size_t i = 0; i < dex_filenames.size(); i++) {
-      dex_locations.push_back(dex_filenames[i]);
-    }
-  } else if (dex_locations.size() != dex_filenames.size()) {
-    Usage("--dex-location arguments do not match --dex-file arguments");
-  }
-
-  if (zip_fd != -1 && zip_location.empty()) {
-    Usage("--zip-location should be supplied with --zip-fd");
-  }
-
-  if (boot_image_option.empty()) {
-    if (image_base == 0) {
-      Usage("Non-zero --base not specified");
-    }
-  }
-
-  std::string oat_stripped(oat_filename);
-  std::string oat_unstripped;
-  if (!oat_symbols.empty()) {
-    oat_unstripped += oat_symbols;
-  } else {
-    oat_unstripped += oat_filename;
-  }
-
-  if (compiler_filter_string == nullptr) {
-    if (instruction_set == kMips64) {
-      // TODO: fix compiler for Mips64.
-      compiler_filter_string = "interpret-only";
-    } else if (image) {
-      compiler_filter_string = "speed";
-    } else {
-#if ART_SMALL_MODE
-      compiler_filter_string = "interpret-only";
-#else
-      compiler_filter_string = "speed";
-#endif
-    }
-  }
-  CHECK(compiler_filter_string != nullptr);
-  CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
-  if (strcmp(compiler_filter_string, "verify-none") == 0) {
-    compiler_filter = CompilerOptions::kVerifyNone;
-  } else if (strcmp(compiler_filter_string, "interpret-only") == 0) {
-    compiler_filter = CompilerOptions::kInterpretOnly;
-  } else if (strcmp(compiler_filter_string, "space") == 0) {
-    compiler_filter = CompilerOptions::kSpace;
-  } else if (strcmp(compiler_filter_string, "balanced") == 0) {
-    compiler_filter = CompilerOptions::kBalanced;
-  } else if (strcmp(compiler_filter_string, "speed") == 0) {
-    compiler_filter = CompilerOptions::kSpeed;
-  } else if (strcmp(compiler_filter_string, "everything") == 0) {
-    compiler_filter = CompilerOptions::kEverything;
-  } else if (strcmp(compiler_filter_string, "time") == 0) {
-    compiler_filter = CompilerOptions::kTime;
-  } else {
-    Usage("Unknown --compiler-filter value %s", compiler_filter_string);
-  }
-
-  // Set the compilation target's implicit checks options.
-  switch (instruction_set) {
-    case kArm:
-    case kThumb2:
-    case kArm64:
-    case kX86:
-    case kX86_64:
-      implicit_null_checks = true;
-      implicit_so_checks = true;
-      break;
-
-    default:
-      // Defaults are correct.
-      break;
-  }
-
-  if (print_pass_options) {
-    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
-#ifdef ART_SEA_IR_MODE
-                                                                        , compiler_options.sea_ir_ =
-                                                                              true;
-#endif
-  ));  // NOLINT(whitespace/parens)
-
-  // Done with usage checks, enable watchdog if requested
-  WatchDog watch_dog(watch_dog_enabled);
-
-  // Check early that the result of compilation can be written
-  std::unique_ptr<File> oat_file;
-  bool create_file = !oat_unstripped.empty();  // as opposed to using open file descriptor
-  if (create_file) {
-    oat_file.reset(OS::CreateEmptyFile(oat_unstripped.c_str()));
-    if (oat_location.empty()) {
-      oat_location = oat_filename;
-    }
-  } else {
-    oat_file.reset(new File(oat_fd, oat_location));
-    oat_file->DisableAutoClose();
-    oat_file->SetLength(0);
-  }
-  if (oat_file.get() == nullptr) {
-    PLOG(ERROR) << "Failed to create oat file: " << oat_location;
-    return EXIT_FAILURE;
-  }
-  if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
-    PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location;
-    return EXIT_FAILURE;
-  }
-
-  timings.StartTiming("dex2oat Setup");
-  LOG(INFO) << CommandLine();
-
-  RuntimeOptions runtime_options;
-  std::vector<const DexFile*> boot_class_path;
-  if (boot_image_option.empty()) {
-    size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
-    if (failure_count > 0) {
-      LOG(ERROR) << "Failed to open some dex files: " << failure_count;
-      return EXIT_FAILURE;
-    }
-    runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
-  } else {
-    runtime_options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
-  }
-  for (size_t i = 0; i < runtime_args.size(); i++) {
-    runtime_options.push_back(std::make_pair(runtime_args[i], nullptr));
-  }
-
-  std::unique_ptr<VerificationResults> verification_results(new VerificationResults(
-                                                            compiler_options.get()));
-  DexFileToMethodInlinerMap method_inliner_map;
-  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))));
-
-  Dex2Oat* p_dex2oat;
-  if (!Dex2Oat::Create(&p_dex2oat,
-                       runtime_options,
-                       *compiler_options,
-                       compiler_kind,
-                       instruction_set,
-                       instruction_set_features,
-                       verification_results.get(),
-                       &method_inliner_map,
-                       thread_count)) {
-    LOG(ERROR) << "Failed to create dex2oat";
-    return EXIT_FAILURE;
-  }
-  std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);
-
-  // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
-  // give it away now so that we don't starve GC.
-  Thread* self = Thread::Current();
-  self->TransitionFromRunnableToSuspended(kNative);
-  // If we're doing the image, override the compiler filter to force full compilation. Must be
-  // done ahead of WellKnownClasses::Init that causes verification.  Note: doesn't force
-  // compilation of class initializers.
-  // Whilst we're in native take the opportunity to initialize well known classes.
-  WellKnownClasses::Init(self->GetJniEnv());
-
-  // If --image-classes was specified, calculate the full list of classes to include in the image
-  std::unique_ptr<std::set<std::string>> image_classes(nullptr);
-  if (image_classes_filename != nullptr) {
-    std::string error_msg;
-    if (image_classes_zip_filename != nullptr) {
-      image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
-                                                           image_classes_filename,
-                                                           &error_msg));
-    } else {
-      image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
-    }
-    if (image_classes.get() == nullptr) {
-      LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
-          "': " << error_msg;
-      return EXIT_FAILURE;
-    }
-  } else if (image) {
-    image_classes.reset(new std::set<std::string>);
-  }
-
-  std::vector<const DexFile*> dex_files;
-  if (boot_image_option.empty()) {
-    dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
-  } else {
-    if (dex_filenames.empty()) {
-      ATRACE_BEGIN("Opening zip archive from file descriptor");
-      std::string error_msg;
-      std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(),
-                                                               &error_msg));
-      if (zip_archive.get() == nullptr) {
-        LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
-            << error_msg;
-        return EXIT_FAILURE;
-      }
-      if (!DexFile::OpenFromZip(*zip_archive.get(), zip_location, &error_msg, &dex_files)) {
-        LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
-            << "': " << error_msg;
-        return EXIT_FAILURE;
-      }
-      ATRACE_END();
-    } else {
-      size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
-      if (failure_count > 0) {
-        LOG(ERROR) << "Failed to open some dex files: " << failure_count;
-        return EXIT_FAILURE;
-      }
-    }
-
-    const bool kSaveDexInput = false;
-    if (kSaveDexInput) {
-      for (size_t i = 0; i < dex_files.size(); ++i) {
-        const DexFile* dex_file = dex_files[i];
-        std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i));
-        std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
-        if (tmp_file.get() == nullptr) {
-            PLOG(ERROR) << "Failed to open file " << tmp_file_name
-                        << ". Try: adb shell chmod 777 /data/local/tmp";
-            continue;
+      if (option.starts_with("--dex-file=")) {
+        dex_filenames_.push_back(option.substr(strlen("--dex-file=")).data());
+      } else if (option.starts_with("--dex-location=")) {
+        dex_locations_.push_back(option.substr(strlen("--dex-location=")).data());
+      } else if (option.starts_with("--zip-fd=")) {
+        const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data();
+        if (!ParseInt(zip_fd_str, &zip_fd_)) {
+          Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str);
         }
-        tmp_file->WriteFully(dex_file->Begin(), dex_file->Size());
-        LOG(INFO) << "Wrote input to " << tmp_file_name;
+        if (zip_fd_ < 0) {
+          Usage("--zip-fd passed a negative value %d", zip_fd_);
+        }
+      } else if (option.starts_with("--zip-location=")) {
+        zip_location_ = option.substr(strlen("--zip-location=")).data();
+      } else if (option.starts_with("--oat-file=")) {
+        oat_filename_ = option.substr(strlen("--oat-file=")).data();
+      } else if (option.starts_with("--oat-symbols=")) {
+        oat_symbols = option.substr(strlen("--oat-symbols=")).data();
+      } else if (option.starts_with("--oat-fd=")) {
+        const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data();
+        if (!ParseInt(oat_fd_str, &oat_fd_)) {
+          Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str);
+        }
+        if (oat_fd_ < 0) {
+          Usage("--oat-fd passed a negative value %d", oat_fd_);
+        }
+      } else if (option == "--watch-dog") {
+        watch_dog_enabled = true;
+      } else if (option == "--no-watch-dog") {
+        watch_dog_enabled = false;
+      } else if (option == "--gen-gdb-info") {
+        generate_gdb_information = true;
+        // Debug symbols are needed for gdb information.
+        include_debug_symbols = true;
+      } else if (option == "--no-gen-gdb-info") {
+        generate_gdb_information = false;
+      } else if (option.starts_with("-j")) {
+        const char* thread_count_str = option.substr(strlen("-j")).data();
+        if (!ParseUint(thread_count_str, &thread_count_)) {
+          Usage("Failed to parse -j argument '%s' as an integer", thread_count_str);
+        }
+      } else if (option.starts_with("--oat-location=")) {
+        oat_location_ = option.substr(strlen("--oat-location=")).data();
+      } else if (option.starts_with("--image=")) {
+        image_filename_ = option.substr(strlen("--image=")).data();
+      } else if (option.starts_with("--image-classes=")) {
+        image_classes_filename_ = option.substr(strlen("--image-classes=")).data();
+      } else if (option.starts_with("--image-classes-zip=")) {
+        image_classes_zip_filename_ = option.substr(strlen("--image-classes-zip=")).data();
+      } else if (option.starts_with("--compiled-classes=")) {
+        compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data();
+      } else if (option.starts_with("--compiled-classes-zip=")) {
+        compiled_classes_zip_filename_ = option.substr(strlen("--compiled-classes-zip=")).data();
+      } else if (option.starts_with("--base=")) {
+        const char* image_base_str = option.substr(strlen("--base=")).data();
+        char* end;
+        image_base_ = strtoul(image_base_str, &end, 16);
+        if (end == image_base_str || *end != '\0') {
+          Usage("Failed to parse hexadecimal value for option %s", option.data());
+        }
+      } else if (option.starts_with("--boot-image=")) {
+        boot_image_filename = option.substr(strlen("--boot-image=")).data();
+      } else if (option.starts_with("--android-root=")) {
+        android_root_ = option.substr(strlen("--android-root=")).data();
+      } else if (option.starts_with("--instruction-set=")) {
+        StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
+        // StringPiece is not necessarily zero-terminated, so need to make a copy and ensure it.
+        std::unique_ptr<char[]> buf(new char[instruction_set_str.length() + 1]);
+        strncpy(buf.get(), instruction_set_str.data(), instruction_set_str.length());
+        buf.get()[instruction_set_str.length()] = 0;
+        instruction_set_ = GetInstructionSetFromString(buf.get());
+        // arm actually means thumb2.
+        if (instruction_set_ == InstructionSet::kArm) {
+          instruction_set_ = InstructionSet::kThumb2;
+        }
+      } 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();
+        if (instruction_set_features_.get() == nullptr) {
+          instruction_set_features_.reset(
+              InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+          if (instruction_set_features_.get() == nullptr) {
+            Usage("Problem initializing default instruction set features variant: %s",
+                  error_msg.c_str());
+          }
+        }
+        instruction_set_features_.reset(
+            instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg));
+        if (instruction_set_features_.get() == nullptr) {
+          Usage("Error parsing '%s': %s", option.data(), error_msg.c_str());
+        }
+      } else if (option.starts_with("--compiler-backend=")) {
+        StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
+        if (backend_str == "Quick") {
+          compiler_kind_ = Compiler::kQuick;
+        } else if (backend_str == "Optimizing") {
+          compiler_kind_ = Compiler::kOptimizing;
+        } else {
+          Usage("Unknown compiler backend: %s", backend_str.data());
+        }
+      } 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)) {
+          Usage("Failed to parse --huge-method-max '%s' as an integer", threshold);
+        }
+        if (huge_method_threshold < 0) {
+          Usage("--huge-method-max passed a negative value %s", huge_method_threshold);
+        }
+      } else if (option.starts_with("--large-method-max=")) {
+        const char* threshold = option.substr(strlen("--large-method-max=")).data();
+        if (!ParseInt(threshold, &large_method_threshold)) {
+          Usage("Failed to parse --large-method-max '%s' as an integer", threshold);
+        }
+        if (large_method_threshold < 0) {
+          Usage("--large-method-max passed a negative value %s", large_method_threshold);
+        }
+      } else if (option.starts_with("--small-method-max=")) {
+        const char* threshold = option.substr(strlen("--small-method-max=")).data();
+        if (!ParseInt(threshold, &small_method_threshold)) {
+          Usage("Failed to parse --small-method-max '%s' as an integer", threshold);
+        }
+        if (small_method_threshold < 0) {
+          Usage("--small-method-max passed a negative value %s", small_method_threshold);
+        }
+      } else if (option.starts_with("--tiny-method-max=")) {
+        const char* threshold = option.substr(strlen("--tiny-method-max=")).data();
+        if (!ParseInt(threshold, &tiny_method_threshold)) {
+          Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold);
+        }
+        if (tiny_method_threshold < 0) {
+          Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold);
+        }
+      } else if (option.starts_with("--num-dex-methods=")) {
+        const char* threshold = option.substr(strlen("--num-dex-methods=")).data();
+        if (!ParseInt(threshold, &num_dex_methods_threshold)) {
+          Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold);
+        }
+        if (num_dex_methods_threshold < 0) {
+          Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold);
+        }
+      } else if (option == "--host") {
+        is_host_ = true;
+      } else if (option == "--runtime-arg") {
+        if (++i >= argc) {
+          Usage("Missing required argument for --runtime-arg");
+        }
+        if (log_options) {
+          LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+        }
+        runtime_args_.push_back(argv[i]);
+      } else if (option == "--dump-timing") {
+        dump_timing_ = true;
+      } else if (option == "--dump-passes") {
+        dump_passes_ = true;
+      } else if (option.starts_with("--dump-cfg=")) {
+        dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data();
+      } else if (option == "--dump-stats") {
+        dump_stats_ = true;
+      } else if (option == "--include-debug-symbols" || option == "--no-strip-symbols") {
+        include_debug_symbols = true;
+      } else if (option == "--no-include-debug-symbols" || option == "--strip-symbols") {
+        include_debug_symbols = false;
+        generate_gdb_information = false;  // Depends on debug symbols, see above.
+      } else if (option.starts_with("--profile-file=")) {
+        profile_file_ = option.substr(strlen("--profile-file=")).data();
+        VLOG(compiler) << "dex2oat: profile file is " << profile_file_;
+      } else if (option == "--no-profile-file") {
+        // No profile
+      } else if (option.starts_with("--top-k-profile-threshold=")) {
+        ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold);
+      } else if (option == "--print-pass-names") {
+        PassDriverMEOpts::PrintPassNames();
+      } else if (option.starts_with("--disable-passes=")) {
+        std::string disable_passes = option.substr(strlen("--disable-passes=")).data();
+        PassDriverMEOpts::CreateDefaultPassList(disable_passes);
+      } else if (option.starts_with("--print-passes=")) {
+        std::string print_passes = option.substr(strlen("--print-passes=")).data();
+        PassDriverMEOpts::SetPrintPassList(print_passes);
+      } else if (option == "--print-all-passes") {
+        PassDriverMEOpts::SetPrintAllPasses();
+      } else if (option.starts_with("--dump-cfg-passes=")) {
+        std::string dump_passes_string = option.substr(strlen("--dump-cfg-passes=")).data();
+        PassDriverMEOpts::SetDumpPassList(dump_passes_string);
+      } else if (option == "--print-pass-options") {
+        print_pass_options = true;
+      } else if (option.starts_with("--pass-options=")) {
+        std::string options = option.substr(strlen("--pass-options=")).data();
+        PassDriverMEOpts::SetOverriddenPassOptions(options);
+      } else if (option == "--include-patch-information") {
+        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 if (option.starts_with("--dump-init-failures=")) {
+        std::string file_name = option.substr(strlen("--dump-init-failures=")).data();
+        init_failure_output_.reset(new std::ofstream(file_name));
+        if (init_failure_output_.get() == nullptr) {
+          LOG(ERROR) << "Failed to allocate ofstream";
+        } else if (init_failure_output_->fail()) {
+          LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization "
+                     << "failures.";
+          init_failure_output_.reset();
+        }
+      } else if (option.starts_with("--swap-file=")) {
+        swap_file_name_ = option.substr(strlen("--swap-file=")).data();
+      } else if (option.starts_with("--swap-fd=")) {
+        const char* swap_fd_str = option.substr(strlen("--swap-fd=")).data();
+        if (!ParseInt(swap_fd_str, &swap_fd_)) {
+          Usage("Failed to parse --swap-fd argument '%s' as an integer", swap_fd_str);
+        }
+        if (swap_fd_ < 0) {
+          Usage("--swap-fd passed a negative value %d", swap_fd_);
+        }
+      } else {
+        Usage("Unknown argument %s", option.data());
       }
     }
-  }
-  // Ensure opened dex files are writable for dex-to-dex transformations.
-  for (const auto& dex_file : dex_files) {
-    if (!dex_file->EnableWrite()) {
-      PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
+
+    if (compiler_kind_ == Compiler::kOptimizing) {
+      // Optimizing only supports PIC mode.
+      compile_pic = true;
+    }
+
+    if (oat_filename_.empty() && oat_fd_ == -1) {
+      Usage("Output must be supplied with either --oat-file or --oat-fd");
+    }
+
+    if (!oat_filename_.empty() && oat_fd_ != -1) {
+      Usage("--oat-file should not be used with --oat-fd");
+    }
+
+    if (!oat_symbols.empty() && oat_fd_ != -1) {
+      Usage("--oat-symbols should not be used with --oat-fd");
+    }
+
+    if (!oat_symbols.empty() && is_host_) {
+      Usage("--oat-symbols should not be used with --host");
+    }
+
+    if (oat_fd_ != -1 && !image_filename_.empty()) {
+      Usage("--oat-fd should not be used with --image");
+    }
+
+    if (android_root_.empty()) {
+      const char* android_root_env_var = getenv("ANDROID_ROOT");
+      if (android_root_env_var == nullptr) {
+        Usage("--android-root unspecified and ANDROID_ROOT not set");
+      }
+      android_root_ += android_root_env_var;
+    }
+
+    image_ = (!image_filename_.empty());
+    if (!image_ && boot_image_filename.empty()) {
+      boot_image_filename += android_root_;
+      boot_image_filename += "/framework/boot.art";
+    }
+    if (!boot_image_filename.empty()) {
+      boot_image_option_ += "-Ximage:";
+      boot_image_option_ += boot_image_filename;
+    }
+
+    if (image_classes_filename_ != nullptr && !image_) {
+      Usage("--image-classes should only be used with --image");
+    }
+
+    if (image_classes_filename_ != nullptr && !boot_image_option_.empty()) {
+      Usage("--image-classes should not be used with --boot-image");
+    }
+
+    if (image_classes_zip_filename_ != nullptr && image_classes_filename_ == nullptr) {
+      Usage("--image-classes-zip should be used with --image-classes");
+    }
+
+    if (compiled_classes_filename_ != nullptr && !image_) {
+      Usage("--compiled-classes should only be used with --image");
+    }
+
+    if (compiled_classes_filename_ != nullptr && !boot_image_option_.empty()) {
+      Usage("--compiled-classes should not be used with --boot-image");
+    }
+
+    if (compiled_classes_zip_filename_ != nullptr && compiled_classes_filename_ == nullptr) {
+      Usage("--compiled-classes-zip should be used with --compiled-classes");
+    }
+
+    if (dex_filenames_.empty() && zip_fd_ == -1) {
+      Usage("Input must be supplied with either --dex-file or --zip-fd");
+    }
+
+    if (!dex_filenames_.empty() && zip_fd_ != -1) {
+      Usage("--dex-file should not be used with --zip-fd");
+    }
+
+    if (!dex_filenames_.empty() && !zip_location_.empty()) {
+      Usage("--dex-file should not be used with --zip-location");
+    }
+
+    if (dex_locations_.empty()) {
+      for (const char* dex_file_name : dex_filenames_) {
+        dex_locations_.push_back(dex_file_name);
+      }
+    } else if (dex_locations_.size() != dex_filenames_.size()) {
+      Usage("--dex-location arguments do not match --dex-file arguments");
+    }
+
+    if (zip_fd_ != -1 && zip_location_.empty()) {
+      Usage("--zip-location should be supplied with --zip-fd");
+    }
+
+    if (boot_image_option_.empty()) {
+      if (image_base_ == 0) {
+        Usage("Non-zero --base not specified");
+      }
+    }
+
+    oat_stripped_ = oat_filename_;
+    if (!oat_symbols.empty()) {
+      oat_unstripped_ = oat_symbols;
+    } else {
+      oat_unstripped_ = oat_filename_;
+    }
+
+    // If no instruction set feature was given, use the default one for the target
+    // instruction set.
+    if (instruction_set_features_.get() == nullptr) {
+      instruction_set_features_.reset(
+          InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+      if (instruction_set_features_.get() == nullptr) {
+        Usage("Problem initializing default instruction set features variant: %s",
+              error_msg.c_str());
+      }
+    }
+
+    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();
+      }
+    }
+
+    if (compiler_filter_string == nullptr) {
+      if (instruction_set_ == kMips &&
+          reinterpret_cast<const MipsInstructionSetFeatures*>(instruction_set_features_.get())->
+          IsR6()) {
+        // For R6, only interpreter mode is working.
+        // TODO: fix compiler for Mips32r6.
+        compiler_filter_string = "interpret-only";
+      } else if (instruction_set_ == kMips64) {
+        // For Mips64, can only compile in interpreter mode.
+        // TODO: fix compiler for Mips64.
+        compiler_filter_string = "interpret-only";
+      } else if (image_) {
+        compiler_filter_string = "speed";
+      } else {
+        // TODO: Migrate SMALL mode to command line option.
+  #if ART_SMALL_MODE
+        compiler_filter_string = "interpret-only";
+  #else
+        compiler_filter_string = "speed";
+  #endif
+      }
+    }
+    CHECK(compiler_filter_string != nullptr);
+    CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
+    if (strcmp(compiler_filter_string, "verify-none") == 0) {
+      compiler_filter = CompilerOptions::kVerifyNone;
+    } else if (strcmp(compiler_filter_string, "interpret-only") == 0) {
+      compiler_filter = CompilerOptions::kInterpretOnly;
+    } else if (strcmp(compiler_filter_string, "space") == 0) {
+      compiler_filter = CompilerOptions::kSpace;
+    } else if (strcmp(compiler_filter_string, "balanced") == 0) {
+      compiler_filter = CompilerOptions::kBalanced;
+    } else if (strcmp(compiler_filter_string, "speed") == 0) {
+      compiler_filter = CompilerOptions::kSpeed;
+    } else if (strcmp(compiler_filter_string, "everything") == 0) {
+      compiler_filter = CompilerOptions::kEverything;
+    } else if (strcmp(compiler_filter_string, "time") == 0) {
+      compiler_filter = CompilerOptions::kTime;
+    } else {
+      Usage("Unknown --compiler-filter value %s", compiler_filter_string);
+    }
+
+    // Checks are all explicit until we know the architecture.
+    bool implicit_null_checks = false;
+    bool implicit_so_checks = false;
+    bool implicit_suspend_checks = false;
+    // Set the compilation target's implicit checks options.
+    switch (instruction_set_) {
+      case kArm:
+      case kThumb2:
+      case kArm64:
+      case kX86:
+      case kX86_64:
+        implicit_null_checks = true;
+        implicit_so_checks = true;
+        break;
+
+      default:
+        // Defaults are correct.
+        break;
+    }
+
+    if (print_pass_options) {
+      PassDriverMEOpts::PrintPassOptions();
+    }
+
+    compiler_options_.reset(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,
+                                                verbose_methods_.empty() ?
+                                                    nullptr :
+                                                    &verbose_methods_,
+                                                init_failure_output_.get()));
+
+    // Done with usage checks, enable watchdog if requested
+    if (watch_dog_enabled) {
+      watchdog_.reset(new WatchDog(true));
+    }
+
+    // Fill some values into the key-value store for the oat header.
+    key_value_store_.reset(new SafeMap<std::string, std::string>());
+
+    // Insert some compiler things.
+    {
+      std::ostringstream oss;
+      for (int i = 0; i < argc; ++i) {
+        if (i > 0) {
+          oss << ' ';
+        }
+        oss << argv[i];
+      }
+      key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
+      oss.str("");  // Reset.
+      oss << kRuntimeISA;
+      key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
+      key_value_store_->Put(OatHeader::kPicKey, compile_pic ? "true" : "false");
     }
   }
 
-  /*
-   * If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
-   * Don't bother to check if we're doing the image.
-   */
-  if (!image && compiler_options->IsCompilationEnabled() && compiler_kind == Compiler::kQuick) {
-    size_t num_methods = 0;
-    for (size_t i = 0; i != dex_files.size(); ++i) {
-      const DexFile* dex_file = dex_files[i];
-      CHECK(dex_file != nullptr);
-      num_methods += dex_file->NumMethodIds();
+  // Check whether the oat output file is writable, and open it for later. Also open a swap file,
+  // if a name is given.
+  bool OpenFile() {
+    bool create_file = !oat_unstripped_.empty();  // as opposed to using open file descriptor
+    if (create_file) {
+      oat_file_.reset(OS::CreateEmptyFile(oat_unstripped_.c_str()));
+      if (oat_location_.empty()) {
+        oat_location_ = oat_filename_;
+      }
+    } else {
+      oat_file_.reset(new File(oat_fd_, oat_location_, true));
+      oat_file_->DisableAutoClose();
+      if (oat_file_->SetLength(0) != 0) {
+        PLOG(WARNING) << "Truncating oat file " << oat_location_ << " failed.";
+      }
     }
-    if (num_methods <= compiler_options->GetNumDexMethodsThreshold()) {
-      compiler_options->SetCompilerFilter(CompilerOptions::kSpeed);
-      VLOG(compiler) << "Below method threshold, compiling anyways";
+    if (oat_file_.get() == nullptr) {
+      PLOG(ERROR) << "Failed to create oat file: " << oat_location_;
+      return false;
     }
-  }
-
-  // Fill some values into the key-value store for the oat header.
-  std::unique_ptr<SafeMap<std::string, std::string> > key_value_store(
-      new SafeMap<std::string, std::string>());
-
-  // Insert some compiler things.
-  std::ostringstream oss;
-  for (int i = 0; i < argc; ++i) {
-    if (i > 0) {
-      oss << ' ';
+    if (create_file && fchmod(oat_file_->Fd(), 0644) != 0) {
+      PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location_;
+      oat_file_->Erase();
+      return false;
     }
-    oss << argv[i];
-  }
-  key_value_store->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
-  oss.str("");  // Reset.
-  oss << kRuntimeISA;
-  key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str());
 
-  dex2oat->Compile(boot_image_option,
-                   dex_files,
-                   bitcode_filename,
-                   image,
-                   image_classes,
-                   dump_stats,
-                   dump_passes,
-                   &timings,
-                   &compiler_phases_timings,
-                   profile_file);
+    // Swap file handling.
+    //
+    // If the swap fd is not -1, we assume this is the file descriptor of an open but unlinked file
+    // that we can use for swap.
+    //
+    // If the swap fd is -1 and we have a swap-file string, open the given file as a swap file. We
+    // will immediately unlink to satisfy the swap fd assumption.
+    if (swap_fd_ == -1 && !swap_file_name_.empty()) {
+      std::unique_ptr<File> swap_file(OS::CreateEmptyFile(swap_file_name_.c_str()));
+      if (swap_file.get() == nullptr) {
+        PLOG(ERROR) << "Failed to create swap file: " << swap_file_name_;
+        return false;
+      }
+      swap_fd_ = swap_file->Fd();
+      swap_file->MarkUnchecked();     // We don't we to track this, it will be unlinked immediately.
+      swap_file->DisableAutoClose();  // We'll handle it ourselves, the File object will be
+                                      // released immediately.
+      unlink(swap_file_name_.c_str());
+    }
 
-  if (image) {
-    dex2oat->PrepareImageWriter(image_base);
+    return true;
   }
 
-  if (!dex2oat->CreateOatFile(dex_files,
-                              android_root,
-                              is_host,
-                              oat_file.get(),
-                              oat_location,
-                              &timings,
-                              key_value_store.get())) {
-    LOG(ERROR) << "Failed to create oat file: " << oat_location;
-    return EXIT_FAILURE;
+  void EraseOatFile() {
+    DCHECK(oat_file_.get() != nullptr);
+    oat_file_->Erase();
+    oat_file_.reset();
   }
 
-  VLOG(compiler) << "Oat file written successfully (unstripped): " << oat_location;
+  // Set up the environment for compilation. Includes starting the runtime and loading/opening the
+  // boot class path.
+  bool Setup() {
+    TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
+    RuntimeOptions runtime_options;
+    art::MemMap::Init();  // For ZipEntry::ExtractToMemMap.
+    if (boot_image_option_.empty()) {
+      std::string boot_class_path = "-Xbootclasspath:";
+      boot_class_path += Join(dex_filenames_, ':');
+      runtime_options.push_back(std::make_pair(boot_class_path, nullptr));
+      std::string boot_class_path_locations = "-Xbootclasspath-locations:";
+      boot_class_path_locations += Join(dex_locations_, ':');
+      runtime_options.push_back(std::make_pair(boot_class_path_locations, nullptr));
+    } else {
+      runtime_options.push_back(std::make_pair(boot_image_option_, nullptr));
+    }
+    for (size_t i = 0; i < runtime_args_.size(); i++) {
+      runtime_options.push_back(std::make_pair(runtime_args_[i], nullptr));
+    }
+
+    verification_results_.reset(new VerificationResults(compiler_options_.get()));
+    callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(), &method_inliner_map_));
+    runtime_options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
+    runtime_options.push_back(
+        std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_)));
+
+    if (!CreateRuntime(runtime_options)) {
+      return false;
+    }
+
+    // Runtime::Create acquired the mutator_lock_ that is normally given away when we
+    // Runtime::Start, give it away now so that we don't starve GC.
+    Thread* self = Thread::Current();
+    self->TransitionFromRunnableToSuspended(kNative);
+    // If we're doing the image, override the compiler filter to force full compilation. Must be
+    // done ahead of WellKnownClasses::Init that causes verification.  Note: doesn't force
+    // compilation of class initializers.
+    // Whilst we're in native take the opportunity to initialize well known classes.
+    WellKnownClasses::Init(self->GetJniEnv());
+
+    // If --image-classes was specified, calculate the full list of classes to include in the image
+    if (image_classes_filename_ != nullptr) {
+      std::string error_msg;
+      if (image_classes_zip_filename_ != nullptr) {
+        image_classes_.reset(ReadImageClassesFromZip(image_classes_zip_filename_,
+                                                    image_classes_filename_,
+                                                    &error_msg));
+      } else {
+        image_classes_.reset(ReadImageClassesFromFile(image_classes_filename_));
+      }
+      if (image_classes_.get() == nullptr) {
+        LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename_ <<
+            "': " << error_msg;
+        return false;
+      }
+    } else if (image_) {
+      image_classes_.reset(new std::set<std::string>);
+    }
+    // If --compiled-classes was specified, calculate the full list of classes to compile in the
+    // image.
+    if (compiled_classes_filename_ != nullptr) {
+      std::string error_msg;
+      if (compiled_classes_zip_filename_ != nullptr) {
+        compiled_classes_.reset(ReadImageClassesFromZip(compiled_classes_zip_filename_,
+                                                        compiled_classes_filename_,
+                                                        &error_msg));
+      } else {
+        compiled_classes_.reset(ReadImageClassesFromFile(compiled_classes_filename_));
+      }
+      if (compiled_classes_.get() == nullptr) {
+        LOG(ERROR) << "Failed to create list of compiled classes from '"
+                   << compiled_classes_filename_ << "': " << error_msg;
+        return false;
+      }
+    } else if (image_) {
+      compiled_classes_.reset(nullptr);  // By default compile everything.
+    }
+
+    if (boot_image_option_.empty()) {
+      dex_files_ = Runtime::Current()->GetClassLinker()->GetBootClassPath();
+    } else {
+      if (dex_filenames_.empty()) {
+        ATRACE_BEGIN("Opening zip archive from file descriptor");
+        std::string error_msg;
+        std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd_,
+                                                                       zip_location_.c_str(),
+                                                                       &error_msg));
+        if (zip_archive.get() == nullptr) {
+          LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location_ << "': "
+              << error_msg;
+          return false;
+        }
+        if (!DexFile::OpenFromZip(*zip_archive.get(), zip_location_, &error_msg, &opened_dex_files_)) {
+          LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location_
+              << "': " << error_msg;
+          return false;
+        }
+        for (auto& dex_file : opened_dex_files_) {
+          dex_files_.push_back(dex_file.get());
+        }
+        ATRACE_END();
+      } else {
+        size_t failure_count = OpenDexFiles(dex_filenames_, dex_locations_, &opened_dex_files_);
+        if (failure_count > 0) {
+          LOG(ERROR) << "Failed to open some dex files: " << failure_count;
+          return false;
+        }
+        for (auto& dex_file : opened_dex_files_) {
+          dex_files_.push_back(dex_file.get());
+        }
+      }
+
+      constexpr bool kSaveDexInput = false;
+      if (kSaveDexInput) {
+        for (size_t i = 0; i < dex_files_.size(); ++i) {
+          const DexFile* dex_file = dex_files_[i];
+          std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex",
+                                                 getpid(), i));
+          std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
+          if (tmp_file.get() == nullptr) {
+            PLOG(ERROR) << "Failed to open file " << tmp_file_name
+                << ". Try: adb shell chmod 777 /data/local/tmp";
+            continue;
+          }
+          // This is just dumping files for debugging. Ignore errors, and leave remnants.
+          UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size()));
+          UNUSED(tmp_file->Flush());
+          UNUSED(tmp_file->Close());
+          LOG(INFO) << "Wrote input to " << tmp_file_name;
+        }
+      }
+    }
+    // Ensure opened dex files are writable for dex-to-dex transformations.
+    for (const auto& dex_file : dex_files_) {
+      if (!dex_file->EnableWrite()) {
+        PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
+      }
+    }
+
+    // If we use a swap file, ensure we are above the threshold to make it necessary.
+    if (swap_fd_ != -1) {
+      if (!UseSwap(image_, dex_files_)) {
+        close(swap_fd_);
+        swap_fd_ = -1;
+        LOG(INFO) << "Decided to run without swap.";
+      } else {
+        LOG(INFO) << "Accepted running with swap.";
+      }
+    }
+    // Note that dex2oat won't close the swap_fd_. The compiler driver's swap space will do that.
+
+    /*
+     * If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
+     * Don't bother to check if we're doing the image.
+     */
+    if (!image_ &&
+        compiler_options_->IsCompilationEnabled() &&
+        compiler_kind_ == Compiler::kQuick) {
+      size_t num_methods = 0;
+      for (size_t i = 0; i != dex_files_.size(); ++i) {
+        const DexFile* dex_file = dex_files_[i];
+        CHECK(dex_file != nullptr);
+        num_methods += dex_file->NumMethodIds();
+      }
+      if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {
+        compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);
+        VLOG(compiler) << "Below method threshold, compiling anyways";
+      }
+    }
+
+    return true;
+  }
+
+  // Create and invoke the compiler driver. This will compile all the dex files.
+  void Compile() {
+    TimingLogger::ScopedTiming t("dex2oat Compile", timings_);
+    compiler_phases_timings_.reset(new CumulativeLogger("compilation times"));
+
+    // Handle and ClassLoader creation needs to come after Runtime::Create
+    jobject class_loader = nullptr;
+    Thread* self = Thread::Current();
+    if (!boot_image_option_.empty()) {
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      OpenClassPathFiles(runtime_->GetClassPathString(), dex_files_, &class_path_files_);
+      ScopedObjectAccess soa(self);
+      std::vector<const DexFile*> class_path_files(dex_files_);
+      for (auto& class_path_file : class_path_files_) {
+        class_path_files.push_back(class_path_file.get());
+      }
+
+      for (size_t i = 0; i < class_path_files.size(); i++) {
+        class_linker->RegisterDexFile(*class_path_files[i]);
+      }
+      soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);
+      ScopedLocalRef<jobject> class_loader_local(soa.Env(),
+          soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
+      class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
+      Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
+    }
+
+    driver_.reset(new CompilerDriver(compiler_options_.get(),
+                                     verification_results_.get(),
+                                     &method_inliner_map_,
+                                     compiler_kind_,
+                                     instruction_set_,
+                                     instruction_set_features_.get(),
+                                     image_,
+                                     image_classes_.release(),
+                                     compiled_classes_.release(),
+                                     thread_count_,
+                                     dump_stats_,
+                                     dump_passes_,
+                                     dump_cfg_file_name_,
+                                     compiler_phases_timings_.get(),
+                                     swap_fd_,
+                                     profile_file_));
+
+    driver_->CompileAll(class_loader, dex_files_, timings_);
+  }
 
   // Notes on the interleaving of creating the image and oat file to
   // ensure the references between the two are correct.
@@ -1504,87 +1307,546 @@
   //
   // Steps 1.-3. are done by the CreateOatFile() above, steps 4.-5.
   // are done by the CreateImageFile() below.
-  //
-  if (image) {
-    TimingLogger::ScopedTiming t("dex2oat ImageWriter", &timings);
-    bool image_creation_success = dex2oat->CreateImageFile(image_filename,
-                                                           oat_unstripped,
-                                                           oat_location);
-    if (!image_creation_success) {
-      return EXIT_FAILURE;
+
+
+  // Write out the generated code part. Calls the OatWriter and ElfBuilder. Also prepares the
+  // ImageWriter, if necessary.
+  // Note: Flushing (and closing) the file is the caller's responsibility, except for the failure
+  //       case (when the file will be explicitly erased).
+  bool CreateOatFile() {
+    CHECK(key_value_store_.get() != nullptr);
+
+    TimingLogger::ScopedTiming t("dex2oat Oat", timings_);
+
+    std::unique_ptr<OatWriter> oat_writer;
+    {
+      TimingLogger::ScopedTiming t2("dex2oat OatWriter", timings_);
+      std::string image_file_location;
+      uint32_t image_file_location_oat_checksum = 0;
+      uintptr_t image_file_location_oat_data_begin = 0;
+      int32_t image_patch_delta = 0;
+      if (image_) {
+        PrepareImageWriter(image_base_);
+      } else {
+        TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
+        gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
+        image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
+        image_file_location_oat_data_begin =
+            reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin());
+        image_file_location = image_space->GetImageFilename();
+        image_patch_delta = image_space->GetImageHeader().GetPatchDelta();
+      }
+
+      if (!image_file_location.empty()) {
+        key_value_store_->Put(OatHeader::kImageLocationKey, image_file_location);
+      }
+
+      oat_writer.reset(new OatWriter(dex_files_, image_file_location_oat_checksum,
+                                     image_file_location_oat_data_begin,
+                                     image_patch_delta,
+                                     driver_.get(),
+                                     image_writer_.get(),
+                                     timings_,
+                                     key_value_store_.get()));
     }
-    VLOG(compiler) << "Image written successfully: " << image_filename;
+
+    if (image_) {
+      // The OatWriter constructor has already updated offsets in methods and we need to
+      // prepare method offsets in the image address space for direct method patching.
+      TimingLogger::ScopedTiming t2("dex2oat Prepare image address space", timings_);
+      if (!image_writer_->PrepareImageAddressSpace()) {
+        LOG(ERROR) << "Failed to prepare image address space.";
+        return false;
+      }
+    }
+
+    {
+      TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_);
+      if (!driver_->WriteElf(android_root_, is_host_, dex_files_, oat_writer.get(),
+                             oat_file_.get())) {
+        LOG(ERROR) << "Failed to write ELF file " << oat_file_->GetPath();
+        return false;
+      }
+    }
+
+    VLOG(compiler) << "Oat file written successfully (unstripped): " << oat_location_;
+    return true;
   }
 
-  if (is_host) {
-    timings.EndTiming();
-    if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
-      LOG(INFO) << Dumpable<TimingLogger>(timings);
+  // If we are compiling an image, invoke the image creation routine. Else just skip.
+  bool HandleImage() {
+    if (image_) {
+      TimingLogger::ScopedTiming t("dex2oat ImageWriter", timings_);
+      if (!CreateImageFile()) {
+        return false;
+      }
+      VLOG(compiler) << "Image written successfully: " << image_filename_;
     }
-    if (dump_passes) {
-      LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
+    return true;
+  }
+
+  // Create a copy from unstripped to stripped.
+  bool CopyUnstrippedToStripped() {
+    // If we don't want to strip in place, copy from unstripped location to stripped location.
+    // We need to strip after image creation because FixupElf needs to use .strtab.
+    if (oat_unstripped_ != oat_stripped_) {
+      // If the oat file is still open, flush it.
+      if (oat_file_.get() != nullptr && oat_file_->IsOpened()) {
+        if (!FlushCloseOatFile()) {
+          return false;
+        }
+      }
+
+      TimingLogger::ScopedTiming t("dex2oat OatFile copy", timings_);
+      std::unique_ptr<File> in(OS::OpenFileForReading(oat_unstripped_.c_str()));
+      std::unique_ptr<File> out(OS::CreateEmptyFile(oat_stripped_.c_str()));
+      size_t buffer_size = 8192;
+      std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+      while (true) {
+        int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size));
+        if (bytes_read <= 0) {
+          break;
+        }
+        bool write_ok = out->WriteFully(buffer.get(), bytes_read);
+        CHECK(write_ok);
+      }
+      if (out->FlushCloseOrErase() != 0) {
+        PLOG(ERROR) << "Failed to flush and close copied oat file: " << oat_stripped_;
+        return false;
+      }
+      VLOG(compiler) << "Oat file copied successfully (stripped): " << oat_stripped_;
     }
+    return true;
+  }
+
+  bool FlushOatFile() {
+    if (oat_file_.get() != nullptr) {
+      TimingLogger::ScopedTiming t2("dex2oat Flush ELF", timings_);
+      if (oat_file_->Flush() != 0) {
+        PLOG(ERROR) << "Failed to flush oat file: " << oat_location_ << " / "
+            << oat_filename_;
+        oat_file_->Erase();
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool FlushCloseOatFile() {
+    if (oat_file_.get() != nullptr) {
+      std::unique_ptr<File> tmp(oat_file_.release());
+      if (tmp->FlushCloseOrErase() != 0) {
+        PLOG(ERROR) << "Failed to flush and close oat file: " << oat_location_ << " / "
+            << oat_filename_;
+        return false;
+      }
+    }
+    return true;
+  }
+
+  void DumpTiming() {
+    if (dump_timing_ || (dump_slow_timing_ && timings_->GetTotalNs() > MsToNs(1000))) {
+      LOG(INFO) << Dumpable<TimingLogger>(*timings_);
+    }
+    if (dump_passes_) {
+      LOG(INFO) << Dumpable<CumulativeLogger>(*driver_->GetTimingsLogger());
+    }
+  }
+
+  CompilerOptions* GetCompilerOptions() const {
+    return compiler_options_.get();
+  }
+
+  bool IsImage() const {
+    return image_;
+  }
+
+  bool IsHost() const {
+    return is_host_;
+  }
+
+ private:
+  static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames,
+                             const std::vector<const char*>& dex_locations,
+                             std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+    DCHECK(dex_files != nullptr) << "OpenDexFiles out-param is NULL";
+    size_t failure_count = 0;
+    for (size_t i = 0; i < dex_filenames.size(); i++) {
+      const char* dex_filename = dex_filenames[i];
+      const char* dex_location = dex_locations[i];
+      ATRACE_BEGIN(StringPrintf("Opening dex file '%s'", dex_filenames[i]).c_str());
+      std::string error_msg;
+      if (!OS::FileExists(dex_filename)) {
+        LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
+        continue;
+      }
+      if (!DexFile::Open(dex_filename, dex_location, &error_msg, dex_files)) {
+        LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
+        ++failure_count;
+      }
+      ATRACE_END();
+    }
+    return failure_count;
+  }
+
+  // Returns true if dex_files has a dex with the named location.
+  static bool DexFilesContains(const std::vector<const DexFile*>& dex_files,
+                               const std::string& location) {
+    for (size_t i = 0; i < dex_files.size(); ++i) {
+      if (dex_files[i]->GetLocation() == location) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Appends to opened_dex_files any elements of class_path that dex_files
+  // doesn't already contain. This will open those dex files as necessary.
+  static void OpenClassPathFiles(const std::string& class_path,
+                                 std::vector<const DexFile*> dex_files,
+                                 std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
+    DCHECK(opened_dex_files != nullptr) << "OpenClassPathFiles out-param is NULL";
+    std::vector<std::string> 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) {
+      if (DexFilesContains(dex_files, parsed[i])) {
+        continue;
+      }
+      std::string error_msg;
+      if (!DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg, opened_dex_files)) {
+        LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "': " << error_msg;
+      }
+    }
+  }
+
+  // Create a runtime necessary for compilation.
+  bool CreateRuntime(const RuntimeOptions& runtime_options)
+      SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
+    if (!Runtime::Create(runtime_options, false)) {
+      LOG(ERROR) << "Failed to create runtime";
+      return false;
+    }
+    Runtime* runtime = Runtime::Current();
+    runtime->SetInstructionSet(instruction_set_);
+    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+      if (!runtime->HasCalleeSaveMethod(type)) {
+        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(), type);
+      }
+    }
+    runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
+    runtime->GetClassLinker()->RunRootClinits();
+    runtime_ = runtime;
+    return true;
+  }
+
+  void PrepareImageWriter(uintptr_t image_base) {
+    image_writer_.reset(new ImageWriter(*driver_, image_base, compiler_options_->GetCompilePic()));
+  }
+
+  // Let the ImageWriter write the image file. If we do not compile PIC, also fix up the oat file.
+  bool CreateImageFile()
+      LOCKS_EXCLUDED(Locks::mutator_lock_) {
+    CHECK(image_writer_ != nullptr);
+    if (!image_writer_->Write(image_filename_, oat_unstripped_, oat_location_)) {
+      LOG(ERROR) << "Failed to create image file " << image_filename_;
+      return false;
+    }
+    uintptr_t oat_data_begin = image_writer_->GetOatDataBegin();
+
+    // Destroy ImageWriter before doing FixupElf.
+    image_writer_.reset();
+
+    // Do not fix up the ELF file if we are --compile-pic
+    if (!compiler_options_->GetCompilePic()) {
+      std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_unstripped_.c_str()));
+      if (oat_file.get() == nullptr) {
+        PLOG(ERROR) << "Failed to open ELF file: " << oat_unstripped_;
+        return false;
+      }
+
+      if (!ElfWriter::Fixup(oat_file.get(), oat_data_begin)) {
+        oat_file->Erase();
+        LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
+        return false;
+      }
+
+      if (oat_file->FlushCloseOrErase()) {
+        PLOG(ERROR) << "Failed to flush and close fixed ELF file " << oat_file->GetPath();
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
+  static std::set<std::string>* ReadImageClassesFromFile(const char* image_classes_filename) {
+    std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
+                                                                        std::ifstream::in));
+    if (image_classes_file.get() == nullptr) {
+      LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
+      return nullptr;
+    }
+    std::unique_ptr<std::set<std::string>> result(ReadImageClasses(*image_classes_file));
+    image_classes_file->close();
+    return result.release();
+  }
+
+  static std::set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {
+    std::unique_ptr<std::set<std::string>> image_classes(new std::set<std::string>);
+    while (image_classes_stream.good()) {
+      std::string dot;
+      std::getline(image_classes_stream, dot);
+      if (StartsWith(dot, "#") || dot.empty()) {
+        continue;
+      }
+      std::string descriptor(DotToDescriptor(dot.c_str()));
+      image_classes->insert(descriptor);
+    }
+    return image_classes.release();
+  }
+
+  // Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
+  static std::set<std::string>* ReadImageClassesFromZip(const char* zip_filename,
+                                                        const char* image_classes_filename,
+                                                        std::string* error_msg) {
+    std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
+    if (zip_archive.get() == nullptr) {
+      return nullptr;
+    }
+    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
+    if (zip_entry.get() == nullptr) {
+      *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
+                                zip_filename, error_msg->c_str());
+      return nullptr;
+    }
+    std::unique_ptr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(zip_filename,
+                                                                          image_classes_filename,
+                                                                          error_msg));
+    if (image_classes_file.get() == nullptr) {
+      *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
+                                zip_filename, error_msg->c_str());
+      return nullptr;
+    }
+    const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
+                                           image_classes_file->Size());
+    std::istringstream image_classes_stream(image_classes_string);
+    return ReadImageClasses(image_classes_stream);
+  }
+
+  void LogCompletionTime() {
+    LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
+              << " (threads: " << thread_count_ << ") "
+              << driver_->GetMemoryUsageString(kIsDebugBuild || VLOG_IS_ON(compiler));
+  }
+
+  std::unique_ptr<CompilerOptions> compiler_options_;
+  Compiler::Kind compiler_kind_;
+
+  InstructionSet instruction_set_;
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
+
+  std::unique_ptr<SafeMap<std::string, std::string> > key_value_store_;
+
+  std::unique_ptr<VerificationResults> verification_results_;
+  DexFileToMethodInlinerMap method_inliner_map_;
+  std::unique_ptr<QuickCompilerCallbacks> callbacks_;
+
+  // Ownership for the class path files.
+  std::vector<std::unique_ptr<const DexFile>> class_path_files_;
+
+  // Not a unique_ptr as we want to just exit on non-debug builds, not bringing the runtime down
+  // in an orderly fashion. The destructor takes care of deleting this.
+  Runtime* runtime_;
+
+  size_t thread_count_;
+  uint64_t start_ns_;
+  std::unique_ptr<WatchDog> watchdog_;
+  std::unique_ptr<File> oat_file_;
+  std::string oat_stripped_;
+  std::string oat_unstripped_;
+  std::string oat_location_;
+  std::string oat_filename_;
+  int oat_fd_;
+  std::vector<const char*> dex_filenames_;
+  std::vector<const char*> dex_locations_;
+  int zip_fd_;
+  std::string zip_location_;
+  std::string boot_image_option_;
+  std::vector<const char*> runtime_args_;
+  std::string image_filename_;
+  uintptr_t image_base_;
+  const char* image_classes_zip_filename_;
+  const char* image_classes_filename_;
+  const char* compiled_classes_zip_filename_;
+  const char* compiled_classes_filename_;
+  std::unique_ptr<std::set<std::string>> image_classes_;
+  std::unique_ptr<std::set<std::string>> compiled_classes_;
+  bool image_;
+  std::unique_ptr<ImageWriter> image_writer_;
+  bool is_host_;
+  std::string android_root_;
+  std::vector<const DexFile*> dex_files_;
+  std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
+  std::unique_ptr<CompilerDriver> driver_;
+  std::vector<std::string> verbose_methods_;
+  bool dump_stats_;
+  bool dump_passes_;
+  bool dump_timing_;
+  bool dump_slow_timing_;
+  std::string dump_cfg_file_name_;
+  std::string swap_file_name_;
+  int swap_fd_;
+  std::string profile_file_;  // Profile file to use
+  TimingLogger* timings_;
+  std::unique_ptr<CumulativeLogger> compiler_phases_timings_;
+  std::unique_ptr<std::ostream> init_failure_output_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
+};
+
+const unsigned int WatchDog::kWatchDogTimeoutSeconds;
+
+static void b13564922() {
+#if defined(__linux__) && defined(__arm__)
+  int major, minor;
+  struct utsname uts;
+  if (uname(&uts) != -1 &&
+      sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
+      ((major < 3) || ((major == 3) && (minor < 4)))) {
+    // Kernels before 3.4 don't handle the ASLR well and we can run out of address
+    // space (http://b/13564922). Work around the issue by inhibiting further mmap() randomization.
+    int old_personality = personality(0xffffffff);
+    if ((old_personality & ADDR_NO_RANDOMIZE) == 0) {
+      int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+      if (new_personality == -1) {
+        LOG(WARNING) << "personality(. | ADDR_NO_RANDOMIZE) failed.";
+      }
+    }
+  }
+#endif
+}
+
+static int CompileImage(Dex2Oat& dex2oat) {
+  dex2oat.Compile();
+
+  // Create the boot.oat.
+  if (!dex2oat.CreateOatFile()) {
+    dex2oat.EraseOatFile();
+    return EXIT_FAILURE;
+  }
+
+  // Flush and close the boot.oat. We always expect the output file by name, and it will be
+  // re-opened from the unstripped name.
+  if (!dex2oat.FlushCloseOatFile()) {
+    return EXIT_FAILURE;
+  }
+
+  // Creates the boot.art and patches the boot.oat.
+  if (!dex2oat.HandleImage()) {
+    return EXIT_FAILURE;
+  }
+
+  // When given --host, finish early without stripping.
+  if (dex2oat.IsHost()) {
+    dex2oat.DumpTiming();
     return EXIT_SUCCESS;
   }
 
-  // If we don't want to strip in place, copy from unstripped location to stripped location.
-  // We need to strip after image creation because FixupElf needs to use .strtab.
-  if (oat_unstripped != oat_stripped) {
-    TimingLogger::ScopedTiming t("dex2oat OatFile copy", &timings);
-    oat_file.reset();
-     std::unique_ptr<File> in(OS::OpenFileForReading(oat_unstripped.c_str()));
-    std::unique_ptr<File> out(OS::CreateEmptyFile(oat_stripped.c_str()));
-    size_t buffer_size = 8192;
-    std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_size]);
-    while (true) {
-      int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size));
-      if (bytes_read <= 0) {
-        break;
-      }
-      bool write_ok = out->WriteFully(buffer.get(), bytes_read);
-      CHECK(write_ok);
-    }
-    oat_file.reset(out.release());
-    VLOG(compiler) << "Oat file copied successfully (stripped): " << oat_stripped;
+  // Copy unstripped to stripped location, if necessary.
+  if (!dex2oat.CopyUnstrippedToStripped()) {
+    return EXIT_FAILURE;
   }
 
-#if ART_USE_PORTABLE_COMPILER  // We currently only generate symbols on Portable
-  if (!compiler_options.GetIncludeDebugSymbols()) {
-    timings.NewSplit("dex2oat ElfStripper");
-    // Strip unneeded sections for target
-    off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
-    CHECK_EQ(0, seek_actual);
-    std::string error_msg;
-    CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg;
-
-
-    // We wrote the oat file successfully, and want to keep it.
-    VLOG(compiler) << "Oat file written successfully (stripped): " << oat_location;
-  } else {
-    VLOG(compiler) << "Oat file written successfully without stripping: " << oat_location;
-  }
-#endif  // ART_USE_PORTABLE_COMPILER
-
-  timings.EndTiming();
-
-  if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
-    LOG(INFO) << Dumpable<TimingLogger>(timings);
-  }
-  if (dump_passes) {
-    LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
+  // FlushClose again, as stripping might have re-opened the oat file.
+  if (!dex2oat.FlushCloseOatFile()) {
+    return EXIT_FAILURE;
   }
 
-  // Everything was successfully written, do an explicit exit here to avoid running Runtime
-  // destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
-  if (!kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) {
-    dex2oat->LogCompletionTime();
-    exit(EXIT_SUCCESS);
-  }
-
+  dex2oat.DumpTiming();
   return EXIT_SUCCESS;
-}  // NOLINT(readability/fn_size)
+}
+
+static int CompileApp(Dex2Oat& dex2oat) {
+  dex2oat.Compile();
+
+  // Create the app oat.
+  if (!dex2oat.CreateOatFile()) {
+    dex2oat.EraseOatFile();
+    return EXIT_FAILURE;
+  }
+
+  // Do not close the oat file here. We might haven gotten the output file by file descriptor,
+  // which we would lose.
+  if (!dex2oat.FlushOatFile()) {
+    return EXIT_FAILURE;
+  }
+
+  // When given --host, finish early without stripping.
+  if (dex2oat.IsHost()) {
+    if (!dex2oat.FlushCloseOatFile()) {
+      return EXIT_FAILURE;
+    }
+
+    dex2oat.DumpTiming();
+    return EXIT_SUCCESS;
+  }
+
+  // Copy unstripped to stripped location, if necessary. This will implicitly flush & close the
+  // unstripped version. If this is given, we expect to be able to open writable files by name.
+  if (!dex2oat.CopyUnstrippedToStripped()) {
+    return EXIT_FAILURE;
+  }
+
+  // Flush and close the file.
+  if (!dex2oat.FlushCloseOatFile()) {
+    return EXIT_FAILURE;
+  }
+
+  dex2oat.DumpTiming();
+  return EXIT_SUCCESS;
+}
+
+static int dex2oat(int argc, char** argv) {
+  b13564922();
+
+  TimingLogger timings("compiler", false, false);
+
+  Dex2Oat dex2oat(&timings);
+
+  // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError.
+  dex2oat.ParseArgs(argc, argv);
+
+  // Check early that the result of compilation can be written
+  if (!dex2oat.OpenFile()) {
+    return EXIT_FAILURE;
+  }
+
+  LOG(INFO) << CommandLine();
+
+  if (!dex2oat.Setup()) {
+    dex2oat.EraseOatFile();
+    return EXIT_FAILURE;
+  }
+
+  if (dex2oat.IsImage()) {
+    return CompileImage(dex2oat);
+  } else {
+    return CompileApp(dex2oat);
+  }
+}
 }  // namespace art
 
 int main(int argc, char** argv) {
-  return art::dex2oat(argc, argv);
+  int result = art::dex2oat(argc, argv);
+  // Everything was done, do an explicit exit here to avoid running Runtime destructors that take
+  // time (bug 10645725) unless we're a debug build or running on valgrind. Note: The Dex2Oat class
+  // should not destruct the runtime in this case.
+  if (!art::kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) {
+    exit(result);
+  }
+  return result;
 }
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index d67c169..218b23b 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -23,6 +23,7 @@
 	disassembler_arm.cc \
 	disassembler_arm64.cc \
 	disassembler_mips.cc \
+	disassembler_mips64.cc \
 	disassembler_x86.cc
 
 # $(1): target or host
@@ -63,6 +64,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)
@@ -83,11 +85,15 @@
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
   include external/libcxx/libcxx.mk
+  # For disassembler_arm64.
+  ifeq ($$(art_ndebug_or_debug),debug)
+     LOCAL_SHARED_LIBRARIES += libvixld
+  else
+     LOCAL_SHARED_LIBRARIES += libvixl
+  endif
   ifeq ($$(art_target_or_host),target)
-    LOCAL_SHARED_LIBRARIES += libcutils libvixl
     include $(BUILD_SHARED_LIBRARY)
   else # host
-    LOCAL_STATIC_LIBRARIES += libcutils libvixl
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
 endef
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index c97bf64..fbc8dbb 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -16,13 +16,14 @@
 
 #include "disassembler.h"
 
-#include <iostream>
+#include <ostream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "disassembler_arm.h"
 #include "disassembler_arm64.h"
 #include "disassembler_mips.h"
+#include "disassembler_mips64.h"
 #include "disassembler_x86.h"
 
 namespace art {
@@ -34,6 +35,8 @@
     return new arm64::DisassemblerArm64(options);
   } else if (instruction_set == kMips) {
     return new mips::DisassemblerMips(options);
+  } else if (instruction_set == kMips64) {
+    return new mips64::DisassemblerMips64(options);
   } else if (instruction_set == kX86) {
     return new x86::DisassemblerX86(options, false);
   } else if (instruction_set == kX86_64) {
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 487f433..966ee3a 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -21,8 +21,8 @@
 
 #include <iosfwd>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
-#include "instruction_set.h"
 
 namespace art {
 
@@ -34,8 +34,14 @@
   // Base addess for calculating relative code offsets when absolute_addresses_ is false.
   const uint8_t* const base_address_;
 
-  DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address)
-      : absolute_addresses_(absolute_addresses), base_address_(base_address) {}
+  // If set, the disassembler is allowed to look at load targets in literal
+  // pools.
+  const bool can_read_literals_;
+
+  DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address,
+                      bool can_read_literals)
+      : absolute_addresses_(absolute_addresses), base_address_(base_address),
+        can_read_literals_(can_read_literals) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DisassemblerOptions);
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 6f8e08b..31e653b 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -18,8 +18,10 @@
 
 #include <inttypes.h>
 
-#include <iostream>
+#include <ostream>
+#include <sstream>
 
+#include "arch/arm/registers_arm.h"
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "thread.h"
@@ -124,8 +126,10 @@
 };
 
 struct ArmRegister {
-  explicit ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); }
-  ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) { CHECK_LE(r, 15U); }
+  explicit ArmRegister(uint32_t r_in) : r(r_in) { CHECK_LE(r_in, 15U); }
+  ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) {
+    CHECK_LE(r, 15U);
+  }
   uint32_t r;
 };
 std::ostream& operator<<(std::ostream& os, const ArmRegister& r) {
@@ -145,15 +149,15 @@
   ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {}
 };
 
-struct Rm {
-  explicit Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {}
-  uint32_t shift;
+struct RmLslImm2 {
+  explicit RmLslImm2(uint32_t instr) : imm2((instr >> 4) & 0x3), rm(instr & 0xf) {}
+  uint32_t imm2;
   ArmRegister rm;
 };
-std::ostream& operator<<(std::ostream& os, const Rm& r) {
+std::ostream& operator<<(std::ostream& os, const RmLslImm2& r) {
   os << r.rm;
-  if (r.shift != 0) {
-    os << "-shift-" << r.shift;  // TODO
+  if (r.imm2 != 0) {
+    os << ", lsl #" << r.imm2;
   }
   return os;
 }
@@ -389,50 +393,78 @@
   return (bit_a << 31) | ((1 << 30) - (bit_b << 25)) | (slice << 19);
 }
 
-uint64_t VFPExpand64(uint32_t imm8) {
+static uint64_t VFPExpand64(uint32_t imm8) {
   CHECK_EQ(imm8 & 0xffu, imm8);
   uint64_t bit_a = (imm8 >> 7) & 1;
   uint64_t bit_b = (imm8 >> 6) & 1;
   uint64_t slice = imm8 & 0x3f;
-  return (bit_a << 31) | ((UINT64_C(1) << 62) - (bit_b << 54)) | (slice << 48);
+  return (bit_a << 63) | ((UINT64_C(1) << 62) - (bit_b << 54)) | (slice << 48);
 }
 
-uint64_t AdvSIMDExpand(uint32_t op, uint32_t cmode, uint32_t imm8) {
-  CHECK_EQ(op & 1, op);
-  CHECK_EQ(cmode & 0xf, cmode);
-  CHECK_EQ(imm8 & 0xff, imm8);
-  int32_t cmode321 = cmode >> 1;
-  if (imm8 == 0 && cmode321 != 0 && cmode321 != 4 && cmode321 != 7) {
-    return INT64_C(0x00000000deadbeef);  // UNPREDICTABLE
-  }
-  uint64_t imm = imm8;
-  switch (cmode321) {
-    case 3: imm <<= 8;  // Fall through.
-    case 2: imm <<= 8;  // Fall through.
-    case 1: imm <<= 8;  // Fall through.
-    case 0: return static_cast<int64_t>((imm << 32) | imm);
-    case 5: imm <<= 8;  // Fall through.
-    case 4: return static_cast<int64_t>((imm << 48) | (imm << 32) | (imm << 16) | imm);
-    case 6:
-      imm = ((imm + 1u) << ((cmode & 1) != 0 ? 16 : 8)) - 1u;  // Add 8 or 16 ones.
-      return static_cast<int64_t>((imm << 32) | imm);
+enum T2LitType {
+  kT2LitInvalid,
+  kT2LitUByte,
+  kT2LitSByte,
+  kT2LitUHalf,
+  kT2LitSHalf,
+  kT2LitUWord,
+  kT2LitSWord,
+  kT2LitHexWord,
+  kT2LitULong,
+  kT2LitSLong,
+  kT2LitHexLong,
+};
+std::ostream& operator<<(std::ostream& os, T2LitType type) {
+  return os << static_cast<int>(type);
+}
+
+void DumpThumb2Literal(std::ostream& args, const uint8_t* instr_ptr, uint32_t U, uint32_t imm32,
+                       T2LitType type) {
+  // Literal offsets (imm32) are not required to be aligned so we may need unaligned access.
+  typedef const int16_t unaligned_int16_t __attribute__ ((aligned (1)));
+  typedef const uint16_t unaligned_uint16_t __attribute__ ((aligned (1)));
+  typedef const int32_t unaligned_int32_t __attribute__ ((aligned (1)));
+  typedef const uint32_t unaligned_uint32_t __attribute__ ((aligned (1)));
+  typedef const int64_t unaligned_int64_t __attribute__ ((aligned (1)));
+  typedef const uint64_t unaligned_uint64_t __attribute__ ((aligned (1)));
+
+  uintptr_t pc = RoundDown(reinterpret_cast<intptr_t>(instr_ptr) + 4, 4);
+  uintptr_t lit_adr = U ? pc + imm32 : pc - imm32;
+  args << "  ; ";
+  switch (type) {
+    case kT2LitUByte:
+      args << *reinterpret_cast<const uint8_t*>(lit_adr);
+      break;
+    case kT2LitSByte:
+      args << *reinterpret_cast<const int8_t*>(lit_adr);
+      break;
+    case kT2LitUHalf:
+      args << *reinterpret_cast<const unaligned_uint16_t*>(lit_adr);
+      break;
+    case kT2LitSHalf:
+      args << *reinterpret_cast<const unaligned_int16_t*>(lit_adr);
+      break;
+    case kT2LitUWord:
+      args << *reinterpret_cast<const unaligned_uint32_t*>(lit_adr);
+      break;
+    case kT2LitSWord:
+      args << *reinterpret_cast<const unaligned_int32_t*>(lit_adr);
+      break;
+    case kT2LitHexWord:
+      args << StringPrintf("0x%08x", *reinterpret_cast<const unaligned_uint32_t*>(lit_adr));
+      break;
+    case kT2LitULong:
+      args << *reinterpret_cast<const unaligned_uint64_t*>(lit_adr);
+      break;
+    case kT2LitSLong:
+      args << *reinterpret_cast<const unaligned_int64_t*>(lit_adr);
+      break;
+    case kT2LitHexLong:
+      args << StringPrintf("0x%" PRIx64, *reinterpret_cast<unaligned_int64_t*>(lit_adr));
+      break;
     default:
-      CHECK_EQ(cmode321, 7);
-      if ((cmode & 1) == 0 && op == 0) {
-        imm = (imm << 8) | imm;
-        return static_cast<int64_t>((imm << 48) | (imm << 32) | (imm << 16) | imm);
-      } else if ((cmode & 1) == 0 && op != 0) {
-        for (int i = 1; i != 8; ++i) {
-          imm |= ((imm >> i) & UINT64_C(1)) << (i * 8);
-        }
-        imm = imm & ~UINT64_C(0xfe);
-        return static_cast<int64_t>((imm << 8) - imm);
-      } else if ((cmode & 1) != 0 && op == 0) {
-        imm = static_cast<uint32_t>(VFPExpand32(imm8));
-        return static_cast<int64_t>((imm << 32) | imm);
-      } else {
-        return INT64_C(0xdeadbeef00000000);  // UNDEFINED
-      }
+      LOG(FATAL) << "Invalid type: " << type;
+      break;
   }
 }
 
@@ -792,10 +824,7 @@
                 args << d << ", [" << Rn << ", #" << ((U == 1) ? "" : "-")
                      << (imm8 << 2) << "]";
                 if (Rn.r == 15 && U == 1) {
-                  intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
-                  lit_adr = RoundDown(lit_adr, 4) + 4 + (imm8 << 2);
-                  typedef const int64_t unaligned_int64_t __attribute__ ((aligned (2)));
-                  args << StringPrintf("  ; 0x%" PRIx64, *reinterpret_cast<unaligned_int64_t*>(lit_adr));
+                  DumpThumb2Literal(args, instr_ptr, U, imm8 << 2, kT2LitHexLong);
                 }
               } else if (Rn.r == 13 && W == 1 && U == L) {  // VPUSH/VPOP
                 opcode << (L == 1 ? "vpop" : "vpush");
@@ -1196,7 +1225,7 @@
               }
               break;
             }
-            // Else deliberate fall-through to B.
+            FALLTHROUGH_INTENDED;  // Else deliberate fall-through to B.
           case 1: case 3: {
             // B
             // |111|11|1|0000|000000|11|1 |1|1 |10000000000|
@@ -1263,166 +1292,141 @@
       break;
     case 3:
       switch (op2) {
-        case 0x00: case 0x02: case 0x04: case 0x06:  // 000xxx0
-        case 0x08: case 0x09: case 0x0A: case 0x0C: case 0x0E: {
-          // Store single data item
-          // |111|11|100|000|0|0000|1111|110000|000000|
-          // |5 3|21|098|765|4|3  0|5  2|10   6|5    0|
-          // |---|--|---|---|-|----|----|------|------|
-          // |332|22|222|222|2|1111|1111|110000|000000|
-          // |1 9|87|654|321|0|9  6|5  2|10   6|5    0|
-          // |---|--|---|---|-|----|----|------|------|
-          // |111|11|000|op3|0|    |    |  op4 |      |
-          uint32_t op3 = (instr >> 21) & 7;
-          // uint32_t op4 = (instr >> 6) & 0x3F;
-          switch (op3) {
-            case 0x0: case 0x4: {
-              // {ST,LD}RB Rt,[Rn,#+/-imm12]    - 111 11 00 0 1 00 0 nnnn tttt 1 PUWii ii iiii
-              // {ST,LD}RB Rt,[Rn,#+/-imm8]     - 111 11 00 0 0 00 0 nnnn tttt 1 PUWii ii iiii
-              // {ST,LD}RB Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 00 0 nnnn tttt 0 00000 ii mmmm
-              ArmRegister Rn(instr, 16);
-              ArmRegister Rt(instr, 12);
-              opcode << (HasBitSet(instr, 20) ? "ldrb" : "strb");
-              if (HasBitSet(instr, 23)) {
-                uint32_t imm12 = instr & 0xFFF;
-                args << Rt << ", [" << Rn << ",#" << imm12 << "]";
-              } else if ((instr & 0x800) != 0) {
-                uint32_t imm8 = instr & 0xFF;
-                args << Rt << ", [" << Rn << ",#" << imm8 << "]";
-              } else {
-                uint32_t imm2 = (instr >> 4) & 3;
-                ArmRegister Rm(instr, 0);
-                args << Rt << ", [" << Rn << ", " << Rm;
-                if (imm2 != 0) {
-                  args << ", " << "lsl #" << imm2;
-                }
-                args << "]";
-              }
-              break;
-            }
-            case 0x1: case 0x5: {
-              // STRH Rt,[Rn,#+/-imm12]    - 111 11 00 0 1 01 0 nnnn tttt 1 PUWii ii iiii
-              // STRH Rt,[Rn,#+/-imm8]     - 111 11 00 0 0 01 0 nnnn tttt 1 PUWii ii iiii
-              // STRH Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 01 0 nnnn tttt 0 00000 ii mmmm
-              ArmRegister Rn(instr, 16);
-              ArmRegister Rt(instr, 12);
-              opcode << "strh";
-              if (HasBitSet(instr, 23)) {
-                uint32_t imm12 = instr & 0xFFF;
-                args << Rt << ", [" << Rn << ",#" << imm12 << "]";
-              } else if ((instr & 0x800) != 0) {
-                uint32_t imm8 = instr & 0xFF;
-                args << Rt << ", [" << Rn << ",#" << imm8 << "]";
-              } else {
-                uint32_t imm2 = (instr >> 4) & 3;
-                ArmRegister Rm(instr, 0);
-                args << Rt << ", [" << Rn << ", " << Rm;
-                if (imm2 != 0) {
-                  args << ", " << "lsl #" << imm2;
-                }
-                args << "]";
-              }
-              break;
-            }
-            case 0x2: case 0x6: {
-              ArmRegister Rn(instr, 16);
-              ArmRegister Rt(instr, 12);
-              if (op3 == 2) {
-                if ((instr & 0x800) != 0) {
-                  // STR Rt, [Rn, #imm8] - 111 11 000 010 0 nnnn tttt 1PUWiiiiiiii
-                  uint32_t P = (instr >> 10) & 1;
-                  uint32_t U = (instr >> 9) & 1;
-                  uint32_t W = (instr >> 8) & 1;
-                  uint32_t imm8 = instr & 0xFF;
-                  int32_t imm32 = (imm8 << 24) >> 24;  // sign-extend imm8
-                  if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) {
-                    opcode << "push";
-                    args << "{" << Rt << "}";
-                  } else if (Rn.r == 15 || (P == 0 && W == 0)) {
-                    opcode << "UNDEFINED";
-                  } else {
-                    if (P == 1 && U == 1 && W == 0) {
-                      opcode << "strt";
-                    } else {
-                      opcode << "str";
-                    }
-                    args << Rt << ", [" << Rn;
-                    if (P == 0 && W == 1) {
-                      args << "], #" << imm32;
-                    } else {
-                      args << ", #" << imm32 << "]";
-                      if (W == 1) {
-                        args << "!";
-                      }
-                    }
-                  }
-                } else {
-                  // STR Rt, [Rn, Rm, LSL #imm2] - 111 11 000 010 0 nnnn tttt 000000iimmmm
-                  ArmRegister Rn(instr, 16);
-                  ArmRegister Rt(instr, 12);
-                  ArmRegister Rm(instr, 0);
-                  uint32_t imm2 = (instr >> 4) & 3;
-                  opcode << "str.w";
-                  args << Rt << ", [" << Rn << ", " << Rm;
-                  if (imm2 != 0) {
-                    args << ", lsl #" << imm2;
-                  }
-                  args << "]";
-                }
-              } else if (op3 == 6) {
-                // STR.W Rt, [Rn, #imm12] - 111 11 000 110 0 nnnn tttt iiiiiiiiiiii
-                uint32_t imm12 = instr & 0xFFF;
-                opcode << "str.w";
-                args << Rt << ", [" << Rn << ", #" << imm12 << "]";
-              }
-              break;
-            }
-          }
-
+        case 0x07: case 0x0F: case 0x17: case 0x1F: {  // Explicitly UNDEFINED, A6.3.
+          opcode << "UNDEFINED";
           break;
         }
-        case 0x03: case 0x0B: case 0x11: case 0x13: case 0x19: case 0x1B: {  // 00xx011
-          // Load byte/halfword
-          // |111|11|10|0 0|00|0|0000|1111|110000|000000|
-          // |5 3|21|09|8 7|65|4|3  0|5  2|10   6|5    0|
-          // |---|--|--|---|--|-|----|----|------|------|
-          // |332|22|22|2 2|22|2|1111|1111|110000|000000|
-          // |1 9|87|65|4 3|21|0|9  6|5  2|10   6|5    0|
-          // |---|--|--|---|--|-|----|----|------|------|
-          // |111|11|00|op3|01|1| Rn | Rt | op4  |      |
-          // |111|11| op2       |    |    | imm12       |
-          uint32_t op3 = (instr >> 23) & 3;
+        case 0x06: case 0x0E: {  // "Store single data item" undefined opcodes, A6.3.10.
+          opcode << "UNDEFINED [store]";
+          break;
+        }
+        case 0x15: case 0x1D: {  // "Load word" undefined opcodes, A6.3.7.
+          opcode << "UNDEFINED [load]";
+          break;
+        }
+        case 0x10: case 0x12: case 0x14: case 0x16: case 0x18: case 0x1A: case 0x1C: case 0x1E: {
+          opcode << "UNKNOWN " << op2 << " [SIMD]";
+          break;
+        }
+        case 0x01: case 0x00: case 0x09: case 0x08:   // {LD,ST}RB{,T}
+        case 0x03: case 0x02: case 0x0B: case 0x0A:   // {LD,ST}RH{,T}
+        case 0x05: case 0x04: case 0x0D: case 0x0C:   // {LD,ST}R{,T}
+        case 0x11:            case 0x19:              // LDRSB{,T} (no signed store)
+        case 0x13:            case 0x1B: {            // LDRSH{,T} (no signed store)
+          // Load:
+          // (Store is the same except that l==0 and always s==0 below.)
+          //                       00s.whl (sign, word, half, load)
+          // LDR{S}B  imm12: 11111|00s1001| Rn | Rt |imm12             (0x09)
+          // LDR{S}B   imm8: 11111|00s0001| Rn | Rt |1PUW|imm8         (0x01)
+          // LDR{S}BT  imm8: 11111|00s0001| Rn | Rt |1110|imm8         (0x01)
+          // LDR{S}B    lit: 11111|00sU001|1111| Rt |imm12             (0x01/0x09)
+          // LDR{S}B    reg: 11111|00s0001| Rn | Rt |000000|imm2| Rm   (0x01)
+          // LDR{S}H  imm12: 11111|00s1011| Rn | Rt |imm12             (0x0B)
+          // LDR{S}H   imm8: 11111|00s0011| Rn | Rt |1PUW|imm8         (0x03)
+          // LDR{S}HT  imm8: 11111|00s0011| Rn | Rt |1110|imm8         (0x03)
+          // LDR{S}H    lit: 11111|00sU011|1111| Rt |imm12             (0x03/0x0B)
+          // LDR{S}H    reg: 11111|00s0011| Rn | Rt |000000|imm2| Rm   (0x03)
+          // LDR      imm12: 11111|0001101| Rn | Rt |imm12             (0x0D)
+          // LDR       imm8: 11111|0000101| Rn | Rt |1PUW|imm8         (0x05)
+          // LDRT      imm8: 11111|0000101| Rn | Rt |1110|imm8         (0x05)
+          // LDR        lit: 11111|000U101|1111| Rt |imm12             (0x05/0x0D)
+          // LDR        reg: 11111|0000101| Rn | Rt |000000|imm2| Rm   (0x05)
+          //
+          // If Rt == 15, instead of load we have preload:
+          // PLD{W}   imm12: 11111|00010W1| Rn |1111|imm12             (0x09/0x0B)
+          // PLD{W}    imm8: 11111|00000W1| Rn |1111|1100|imm8         (0x01/0x03); -imm8
+          // PLD        lit: 11111|000U001|1111|1111|imm12             (0x01/0x09)
+          // PLD{W}     reg: 11111|00000W1| Rn |1111|000000|imm2| Rm   (0x01/0x03)
+          // PLI      imm12: 11111|0011001| Rn |1111|imm12             (0x19)
+          // PLI       imm8: 11111|0010001| Rn |1111|1100|imm8         (0x11); -imm8
+          // PLI        lit: 11111|001U001|1111|1111|imm12             (0x01/0x09)
+          // PLI        reg: 11111|0010001| Rn |1111|000000|imm2| Rm   (0x01/0x03)
+
+          bool is_load = HasBitSet(instr, 20);
+          bool is_half = HasBitSet(instr, 21);  // W for PLD/PLDW.
+          bool is_word = HasBitSet(instr, 22);
+          bool is_signed = HasBitSet(instr, 24);
           ArmRegister Rn(instr, 16);
           ArmRegister Rt(instr, 12);
-          if (Rt.r != 15) {
-            if (op3 == 1) {
-              // LDRH.W Rt, [Rn, #imm12]       - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii
-              uint32_t imm12 = instr & 0xFFF;
-              opcode << "ldrh.w";
-              args << Rt << ", [" << Rn << ", #" << imm12 << "]";
-              if (Rn.r == 9) {
-                args << "  ; ";
-                Thread::DumpThreadOffset<4>(args, imm12);
-              } else if (Rn.r == 15) {
-                intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
-                lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
-                args << StringPrintf("  ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr));
+          uint32_t imm12 = instr & 0xFFF;
+          uint32_t U = (instr >> 23) & 1;  // U for imm12
+          uint32_t imm8 = instr & 0xFF;
+          uint32_t op4 = (instr >> 8) & 0xF;  // 1PUW for imm8
+          if (Rt.r == PC && is_load && !is_word) {
+            // PLD, PLDW, PLI
+            const char* pld_pli = (is_signed ? "pli" : "pld");
+            const char* w = (is_half ? "w" : "");
+            if (is_signed && !is_half) {
+              opcode << "UNDEFINED [PLI+W]";
+            } else if (Rn.r == PC || U != 0u) {
+              opcode << pld_pli << w;
+              args << "[" << Rn << ", #" << (U != 0u ? "" : "-") << imm12 << "]";
+              if (Rn.r == PC && is_half) {
+                args << " (UNPREDICTABLE)";
               }
-            } else if (op3 == 3) {
-              // LDRSH.W Rt, [Rn, #imm12]      - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii
-              // LDRSB.W Rt, [Rn, #imm12]      - 111 11 00 11 001 nnnn tttt iiiiiiiiiiii
-              uint32_t imm12 = instr & 0xFFF;
-              opcode << (HasBitSet(instr, 20) ? "ldrsb.w" : "ldrsh.w");
-              args << Rt << ", [" << Rn << ", #" << imm12 << "]";
-              if (Rn.r == 9) {
-                args << "  ; ";
-                Thread::DumpThreadOffset<4>(args, imm12);
-              } else if (Rn.r == 15) {
-                intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
-                lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
-                args << StringPrintf("  ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr));
-              }
+            } else if ((instr & 0xFC0) == 0) {
+              opcode << pld_pli << w;
+              RmLslImm2 Rm(instr);
+              args << "[" << Rn << ", " << Rm << "]";
+            } else if (op4 == 0xC) {
+              opcode << pld_pli << w;
+              args << "[" << Rn << ", #-" << imm8 << "]";
+            } else {
+              opcode << "UNDEFINED [~" << pld_pli << "]";
             }
+            break;
+          }
+          const char* ldr_str = is_load ? "ldr" : "str";
+          const char* sign = is_signed ? "s" : "";
+          const char* type = is_word ? "" : is_half ? "h" : "b";
+          bool unpred = (Rt.r == SP && !is_word) || (Rt.r == PC && !is_load);
+          if (Rn.r == PC && !is_load) {
+            opcode << "UNDEFINED [STR-lit]";
+            unpred = false;
+          } else if (Rn.r == PC || U != 0u) {
+            // Load/store with imm12 (load literal if Rn.r == PC; there's no store literal).
+            opcode << ldr_str << sign << type << ".w";
+            args << Rt << ", [" << Rn << ", #" << (U != 0u ? "" : "-") << imm12 << "]";
+            if (Rn.r == TR && is_load) {
+              args << "  ; ";
+              Thread::DumpThreadOffset<4>(args, imm12);
+            } else if (Rn.r == PC) {
+              T2LitType lit_type[] = {
+                  kT2LitUByte, kT2LitUHalf, kT2LitHexWord, kT2LitInvalid,
+                  kT2LitUByte, kT2LitUHalf, kT2LitHexWord, kT2LitInvalid,
+                  kT2LitSByte, kT2LitSHalf, kT2LitInvalid, kT2LitInvalid,
+                  kT2LitSByte, kT2LitSHalf, kT2LitInvalid, kT2LitInvalid,
+              };
+              DCHECK_LT(op2 >> 1, arraysize(lit_type));
+              DCHECK_NE(lit_type[op2 >> 1], kT2LitInvalid);
+              DumpThumb2Literal(args, instr_ptr, U, imm12, lit_type[op2 >> 1]);
+            }
+          } else if ((instr & 0xFC0) == 0) {
+            opcode << ldr_str << sign << type << ".w";
+            RmLslImm2 Rm(instr);
+            args << Rt << ", [" << Rn << ", " << Rm << "]";
+            unpred = unpred || (Rm.rm.r == SP) || (Rm.rm.r == PC);
+          } else if (is_word && Rn.r == SP && imm8 == 4 && op4 == (is_load ? 0xB : 0xD)) {
+            opcode << (is_load ? "pop" : "push") << ".w";
+            args << Rn;
+            unpred = unpred || (Rn.r == SP);
+          } else if ((op4 & 5) == 0) {
+            opcode << "UNDEFINED [P = W = 0 for " << ldr_str << "]";
+            unpred = false;
+          } else {
+            uint32_t P = (instr >> 10) & 1;
+            U = (instr >> 9) & 1;
+            uint32_t W = (instr >> 8) & 1;
+            bool pre_index = (P != 0 && W == 1);
+            bool post_index = (P == 0 && W == 1);
+            const char* t = (P != 0 && U != 0 && W == 0) ? "t" : "";  // Unprivileged load/store?
+            opcode << ldr_str << sign << type << t << ".w";
+            args << Rt << ", [" << Rn << (post_index ? "]" : "") << ", #" << (U != 0 ? "" : "-")
+                << imm8 << (post_index ? "" : "]") << (pre_index ? "!" : "");
+            unpred = (W != 0 && Rn.r == Rt.r);
+          }
+          if (unpred) {
+            args << " (UNPREDICTABLE)";
           }
           break;
         }
@@ -1451,75 +1455,6 @@
           }  // else unknown instruction
           break;
         }
-        case 0x05: case 0x0D: case 0x15: case 0x1D: {  // 00xx101
-          // Load word
-          // |111|11|10|0 0|00|0|0000|1111|110000|000000|
-          // |5 3|21|09|8 7|65|4|3  0|5  2|10   6|5    0|
-          // |---|--|--|---|--|-|----|----|------|------|
-          // |332|22|22|2 2|22|2|1111|1111|110000|000000|
-          // |1 9|87|65|4 3|21|0|9  6|5  2|10   6|5    0|
-          // |---|--|--|---|--|-|----|----|------|------|
-          // |111|11|00|op3|10|1| Rn | Rt | op4  |      |
-          // |111|11| op2       |    |    | imm12       |
-          uint32_t op3 = (instr >> 23) & 3;
-          uint32_t op4 = (instr >> 6) & 0x3F;
-          ArmRegister Rn(instr, 16);
-          ArmRegister Rt(instr, 12);
-          if (op3 == 1 || Rn.r == 15) {
-            // LDR.W Rt, [Rn, #imm12]          - 111 11 00 00 101 nnnn tttt iiiiiiiiiiii
-            // LDR.W Rt, [PC, #imm12]          - 111 11 00 0x 101 1111 tttt iiiiiiiiiiii
-            uint32_t imm12 = instr & 0xFFF;
-            opcode << "ldr.w";
-            args << Rt << ", [" << Rn << ", #" << imm12 << "]";
-            if (Rn.r == 9) {
-              args << "  ; ";
-              Thread::DumpThreadOffset<4>(args, imm12);
-            } else if (Rn.r == 15) {
-              intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr);
-              lit_adr = RoundDown(lit_adr, 4) + 4 + imm12;
-              args << StringPrintf("  ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr));
-            }
-          } else if (op4 == 0) {
-            // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm
-            uint32_t imm2 = (instr >> 4) & 0xF;
-            ArmRegister rm(instr, 0);
-            opcode << "ldr.w";
-            args << Rt << ", [" << Rn << ", " << rm;
-            if (imm2 != 0) {
-              args << ", lsl #" << imm2;
-            }
-            args << "]";
-          } else {
-            bool p = (instr & (1 << 10)) != 0;
-            bool w = (instr & (1 << 8)) != 0;
-            bool u = (instr & (1 << 9)) != 0;
-            if (p && u && !w) {
-              // LDRT Rt, [Rn, #imm8]            - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
-              uint32_t imm8 = instr & 0xFF;
-              opcode << "ldrt";
-              args << Rt << ", [" << Rn << ", #" << imm8 << "]";
-            } else if (Rn.r == 13 && !p && u && w && (instr & 0xff) == 4) {
-              // POP
-              opcode << "pop";
-              args << "{" << Rt << "}";
-           } else {
-              bool wback = !p || w;
-              uint32_t offset = (instr & 0xff);
-              opcode << "ldr.w";
-              args << Rt << ",";
-              if (p && !wback) {
-                args << "[" << Rn << ", #" << offset << "]";
-              } else if (p && wback) {
-                args << "[" << Rn << ", #" << offset << "]!";
-              } else if (!p && wback) {
-                args << "[" << Rn << "], #" << offset;
-              } else {
-                LOG(FATAL) << p << " " << w;
-              }
-            }
-          }
-          break;
-        }
       default:      // more formats
         if ((op2 >> 4) == 2) {      // 010xxxx
           // data processing (register)
@@ -1536,7 +1471,7 @@
         } else if ((op2 >> 3) == 6) {       // 0110xxx
           // Multiply, multiply accumulate, and absolute difference
           op1 = (instr >> 20) & 0x7;
-          op2 = (instr >> 4) & 0x2;
+          op2 = (instr >> 4) & 0x1;
           ArmRegister Ra(instr, 12);
           ArmRegister Rn(instr, 16);
           ArmRegister Rm(instr, 0);
@@ -1597,6 +1532,7 @@
           }
         }
       }
+      break;
     default:
       break;
   }
@@ -1845,6 +1781,23 @@
           DumpBranchTarget(args, instr_ptr + 4, imm32);
           break;
         }
+        case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
+        case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: {
+          opcode << "push";
+          args << RegisterList((instr & 0xFF) | ((instr & 0x100) << 6));
+          break;
+        }
+        case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
+        case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: {
+          opcode << "pop";
+          args << RegisterList((instr & 0xFF) | ((instr & 0x100) << 7));
+          break;
+        }
+        case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: {
+          opcode << "bkpt";
+          args << "#" << (instr & 0xFF);
+          break;
+        }
         case 0x50: case 0x51:    // 101000x
         case 0x52: case 0x53:    // 101001x
         case 0x56: case 0x57: {  // 101011x
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 5d0c218..bd3bebf 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,89 @@
 namespace art {
 namespace arm64 {
 
-static uint32_t ReadU32(const uint8_t* ptr) {
-  return *((const uint32_t*)ptr);
+void CustomDisassembler::AppendRegisterNameToOutput(
+    const vixl::Instruction* instr,
+    const vixl::CPURegister& reg) {
+  USE(instr);
+  if (reg.IsRegister()) {
+    // This enumeration should mirror the declarations in
+    // runtime/arch/arm64/registers_arm64.h. We do not include that file to
+    // avoid a dependency on libart.
+    enum {
+      TR  = 18,
+      ETR = 21,
+      IP0 = 16,
+      IP1 = 17,
+      FP  = 29,
+      LR  = 30
+    };
+    switch (reg.code()) {
+      case IP0: AppendToOutput(reg.Is64Bits() ? "ip0" : "wip0"); return;
+      case IP1: AppendToOutput(reg.Is64Bits() ? "ip1" : "wip1"); return;
+      case TR:  AppendToOutput(reg.Is64Bits() ? "tr"  :  "w18"); return;
+      case ETR: AppendToOutput(reg.Is64Bits() ? "etr" :  "w21"); return;
+      case FP:  AppendToOutput(reg.Is64Bits() ? "fp"  :  "w29"); return;
+      case LR:  AppendToOutput(reg.Is64Bits() ? "lr"  :  "w30"); return;
+      default:
+        // Fall through.
+        break;
+    }
+  }
+  // Print other register names as usual.
+  Disassembler::AppendRegisterNameToOutput(instr, reg);
+}
+
+void CustomDisassembler::VisitLoadLiteral(const vixl::Instruction* instr) {
+  Disassembler::VisitLoadLiteral(instr);
+
+  if (!read_literals_) {
+    return;
+  }
+
+  char* buffer = buffer_;
+  char* buffer_end = buffer_ + buffer_size_;
+
+  // Find the end position in the buffer.
+  while ((*buffer != 0) && (buffer < buffer_end)) {
+    ++buffer;
+  }
+
+  void* data_address = instr->LiteralAddress<void*>();
+  ptrdiff_t buf_size_remaining = buffer_end - buffer;
+  vixl::Instr op = instr->Mask(vixl::LoadLiteralMask);
+
+  switch (op) {
+    case vixl::LDR_w_lit:
+    case vixl::LDR_x_lit:
+    case vixl::LDRSW_x_lit: {
+      int64_t data = op == vixl::LDR_x_lit ? *reinterpret_cast<int64_t*>(data_address)
+                                           : *reinterpret_cast<int32_t*>(data_address);
+      snprintf(buffer, buf_size_remaining, " (0x%" PRIx64 " / %" PRId64 ")", data, data);
+      break;
+    }
+    case vixl::LDR_s_lit:
+    case vixl::LDR_d_lit: {
+      double data = (op == vixl::LDR_s_lit) ? *reinterpret_cast<float*>(data_address)
+                                            : *reinterpret_cast<double*>(data_address);
+      snprintf(buffer, buf_size_remaining, " (%g)", data);
+      break;
+    }
+    default:
+      break;
+  }
 }
 
 size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
-  uint32_t instruction = ReadU32(begin);
-  decoder.Decode(reinterpret_cast<vixl::Instruction*>(&instruction));
-  os << FormatInstructionPointer(begin)
-     << StringPrintf(": %08x\t%s\n", instruction, disasm.GetOutput());
+  const vixl::Instruction* instr = reinterpret_cast<const vixl::Instruction*>(begin);
+  decoder.Decode(instr);
+  // TODO: Use FormatInstructionPointer() once VIXL provides the appropriate
+  // features.
+  // VIXL does not yet allow remapping addresses disassembled. Using
+  // FormatInstructionPointer() would show incoherences between the instruction
+  // location addresses and the target addresses disassembled by VIXL (eg. for
+  // branch instructions).
+  os << StringPrintf("%p", instr)
+     << StringPrintf(": %08x\t%s\n", instr->InstructionBits(), disasm.GetOutput());
   return vixl::kInstructionSize;
 }
 
diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h
index ad20c70..a370b8d 100644
--- a/disassembler/disassembler_arm64.h
+++ b/disassembler/disassembler_arm64.h
@@ -19,15 +19,44 @@
 
 #include "disassembler.h"
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
 #include "a64/decoder-a64.h"
 #include "a64/disasm-a64.h"
+#pragma GCC diagnostic pop
 
 namespace art {
 namespace arm64 {
 
+class CustomDisassembler FINAL : public vixl::Disassembler {
+ public:
+  explicit CustomDisassembler(bool read_literals) :
+      vixl::Disassembler(), read_literals_(read_literals) {}
+
+  // Use register aliases in the disassembly.
+  virtual void AppendRegisterNameToOutput(const vixl::Instruction* instr,
+                                          const vixl::CPURegister& reg) OVERRIDE;
+
+  // Improve the disassembly of literal load instructions.
+  virtual void VisitLoadLiteral(const vixl::Instruction* instr) OVERRIDE;
+
+ private:
+  // Indicate if the disassembler should read data loaded from literal pools.
+  // This should only be enabled if reading the target of literal loads is safe.
+  // Here are possible outputs when the option is on or off:
+  // read_literals_ | disassembly
+  //           true | 0x72681558: 1c000acb  ldr s11, pc+344 (addr 0x726816b0)
+  //          false | 0x72681558: 1c000acb  ldr s11, pc+344 (addr 0x726816b0) (3.40282e+38)
+  const bool read_literals_;
+};
+
 class DisassemblerArm64 FINAL : public Disassembler {
  public:
-  explicit DisassemblerArm64(DisassemblerOptions* options) : Disassembler(options) {
+  // TODO: Update this code once VIXL provides the ability to map code addresses
+  // to disassemble as a different address (the way FormatInstructionPointer()
+  // does).
+  explicit DisassemblerArm64(DisassemblerOptions* options) :
+      Disassembler(options), disasm(options->can_read_literals_) {
     decoder.AppendVisitor(&disasm);
   }
 
@@ -36,7 +65,7 @@
 
  private:
   vixl::Decoder decoder;
-  vixl::Disassembler disasm;
+  CustomDisassembler disasm;
 
   DISALLOW_COPY_AND_ASSIGN(DisassemblerArm64);
 };
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index bd5fac7..7442c70 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"
@@ -137,7 +138,9 @@
   { kITypeMask, 41u << kOpcodeShift, "sh", "TO", },
   { kITypeMask, 43u << kOpcodeShift, "sw", "TO", },
   { kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", },
+  { kITypeMask, 53u << kOpcodeShift, "ldc1", "tO", },
   { kITypeMask, 57u << kOpcodeShift, "swc1", "tO", },
+  { kITypeMask, 61u << kOpcodeShift, "sdc1", "tO", },
 
   // Floating point.
   { kFpMask,                kCop1 | 0, "add", "fdst" },
diff --git a/disassembler/disassembler_mips64.cc b/disassembler/disassembler_mips64.cc
new file mode 100644
index 0000000..2d3239f
--- /dev/null
+++ b/disassembler/disassembler_mips64.cc
@@ -0,0 +1,289 @@
+/*
+ * 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 "disassembler_mips64.h"
+
+#include <ostream>
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "thread.h"
+
+namespace art {
+namespace mips64 {
+
+
+struct Mips64Instruction {
+  uint32_t    mask;
+  uint32_t    value;
+  const char* name;
+  const char* args_fmt;
+
+  bool Matches(uint32_t instruction) const {
+    return (instruction & mask) == value;
+  }
+};
+
+static const uint32_t kOpcodeShift = 26;
+static const uint32_t kCop1 = (17 << kOpcodeShift);
+static const uint32_t kITypeMask = (0x3f << kOpcodeShift);
+static const uint32_t kJTypeMask = (0x3f << kOpcodeShift);
+static const uint32_t kRTypeMask = ((0x3f << kOpcodeShift) | (0x3f));
+static const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift);
+static const uint32_t kFpMask = kRTypeMask;
+
+static const Mips64Instruction gMips64Instructions[] = {
+  // "sll r0, r0, 0" is the canonical "nop", used in delay slots.
+  { 0xffffffff, 0, "nop", "" },
+
+  // R-type instructions.
+  { kRTypeMask, 0, "sll", "DTA", },
+  // 0, 1, movci
+  { kRTypeMask, 2, "srl", "DTA", },
+  { kRTypeMask, 3, "sra", "DTA", },
+  { kRTypeMask, 4, "sllv", "DTS", },
+  { kRTypeMask, 6, "srlv", "DTS", },
+  { kRTypeMask, 7, "srav", "DTS", },
+  { kRTypeMask, 8, "jr", "S", },
+  // rd = 31 is implicit.
+  { kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", },
+  { kRTypeMask, 9, "jalr", "DS", },  // General case.
+  { kRTypeMask | (0x1f << 6), 10, "movz", "DST", },
+  { kRTypeMask | (0x1f << 6), 11, "movn", "DST", },
+  { kRTypeMask, 12, "syscall", "", },  // TODO: code
+  { kRTypeMask, 13, "break", "", },  // TODO: code
+  { kRTypeMask, 15, "sync", "", },  // TODO: type
+  { kRTypeMask, 16, "mfhi", "D", },
+  { kRTypeMask, 17, "mthi", "S", },
+  { kRTypeMask, 18, "mflo", "D", },
+  { kRTypeMask, 19, "mtlo", "S", },
+  { kRTypeMask, 24, "mult", "ST", },
+  { kRTypeMask, 25, "multu", "ST", },
+  { kRTypeMask, 26, "div", "ST", },
+  { kRTypeMask, 27, "divu", "ST", },
+  { kRTypeMask, 32, "add", "DST", },
+  { kRTypeMask, 33, "addu", "DST", },
+  { kRTypeMask, 34, "sub", "DST", },
+  { kRTypeMask, 35, "subu", "DST", },
+  { kRTypeMask, 36, "and", "DST", },
+  { kRTypeMask, 37, "or", "DST", },
+  { kRTypeMask, 38, "xor", "DST", },
+  { kRTypeMask, 39, "nor", "DST", },
+  { kRTypeMask, 42, "slt", "DST", },
+  { kRTypeMask, 43, "sltu", "DST", },
+  { kRTypeMask, 44, "dadd", "DST", },
+  { kRTypeMask, 45, "daddu", "DST", },
+  { kRTypeMask, 46, "dsub", "DST", },
+  { kRTypeMask, 47, "dsubu", "DST", },
+  // 0, 48, tge
+  // 0, 49, tgeu
+  // 0, 50, tlt
+  // 0, 51, tltu
+  // 0, 52, teq
+  // 0, 54, tne
+
+  // SPECIAL2
+  { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" },
+  { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" },
+  { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 36, "dclz", "DS" },
+  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" },
+  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" },
+  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" },
+  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 4, "msub", "ST" },
+  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 5, "msubu", "ST" },
+  { kSpecial2Mask | 0x3f, (28 << kOpcodeShift) | 0x3f, "sdbbp", "" },
+
+  // J-type instructions.
+  { kJTypeMask, 2 << kOpcodeShift, "j", "L" },
+  { kJTypeMask, 3 << kOpcodeShift, "jal", "L" },
+
+  // I-type instructions.
+  { kITypeMask, 4 << kOpcodeShift, "beq", "STB" },
+  { kITypeMask, 5 << kOpcodeShift, "bne", "STB" },
+  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (1 << 16), "bgez", "SB" },
+  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (0 << 16), "bltz", "SB" },
+  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (2 << 16), "bltzl", "SB" },
+  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (16 << 16), "bltzal", "SB" },
+  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (18 << 16), "bltzall", "SB" },
+  { kITypeMask | (0x1f << 16), 6 << kOpcodeShift | (0 << 16), "blez", "SB" },
+  { kITypeMask | (0x1f << 16), 7 << kOpcodeShift | (0 << 16), "bgtz", "SB" },
+
+  { 0xffff0000, (4 << kOpcodeShift), "b", "B" },
+  { 0xffff0000, (1 << kOpcodeShift) | (17 << 16), "bal", "B" },
+
+  { kITypeMask, 8 << kOpcodeShift, "addi", "TSi", },
+  { kITypeMask, 9 << kOpcodeShift, "addiu", "TSi", },
+  { kITypeMask, 10 << kOpcodeShift, "slti", "TSi", },
+  { kITypeMask, 11 << kOpcodeShift, "sltiu", "TSi", },
+  { kITypeMask, 12 << kOpcodeShift, "andi", "TSi", },
+  { kITypeMask, 13 << kOpcodeShift, "ori", "TSi", },
+  { kITypeMask, 14 << kOpcodeShift, "ori", "TSi", },
+  { kITypeMask, 15 << kOpcodeShift, "lui", "TI", },
+
+  { kITypeMask, 24 << kOpcodeShift, "daddi", "TSi", },
+  { kITypeMask, 25 << kOpcodeShift, "daddiu", "TSi", },
+
+
+  { kITypeMask, 32u << kOpcodeShift, "lb", "TO", },
+  { kITypeMask, 33u << kOpcodeShift, "lh", "TO", },
+  { kITypeMask, 35u << kOpcodeShift, "lw", "TO", },
+  { kITypeMask, 36u << kOpcodeShift, "lbu", "TO", },
+  { kITypeMask, 37u << kOpcodeShift, "lhu", "TO", },
+  { kITypeMask, 40u << kOpcodeShift, "sb", "TO", },
+  { kITypeMask, 41u << kOpcodeShift, "sh", "TO", },
+  { kITypeMask, 43u << kOpcodeShift, "sw", "TO", },
+  { kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", },
+  { kITypeMask, 53u << kOpcodeShift, "ldc1", "tO", },
+  { kITypeMask, 55u << kOpcodeShift, "ld", "TO", },
+  { kITypeMask, 57u << kOpcodeShift, "swc1", "tO", },
+  { kITypeMask, 61u << kOpcodeShift, "sdc1", "tO", },
+  { kITypeMask, 63u << kOpcodeShift, "sd", "TO", },
+
+  // Floating point.
+  { kFpMask,                kCop1 | 0, "add", "fdst" },
+  { kFpMask,                kCop1 | 1, "sub", "fdst" },
+  { kFpMask,                kCop1 | 2, "mul", "fdst" },
+  { kFpMask,                kCop1 | 3, "div", "fdst" },
+  { kFpMask | (0x1f << 16), kCop1 | 4, "sqrt", "fdst" },
+  { kFpMask | (0x1f << 16), kCop1 | 5, "abs", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 6, "mov", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 7, "neg", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 8, "round.l", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 9, "trunc.l", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 10, "ceil.l", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 11, "floor.l", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 12, "round.w", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 13, "trunc.w", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 14, "ceil.w", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 15, "floor.w", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 32, "cvt.s", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 33, "cvt.d", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 36, "cvt.w", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 37, "cvt.l", "fds" },
+  { kFpMask | (0x1f << 16), kCop1 | 38, "cvt.ps", "fds" },
+};
+
+static uint32_t ReadU32(const uint8_t* ptr) {
+  // We only support little-endian MIPS64.
+  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+}
+
+static void DumpMips64(std::ostream& os, const uint8_t* instr_ptr) {
+  uint32_t instruction = ReadU32(instr_ptr);
+
+  uint32_t rs = (instruction >> 21) & 0x1f;  // I-type, R-type.
+  uint32_t rt = (instruction >> 16) & 0x1f;  // I-type, R-type.
+  uint32_t rd = (instruction >> 11) & 0x1f;  // R-type.
+  uint32_t sa = (instruction >>  6) & 0x1f;  // R-type.
+
+  std::string opcode;
+  std::ostringstream args;
+
+  // TODO: remove this!
+  uint32_t op = (instruction >> 26) & 0x3f;
+  uint32_t function = (instruction & 0x3f);  // R-type.
+  opcode = StringPrintf("op=%d fn=%d", op, function);
+
+  for (size_t i = 0; i < arraysize(gMips64Instructions); ++i) {
+    if (gMips64Instructions[i].Matches(instruction)) {
+      opcode = gMips64Instructions[i].name;
+      for (const char* args_fmt = gMips64Instructions[i].args_fmt; *args_fmt; ++args_fmt) {
+        switch (*args_fmt) {
+          case 'A':  // sa (shift amount).
+            args << sa;
+            break;
+          case 'B':  // Branch offset.
+            {
+              int32_t offset = static_cast<int16_t>(instruction & 0xffff);
+              offset <<= 2;
+              offset += 4;  // Delay slot.
+              args << StringPrintf("%p  ; %+d", instr_ptr + offset, offset);
+            }
+            break;
+          case 'D': args << 'r' << rd; break;
+          case 'd': args << 'f' << rd; break;
+          case 'f':  // Floating point "fmt".
+            {
+              size_t fmt = (instruction >> 21) & 0x7;  // TODO: other fmts?
+              switch (fmt) {
+                case 0: opcode += ".s"; break;
+                case 1: opcode += ".d"; break;
+                case 4: opcode += ".w"; break;
+                case 5: opcode += ".l"; break;
+                case 6: opcode += ".ps"; break;
+                default: opcode += ".?"; break;
+              }
+              continue;  // No ", ".
+            }
+            break;
+          case 'I':  // Upper 16-bit immediate.
+            args << reinterpret_cast<void*>((instruction & 0xffff) << 16);
+            break;
+          case 'i':  // Sign-extended lower 16-bit immediate.
+            args << static_cast<int16_t>(instruction & 0xffff);
+            break;
+          case 'L':  // Jump label.
+            {
+              // TODO: is this right?
+              uint32_t instr_index = (instruction & 0x1ffffff);
+              uint32_t target = (instr_index << 2);
+              target |= (reinterpret_cast<uintptr_t>(instr_ptr + 4)
+                        & 0xf0000000);
+              args << reinterpret_cast<void*>(target);
+            }
+            break;
+          case 'O':  // +x(rs)
+            {
+              int32_t offset = static_cast<int16_t>(instruction & 0xffff);
+              args << StringPrintf("%+d(r%d)", offset, rs);
+              if (rs == 17) {
+                args << "  ; ";
+                Thread::DumpThreadOffset<8>(args, offset);
+              }
+            }
+            break;
+          case 'S': args << 'r' << rs; break;
+          case 's': args << 'f' << rs; break;
+          case 'T': args << 'r' << rt; break;
+          case 't': args << 'f' << rt; break;
+        }
+        if (*(args_fmt + 1)) {
+          args << ", ";
+        }
+      }
+      break;
+    }
+  }
+
+  os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str())
+     << args.str() << '\n';
+}
+
+size_t DisassemblerMips64::Dump(std::ostream& os, const uint8_t* begin) {
+  DumpMips64(os, begin);
+  return 4;
+}
+
+void DisassemblerMips64::Dump(std::ostream& os, const uint8_t* begin,
+                            const uint8_t* end) {
+  for (const uint8_t* cur = begin; cur < end; cur += 4) {
+    DumpMips64(os, cur);
+  }
+}
+
+}  // namespace mips64
+}  // namespace art
diff --git a/disassembler/disassembler_mips64.h b/disassembler/disassembler_mips64.h
new file mode 100644
index 0000000..06efdc8
--- /dev/null
+++ b/disassembler/disassembler_mips64.h
@@ -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.
+ */
+
+#ifndef ART_DISASSEMBLER_DISASSEMBLER_MIPS64_H_
+#define ART_DISASSEMBLER_DISASSEMBLER_MIPS64_H_
+
+#include <vector>
+
+#include "disassembler.h"
+
+namespace art {
+namespace mips64 {
+
+class DisassemblerMips64 FINAL : public Disassembler {
+ public:
+  explicit DisassemblerMips64(DisassemblerOptions* options) : Disassembler(options) {}
+
+  size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE;
+  void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisassemblerMips64);
+};
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_DISASSEMBLER_DISASSEMBLER_MIPS64_H_
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 195c45f..1a768c8 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 {
@@ -78,8 +80,6 @@
   }
 }
 
-enum RegFile { GPR, MMX, SSE };
-
 static void DumpAnyReg(std::ostream& os, uint8_t rex, size_t reg,
                        bool byte_operand, uint8_t size_override, RegFile reg_file) {
   if (reg_file == GPR) {
@@ -153,11 +153,94 @@
   }
 }
 
+// Do not inline to avoid Clang stack frame problems. b/18733806
+NO_INLINE
+static std::string DumpCodeHex(const uint8_t* begin, const uint8_t* end) {
+  std::stringstream hex;
+  for (size_t i = 0; begin + i < end; ++i) {
+    hex << StringPrintf("%02X", begin[i]);
+  }
+  return hex.str();
+}
+
+std::string DisassemblerX86::DumpAddress(uint8_t mod, uint8_t rm, uint8_t rex64, uint8_t rex_w,
+                                         bool no_ops, bool byte_operand, bool byte_second_operand,
+                                         uint8_t* prefix, bool load, RegFile src_reg_file,
+                                         RegFile dst_reg_file, const uint8_t** instr,
+                                         uint32_t* address_bits) {
+  std::ostringstream address;
+  if (mod == 0 && rm == 5) {
+    if (!supports_rex_) {  // Absolute address.
+      *address_bits = *reinterpret_cast<const uint32_t*>(*instr);
+      address << StringPrintf("[0x%x]", *address_bits);
+    } else {  // 64-bit RIP relative addressing.
+      address << StringPrintf("[RIP + 0x%x]",  *reinterpret_cast<const uint32_t*>(*instr));
+    }
+    (*instr) += 4;
+  } else if (rm == 4 && mod != 3) {  // SIB
+    uint8_t sib = **instr;
+    (*instr)++;
+    uint8_t scale = (sib >> 6) & 3;
+    uint8_t index = (sib >> 3) & 7;
+    uint8_t base = sib & 7;
+    address << "[";
+    if (base != 5 || mod != 0) {
+      DumpBaseReg(address, rex64, base);
+      if (index != 4) {
+        address << " + ";
+      }
+    }
+    if (index != 4) {
+      DumpIndexReg(address, rex64, index);
+      if (scale != 0) {
+        address << StringPrintf(" * %d", 1 << scale);
+      }
+    }
+    if (mod == 0) {
+      if (base == 5) {
+        if (index != 4) {
+          address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
+        } else {
+          // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit.
+          *address_bits = *reinterpret_cast<const uint32_t*>(*instr);
+          address << StringPrintf("%d", *address_bits);
+        }
+        (*instr) += 4;
+      }
+    } else if (mod == 1) {
+      address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr));
+      (*instr)++;
+    } else if (mod == 2) {
+      address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
+      (*instr) += 4;
+    }
+    address << "]";
+  } else {
+    if (mod == 3) {
+      if (!no_ops) {
+        DumpRmReg(address, rex_w, rm, byte_operand || byte_second_operand,
+                  prefix[2], load ? src_reg_file : dst_reg_file);
+      }
+    } else {
+      address << "[";
+      DumpBaseReg(address, rex64, rm);
+      if (mod == 1) {
+        address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr));
+        (*instr)++;
+      } else if (mod == 2) {
+        address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
+        (*instr) += 4;
+      }
+      address << "]";
+    }
+  }
+  return address.str();
+}
+
 size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) {
   const uint8_t* begin_instr = instr;
   bool have_prefixes = true;
   uint8_t prefix[4] = {0, 0, 0, 0};
-  const char** modrm_opcodes = NULL;
   do {
     switch (*instr) {
         // Group 1 - lock and repeat prefixes:
@@ -195,15 +278,23 @@
   if (rex != 0) {
     instr++;
   }
+  const char** modrm_opcodes = nullptr;
   bool has_modrm = false;
   bool reg_is_opcode = false;
   size_t immediate_bytes = 0;
   size_t branch_bytes = 0;
-  std::ostringstream opcode;
+  std::string opcode_tmp;    // Storage to keep StringPrintf result alive.
+  const char* opcode0 = "";  // Prefix part.
+  const char* opcode1 = "";  // Main opcode.
+  const char* opcode2 = "";  // Sub-opcode. E.g., jump type.
+  const char* opcode3 = "";  // Mod-rm part.
+  const char* opcode4 = "";  // Suffix part.
   bool store = false;  // stores to memory (ie rm is on the left)
   bool load = false;  // loads from memory (ie rm is on the right)
   bool byte_operand = false;  // true when the opcode is dealing with byte operands
-  bool byte_second_operand = false;  // true when the source operand is a byte register but the target register isn't (ie movsxb/movzxb).
+  // true when the source operand is a byte register but the target register isn't
+  // (ie movsxb/movzxb).
+  bool byte_second_operand = false;
   bool target_specific = false;  // register name depends on target (64 vs 32 bits).
   bool ax = false;  // implicit use of ax
   bool cx = false;  // implicit use of cx
@@ -216,12 +307,12 @@
                      rm8_r8, rm32_r32, \
                      r8_rm8, r32_rm32, \
                      ax8_i8, ax32_i32) \
-  case rm8_r8:   opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \
-  case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \
-  case r8_rm8:   opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \
-  case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \
-  case ax8_i8:   opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \
-  case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break;
+  case rm8_r8:   opcode1 = #opname; store = true; has_modrm = true; byte_operand = true; break; \
+  case rm32_r32: opcode1 = #opname; store = true; has_modrm = true; break; \
+  case r8_rm8:   opcode1 = #opname; load = true; has_modrm = true; byte_operand = true; break; \
+  case r32_rm32: opcode1 = #opname; load = true; has_modrm = true; break; \
+  case ax8_i8:   opcode1 = #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \
+  case ax32_i32: opcode1 = #opname; ax = true; immediate_bytes = 4; break;
 
 DISASSEMBLER_ENTRY(add,
   0x00 /* RegMem8/Reg8 */,     0x01 /* RegMem32/Reg32 */,
@@ -258,65 +349,67 @@
 
 #undef DISASSEMBLER_ENTRY
   case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
-    opcode << "push";
+    opcode1 = "push";
     reg_in_opcode = true;
     target_specific = true;
     break;
   case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F:
-    opcode << "pop";
+    opcode1 = "pop";
     reg_in_opcode = true;
     target_specific = true;
     break;
   case 0x63:
     if ((rex & REX_W) != 0) {
-      opcode << "movsxd";
+      opcode1 = "movsxd";
       has_modrm = true;
       load = true;
     } else {
       // In 32-bit mode (!supports_rex_) this is ARPL, with no REX prefix the functionality is the
       // same as 'mov' but the use of the instruction is discouraged.
-      opcode << StringPrintf("unknown opcode '%02X'", *instr);
+      opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
+      opcode1 = opcode_tmp.c_str();
     }
     break;
-  case 0x68: opcode << "push"; immediate_bytes = 4; break;
-  case 0x69: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 4; break;
-  case 0x6A: opcode << "push"; immediate_bytes = 1; break;
-  case 0x6B: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 1; break;
+  case 0x68: opcode1 = "push"; immediate_bytes = 4; break;
+  case 0x69: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 4; break;
+  case 0x6A: opcode1 = "push"; immediate_bytes = 1; break;
+  case 0x6B: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 1; break;
   case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
   case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
     static const char* condition_codes[] =
     {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq",  "nz/ne", "be/na", "nbe/a",
      "s", "ns", "p/pe",    "np/po",    "l/nge", "nl/ge", "le/ng", "nle/g"
     };
-    opcode << "j" << condition_codes[*instr & 0xF];
+    opcode1 = "j";
+    opcode2 = condition_codes[*instr & 0xF];
     branch_bytes = 1;
     break;
   case 0x86: case 0x87:
-    opcode << "xchg";
+    opcode1 = "xchg";
     store = true;
     has_modrm = true;
     byte_operand = (*instr == 0x86);
     break;
-  case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break;
-  case 0x89: opcode << "mov"; store = true; has_modrm = true; break;
-  case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break;
-  case 0x8B: opcode << "mov"; load = true; has_modrm = true; break;
+  case 0x88: opcode1 = "mov"; store = true; has_modrm = true; byte_operand = true; break;
+  case 0x89: opcode1 = "mov"; store = true; has_modrm = true; break;
+  case 0x8A: opcode1 = "mov"; load = true; has_modrm = true; byte_operand = true; break;
+  case 0x8B: opcode1 = "mov"; load = true; has_modrm = true; break;
 
   case 0x0F:  // 2 byte extended opcode
     instr++;
     switch (*instr) {
       case 0x10: case 0x11:
         if (prefix[0] == 0xF2) {
-          opcode << "movsd";
+          opcode1 = "movsd";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
-          opcode << "movss";
+          opcode1 = "movss";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[2] == 0x66) {
-          opcode << "movupd";
+          opcode1 = "movupd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "movups";
+          opcode1 = "movups";
         }
         has_modrm = true;
         src_reg_file = dst_reg_file = SSE;
@@ -325,10 +418,10 @@
         break;
       case 0x12: case 0x13:
         if (prefix[2] == 0x66) {
-          opcode << "movlpd";
+          opcode1 = "movlpd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0) {
-          opcode << "movlps";
+          opcode1 = "movlps";
         }
         has_modrm = true;
         src_reg_file = dst_reg_file = SSE;
@@ -337,10 +430,10 @@
         break;
       case 0x16: case 0x17:
         if (prefix[2] == 0x66) {
-          opcode << "movhpd";
+          opcode1 = "movhpd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0) {
-          opcode << "movhps";
+          opcode1 = "movhps";
         }
         has_modrm = true;
         src_reg_file = dst_reg_file = SSE;
@@ -349,10 +442,10 @@
         break;
       case 0x28: case 0x29:
         if (prefix[2] == 0x66) {
-          opcode << "movapd";
+          opcode1 = "movapd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0) {
-          opcode << "movaps";
+          opcode1 = "movaps";
         }
         has_modrm = true;
         src_reg_file = dst_reg_file = SSE;
@@ -361,16 +454,16 @@
         break;
       case 0x2A:
         if (prefix[2] == 0x66) {
-          opcode << "cvtpi2pd";
+          opcode1 = "cvtpi2pd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF2) {
-          opcode << "cvtsi2sd";
+          opcode1 = "cvtsi2sd";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
-          opcode << "cvtsi2ss";
+          opcode1 = "cvtsi2ss";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "cvtpi2ps";
+          opcode1 = "cvtpi2ps";
         }
         load = true;
         has_modrm = true;
@@ -378,16 +471,16 @@
         break;
       case 0x2C:
         if (prefix[2] == 0x66) {
-          opcode << "cvttpd2pi";
+          opcode1 = "cvttpd2pi";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF2) {
-          opcode << "cvttsd2si";
+          opcode1 = "cvttsd2si";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
-          opcode << "cvttss2si";
+          opcode1 = "cvttss2si";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "cvttps2pi";
+          opcode1 = "cvttps2pi";
         }
         load = true;
         has_modrm = true;
@@ -395,30 +488,30 @@
         break;
       case 0x2D:
         if (prefix[2] == 0x66) {
-          opcode << "cvtpd2pi";
+          opcode1 = "cvtpd2pi";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF2) {
-          opcode << "cvtsd2si";
+          opcode1 = "cvtsd2si";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
-          opcode << "cvtss2si";
+          opcode1 = "cvtss2si";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "cvtps2pi";
+          opcode1 = "cvtps2pi";
         }
         load = true;
         has_modrm = true;
         src_reg_file = SSE;
         break;
       case 0x2E:
-        opcode << "u";
-        // FALLTHROUGH
+        opcode0 = "u";
+        FALLTHROUGH_INTENDED;
       case 0x2F:
         if (prefix[2] == 0x66) {
-          opcode << "comisd";
+          opcode1 = "comisd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "comiss";
+          opcode1 = "comiss";
         }
         has_modrm = true;
         load = true;
@@ -429,31 +522,33 @@
         if (prefix[2] == 0x66) {
           switch (*instr) {
             case 0x01:
-              opcode << "phaddw";
+              opcode1 = "phaddw";
               prefix[2] = 0;
               has_modrm = true;
               load = true;
               src_reg_file = dst_reg_file = SSE;
               break;
             case 0x02:
-              opcode << "phaddd";
+              opcode1 = "phaddd";
               prefix[2] = 0;
               has_modrm = true;
               load = true;
               src_reg_file = dst_reg_file = SSE;
               break;
             case 0x40:
-              opcode << "pmulld";
+              opcode1 = "pmulld";
               prefix[2] = 0;
               has_modrm = true;
               load = true;
               src_reg_file = dst_reg_file = SSE;
               break;
             default:
-              opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr);
+              opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr);
+              opcode1 = opcode_tmp.c_str();
           }
         } else {
-          opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr);
+          opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr);
+          opcode1 = opcode_tmp.c_str();
         }
         break;
       case 0x3A:  // 3 byte extended opcode
@@ -461,7 +556,7 @@
         if (prefix[2] == 0x66) {
           switch (*instr) {
             case 0x14:
-              opcode << "pextrb";
+              opcode1 = "pextrb";
               prefix[2] = 0;
               has_modrm = true;
               store = true;
@@ -469,7 +564,7 @@
               immediate_bytes = 1;
               break;
             case 0x16:
-              opcode << "pextrd";
+              opcode1 = "pextrd";
               prefix[2] = 0;
               has_modrm = true;
               store = true;
@@ -477,48 +572,51 @@
               immediate_bytes = 1;
               break;
             default:
-              opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
+              opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr);
+              opcode1 = opcode_tmp.c_str();
           }
         } else {
-          opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
+          opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr);
+          opcode1 = opcode_tmp.c_str();
         }
         break;
       case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
       case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F:
-        opcode << "cmov" << condition_codes[*instr & 0xF];
+        opcode1 = "cmov";
+        opcode2 = condition_codes[*instr & 0xF];
         has_modrm = true;
         load = true;
         break;
       case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
       case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
         switch (*instr) {
-          case 0x50: opcode << "movmsk"; break;
-          case 0x51: opcode << "sqrt"; break;
-          case 0x52: opcode << "rsqrt"; break;
-          case 0x53: opcode << "rcp"; break;
-          case 0x54: opcode << "and"; break;
-          case 0x55: opcode << "andn"; break;
-          case 0x56: opcode << "or"; break;
-          case 0x57: opcode << "xor"; break;
-          case 0x58: opcode << "add"; break;
-          case 0x59: opcode << "mul"; break;
-          case 0x5C: opcode << "sub"; break;
-          case 0x5D: opcode << "min"; break;
-          case 0x5E: opcode << "div"; break;
-          case 0x5F: opcode << "max"; break;
-          default: LOG(FATAL) << "Unreachable";
+          case 0x50: opcode1 = "movmsk"; break;
+          case 0x51: opcode1 = "sqrt"; break;
+          case 0x52: opcode1 = "rsqrt"; break;
+          case 0x53: opcode1 = "rcp"; break;
+          case 0x54: opcode1 = "and"; break;
+          case 0x55: opcode1 = "andn"; break;
+          case 0x56: opcode1 = "or"; break;
+          case 0x57: opcode1 = "xor"; break;
+          case 0x58: opcode1 = "add"; break;
+          case 0x59: opcode1 = "mul"; break;
+          case 0x5C: opcode1 = "sub"; break;
+          case 0x5D: opcode1 = "min"; break;
+          case 0x5E: opcode1 = "div"; break;
+          case 0x5F: opcode1 = "max"; break;
+          default: LOG(FATAL) << "Unreachable"; UNREACHABLE();
         }
         if (prefix[2] == 0x66) {
-          opcode << "pd";
+          opcode2 = "pd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF2) {
-          opcode << "sd";
+          opcode2 = "sd";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
-          opcode << "ss";
+          opcode2 = "ss";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "ps";
+          opcode2 = "ps";
         }
         load = true;
         has_modrm = true;
@@ -527,16 +625,16 @@
       }
       case 0x5A:
         if (prefix[2] == 0x66) {
-          opcode << "cvtpd2ps";
+          opcode1 = "cvtpd2ps";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF2) {
-          opcode << "cvtsd2ss";
+          opcode1 = "cvtsd2ss";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
-          opcode << "cvtss2sd";
+          opcode1 = "cvtss2sd";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "cvtps2pd";
+          opcode1 = "cvtps2pd";
         }
         load = true;
         has_modrm = true;
@@ -544,15 +642,15 @@
         break;
       case 0x5B:
         if (prefix[2] == 0x66) {
-          opcode << "cvtps2dq";
+          opcode1 = "cvtps2dq";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF2) {
-          opcode << "bad opcode F2 0F 5B";
+          opcode1 = "bad opcode F2 0F 5B";
         } else if (prefix[0] == 0xF3) {
-          opcode << "cvttps2dq";
+          opcode1 = "cvttps2dq";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << "cvtdq2ps";
+          opcode1 = "cvtdq2ps";
         }
         load = true;
         has_modrm = true;
@@ -566,10 +664,10 @@
           src_reg_file = dst_reg_file = MMX;
         }
         switch (*instr) {
-          case 0x60: opcode << "punpcklbw"; break;
-          case 0x61: opcode << "punpcklwd"; break;
-          case 0x62: opcode << "punpckldq"; break;
-          case 0x6c: opcode << "punpcklqdq"; break;
+          case 0x60: opcode1 = "punpcklbw"; break;
+          case 0x61: opcode1 = "punpcklwd"; break;
+          case 0x62: opcode1 = "punpckldq"; break;
+          case 0x6c: opcode1 = "punpcklqdq"; break;
         }
         load = true;
         has_modrm = true;
@@ -581,43 +679,44 @@
         } else {
           dst_reg_file = MMX;
         }
-        opcode << "movd";
+        opcode1 = "movd";
         load = true;
         has_modrm = true;
         break;
       case 0x6F:
         if (prefix[2] == 0x66) {
           src_reg_file = dst_reg_file = SSE;
-          opcode << "movdqa";
+          opcode1 = "movdqa";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[0] == 0xF3) {
           src_reg_file = dst_reg_file = SSE;
-          opcode << "movdqu";
+          opcode1 = "movdqu";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
           dst_reg_file = MMX;
-          opcode << "movq";
+          opcode1 = "movq";
         }
         load = true;
         has_modrm = true;
         break;
       case 0x70:
         if (prefix[2] == 0x66) {
-          opcode << "pshufd";
+          opcode1 = "pshufd";
           prefix[2] = 0;
           has_modrm = true;
           store = true;
           src_reg_file = dst_reg_file = SSE;
           immediate_bytes = 1;
         } else if (prefix[0] == 0xF2) {
-          opcode << "pshuflw";
+          opcode1 = "pshuflw";
           prefix[0] = 0;
           has_modrm = true;
           store = true;
           src_reg_file = dst_reg_file = SSE;
           immediate_bytes = 1;
         } else {
-          opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode1 = opcode_tmp.c_str();
         }
         break;
       case 0x71:
@@ -627,7 +726,9 @@
         } else {
           dst_reg_file = MMX;
         }
-        static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"};
+        static const char* x71_opcodes[] = {
+            "unknown-71", "unknown-71", "psrlw", "unknown-71",
+            "psraw",      "unknown-71", "psllw", "unknown-71"};
         modrm_opcodes = x71_opcodes;
         reg_is_opcode = true;
         has_modrm = true;
@@ -641,7 +742,9 @@
         } else {
           dst_reg_file = MMX;
         }
-        static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"};
+        static const char* x72_opcodes[] = {
+            "unknown-72", "unknown-72", "psrld", "unknown-72",
+            "psrad",      "unknown-72", "pslld", "unknown-72"};
         modrm_opcodes = x72_opcodes;
         reg_is_opcode = true;
         has_modrm = true;
@@ -655,7 +758,9 @@
         } else {
           dst_reg_file = MMX;
         }
-        static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "psrldq", "unknown-73", "unknown-73", "psllq", "unknown-73"};
+        static const char* x73_opcodes[] = {
+            "unknown-73", "unknown-73", "psrlq", "psrldq",
+            "unknown-73", "unknown-73", "psllq", "unknown-73"};
         modrm_opcodes = x73_opcodes;
         reg_is_opcode = true;
         has_modrm = true;
@@ -664,13 +769,14 @@
         break;
       case 0x7C:
         if (prefix[0] == 0xF2) {
-          opcode << "haddps";
+          opcode1 = "haddps";
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else if (prefix[2] == 0x66) {
-          opcode << "haddpd";
+          opcode1 = "haddpd";
           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
         } else {
-          opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode1 = opcode_tmp.c_str();
           break;
         }
         src_reg_file = dst_reg_file = SSE;
@@ -684,43 +790,45 @@
         } else {
           src_reg_file = MMX;
         }
-        opcode << "movd";
+        opcode1 = "movd";
         has_modrm = true;
         store = true;
         break;
       case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
       case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
-        opcode << "j" << condition_codes[*instr & 0xF];
+        opcode1 = "j";
+        opcode2 = condition_codes[*instr & 0xF];
         branch_bytes = 4;
         break;
       case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
       case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
-        opcode << "set" << condition_codes[*instr & 0xF];
-        modrm_opcodes = NULL;
+        opcode1 = "set";
+        opcode2 = condition_codes[*instr & 0xF];
+        modrm_opcodes = nullptr;
         reg_is_opcode = true;
         has_modrm = true;
         store = true;
         break;
       case 0xA4:
-        opcode << "shld";
+        opcode1 = "shld";
         has_modrm = true;
         load = true;
         immediate_bytes = 1;
         break;
       case 0xA5:
-        opcode << "shld";
+        opcode1 = "shld";
         has_modrm = true;
         load = true;
         cx = true;
         break;
       case 0xAC:
-        opcode << "shrd";
+        opcode1 = "shrd";
         has_modrm = true;
         load = true;
         immediate_bytes = 1;
         break;
       case 0xAD:
-        opcode << "shrd";
+        opcode1 = "shrd";
         has_modrm = true;
         load = true;
         cx = true;
@@ -728,7 +836,9 @@
       case 0xAE:
         if (prefix[0] == 0xF3) {
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
-          static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"};
+          static const char* xAE_opcodes[] = {
+              "rdfsbase",   "rdgsbase",   "wrfsbase",   "wrgsbase",
+              "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"};
           modrm_opcodes = xAE_opcodes;
           reg_is_opcode = true;
           has_modrm = true;
@@ -755,7 +865,9 @@
               break;
           }
         } else {
-          static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"};
+          static const char* xAE_opcodes[] = {
+              "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE",
+              "unknown-AE", "lfence",     "mfence",     "sfence"};
           modrm_opcodes = xAE_opcodes;
           reg_is_opcode = true;
           has_modrm = true;
@@ -763,31 +875,63 @@
           no_ops = true;
         }
         break;
-      case 0xAF: opcode << "imul"; has_modrm = true; load = true; break;
-      case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break;
-      case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; byte_second_operand = true; break;
-      case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break;
-      case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; byte_second_operand = true; rex |= (rex == 0 ? 0 : REX_W); break;
-      case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break;
-      case 0xC3: opcode << "movnti"; store = true; has_modrm = true; break;
+      case 0xAF:
+        opcode1 = "imul";
+        has_modrm = true;
+        load = true;
+        break;
+      case 0xB1:
+        opcode1 = "cmpxchg";
+        has_modrm = true;
+        store = true;
+        break;
+      case 0xB6:
+        opcode1 = "movzxb";
+        has_modrm = true;
+        load = true;
+        byte_second_operand = true;
+        break;
+      case 0xB7:
+        opcode1 = "movzxw";
+        has_modrm = true;
+        load = true;
+        break;
+      case 0xBE:
+        opcode1 = "movsxb";
+        has_modrm = true;
+        load = true;
+        byte_second_operand = true;
+        rex |= (rex == 0 ? 0 : REX_W);
+        break;
+      case 0xBF:
+        opcode1 = "movsxw";
+        has_modrm = true;
+        load = true;
+        break;
+      case 0xC3:
+        opcode1 = "movnti";
+        store = true;
+        has_modrm = true;
+        break;
       case 0xC5:
         if (prefix[2] == 0x66) {
-          opcode << "pextrw";
+          opcode1 = "pextrw";
           prefix[2] = 0;
           has_modrm = true;
           store = true;
           src_reg_file = SSE;
           immediate_bytes = 1;
         } else {
-          opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode1 = opcode_tmp.c_str();
         }
         break;
       case 0xC6:
         if (prefix[2] == 0x66) {
-          opcode << "shufpd";
+          opcode1 = "shufpd";
           prefix[2] = 0;
         } else {
-          opcode << "shufps";
+          opcode1 = "shufps";
         }
         has_modrm = true;
         store = true;
@@ -795,14 +939,16 @@
         immediate_bytes = 1;
         break;
       case 0xC7:
-        static const char* x0FxC7_opcodes[] = { "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7" };
+        static const char* x0FxC7_opcodes[] = {
+            "unknown-0f-c7", "cmpxchg8b",     "unknown-0f-c7", "unknown-0f-c7",
+            "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7"};
         modrm_opcodes = x0FxC7_opcodes;
         has_modrm = true;
         reg_is_opcode = true;
         store = true;
         break;
       case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
-        opcode << "bswap";
+        opcode1 = "bswap";
         reg_in_opcode = true;
         break;
       case 0xD4:
@@ -812,7 +958,7 @@
         } else {
           src_reg_file = dst_reg_file = MMX;
         }
-        opcode << "paddq";
+        opcode1 = "paddq";
         prefix[2] = 0;
         has_modrm = true;
         load = true;
@@ -824,20 +970,21 @@
         } else {
           src_reg_file = dst_reg_file = MMX;
         }
-        opcode << "pand";
+        opcode1 = "pand";
         prefix[2] = 0;
         has_modrm = true;
         load = true;
         break;
       case 0xD5:
         if (prefix[2] == 0x66) {
-          opcode << "pmullw";
+          opcode1 = "pmullw";
           prefix[2] = 0;
           has_modrm = true;
           load = true;
           src_reg_file = dst_reg_file = SSE;
         } else {
-          opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
+          opcode1 = opcode_tmp.c_str();
         }
         break;
       case 0xEB:
@@ -847,7 +994,7 @@
         } else {
           src_reg_file = dst_reg_file = MMX;
         }
-        opcode << "por";
+        opcode1 = "por";
         prefix[2] = 0;
         has_modrm = true;
         load = true;
@@ -859,7 +1006,7 @@
         } else {
           src_reg_file = dst_reg_file = MMX;
         }
-        opcode << "pxor";
+        opcode1 = "pxor";
         prefix[2] = 0;
         has_modrm = true;
         load = true;
@@ -880,22 +1027,23 @@
           src_reg_file = dst_reg_file = MMX;
         }
         switch (*instr) {
-          case 0xF4: opcode << "pmuludq"; break;
-          case 0xF6: opcode << "psadbw"; break;
-          case 0xF8: opcode << "psubb"; break;
-          case 0xF9: opcode << "psubw"; break;
-          case 0xFA: opcode << "psubd"; break;
-          case 0xFB: opcode << "psubq"; break;
-          case 0xFC: opcode << "paddb"; break;
-          case 0xFD: opcode << "paddw"; break;
-          case 0xFE: opcode << "paddd"; break;
+          case 0xF4: opcode1 = "pmuludq"; break;
+          case 0xF6: opcode1 = "psadbw"; break;
+          case 0xF8: opcode1 = "psubb"; break;
+          case 0xF9: opcode1 = "psubw"; break;
+          case 0xFA: opcode1 = "psubd"; break;
+          case 0xFB: opcode1 = "psubq"; break;
+          case 0xFC: opcode1 = "paddb"; break;
+          case 0xFD: opcode1 = "paddw"; break;
+          case 0xFE: opcode1 = "paddd"; break;
         }
         prefix[2] = 0;
         has_modrm = true;
         load = true;
         break;
       default:
-        opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
+        opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
+        opcode1 = opcode_tmp.c_str();
         break;
     }
     break;
@@ -909,38 +1057,39 @@
     immediate_bytes = *instr == 0x81 ? 4 : 1;
     break;
   case 0x84: case 0x85:
-    opcode << "test";
+    opcode1 = "test";
     has_modrm = true;
     load = true;
     byte_operand = (*instr & 1) == 0;
     break;
   case 0x8D:
-    opcode << "lea";
+    opcode1 = "lea";
     has_modrm = true;
     load = true;
     break;
   case 0x8F:
-    opcode << "pop";
+    opcode1 = "pop";
     has_modrm = true;
     reg_is_opcode = true;
     store = true;
     break;
   case 0x99:
-    opcode << "cdq";
+    opcode1 = "cdq";
     break;
   case 0x9B:
     if (instr[1] == 0xDF && instr[2] == 0xE0) {
-      opcode << "fstsw\tax";
+      opcode1 = "fstsw\tax";
       instr += 2;
     } else {
-      opcode << StringPrintf("unknown opcode '%02X'", *instr);
+      opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
+      opcode1 = opcode_tmp.c_str();
     }
     break;
   case 0xAF:
-    opcode << (prefix[2] == 0x66 ? "scasw" : "scasl");
+    opcode1 = (prefix[2] == 0x66 ? "scasw" : "scasl");
     break;
   case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
-    opcode << "mov";
+    opcode1 = "mov";
     immediate_bytes = 1;
     byte_operand = true;
     reg_in_opcode = true;
@@ -948,12 +1097,12 @@
     break;
   case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
     if ((rex & REX_W) != 0) {
-      opcode << "movabsq";
+      opcode1 = "movabsq";
       immediate_bytes = 8;
       reg_in_opcode = true;
       break;
     }
-    opcode << "mov";
+    opcode1 = "mov";
     immediate_bytes = 4;
     reg_in_opcode = true;
     break;
@@ -969,9 +1118,11 @@
     cx = (*instr == 0xD2) || (*instr == 0xD3);
     byte_operand = (*instr == 0xC0);
     break;
-  case 0xC3: opcode << "ret"; break;
+  case 0xC3: opcode1 = "ret"; break;
   case 0xC6:
-    static const char* c6_opcodes[] = {"mov", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6"};
+    static const char* c6_opcodes[] = {"mov",        "unknown-c6", "unknown-c6",
+                                       "unknown-c6", "unknown-c6", "unknown-c6",
+                                       "unknown-c6", "unknown-c6"};
     modrm_opcodes = c6_opcodes;
     store = true;
     immediate_bytes = 1;
@@ -980,17 +1131,19 @@
     byte_operand = true;
     break;
   case 0xC7:
-    static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"};
+    static const char* c7_opcodes[] = {"mov",        "unknown-c7", "unknown-c7",
+                                       "unknown-c7", "unknown-c7", "unknown-c7",
+                                       "unknown-c7", "unknown-c7"};
     modrm_opcodes = c7_opcodes;
     store = true;
     immediate_bytes = 4;
     has_modrm = true;
     reg_is_opcode = true;
     break;
-  case 0xCC: opcode << "int 3"; break;
+  case 0xCC: opcode1 = "int 3"; break;
   case 0xD9:
     if (instr[1] == 0xF8) {
-      opcode << "fprem";
+      opcode1 = "fprem";
       instr++;
     } else {
       static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw",
@@ -1003,40 +1156,50 @@
     break;
   case 0xDA:
     if (instr[1] == 0xE9) {
-      opcode << "fucompp";
+      opcode1 = "fucompp";
       instr++;
     } else {
-      opcode << StringPrintf("unknown opcode '%02X'", *instr);
+      opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
+      opcode1 = opcode_tmp.c_str();
     }
     break;
   case 0xDB:
-    static const char* db_opcodes[] = {"fildl", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db"};
+    static const char* db_opcodes[] = {"fildl",      "unknown-db", "unknown-db",
+                                       "unknown-db", "unknown-db", "unknown-db",
+                                       "unknown-db", "unknown-db"};
     modrm_opcodes = db_opcodes;
     load = true;
     has_modrm = true;
     reg_is_opcode = true;
     break;
   case 0xDD:
-    static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl", "fstpl", "frstor", "unknown-dd", "fnsave", "fnstsw"};
+    static const char* dd_opcodes[] = {"fldl",   "fisttp", "fstl",
+                                       "fstpl",  "frstor", "unknown-dd",
+                                       "fnsave", "fnstsw"};
     modrm_opcodes = dd_opcodes;
     store = true;
     has_modrm = true;
     reg_is_opcode = true;
     break;
   case 0xDF:
-    static const char* df_opcodes[] = {"fild", "unknown-df", "unknown-df", "unknown-df", "unknown-df", "fildll", "unknown-df", "unknown-df"};
+    static const char* df_opcodes[] = {"fild",       "unknown-df", "unknown-df",
+                                       "unknown-df", "unknown-df", "fildll",
+                                       "unknown-df", "unknown-df"};
     modrm_opcodes = df_opcodes;
     load = true;
     has_modrm = true;
     reg_is_opcode = true;
     break;
-  case 0xE3: opcode << "jecxz"; branch_bytes = 1; break;
-  case 0xE8: opcode << "call"; branch_bytes = 4; break;
-  case 0xE9: opcode << "jmp"; branch_bytes = 4; break;
-  case 0xEB: opcode << "jmp"; branch_bytes = 1; break;
-  case 0xF5: opcode << "cmc"; break;
+  case 0xE3: opcode1 = "jecxz"; branch_bytes = 1; break;
+  case 0xE8: opcode1 = "call"; branch_bytes = 4; break;
+  case 0xE9: opcode1 = "jmp"; branch_bytes = 4; break;
+  case 0xEB: opcode1 = "jmp"; branch_bytes = 1; break;
+  case 0xF5: opcode1 = "cmc"; break;
   case 0xF6: case 0xF7:
-    static const char* f7_opcodes[] = {"test", "unknown-f7", "not", "neg", "mul edx:eax, eax *", "imul edx:eax, eax *", "div edx:eax, edx:eax /", "idiv edx:eax, edx:eax /"};
+    static const char* f7_opcodes[] = {
+        "test", "unknown-f7", "not", "neg", "mul edx:eax, eax *",
+        "imul edx:eax, eax *", "div edx:eax, edx:eax /",
+        "idiv edx:eax, edx:eax /"};
     modrm_opcodes = f7_opcodes;
     has_modrm = true;
     reg_is_opcode = true;
@@ -1045,7 +1208,9 @@
     break;
   case 0xFF:
     {
-      static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"};
+      static const char* ff_opcodes[] = {
+          "inc", "dec", "call", "call",
+          "jmp", "jmp", "push", "unknown-ff"};
       modrm_opcodes = ff_opcodes;
       has_modrm = true;
       reg_is_opcode = true;
@@ -1058,7 +1223,8 @@
     }
     break;
   default:
-    opcode << StringPrintf("unknown opcode '%02X'", *instr);
+    opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
+    opcode1 = opcode_tmp.c_str();
     break;
   }
   std::ostringstream args;
@@ -1079,84 +1245,21 @@
     uint8_t mod = modrm >> 6;
     uint8_t reg_or_opcode = (modrm >> 3) & 7;
     uint8_t rm = modrm & 7;
-    std::ostringstream address;
-    if (mod == 0 && rm == 5) {
-      if (!supports_rex_) {  // Absolute address.
-        address_bits = *reinterpret_cast<const uint32_t*>(instr);
-        address << StringPrintf("[0x%x]", address_bits);
-      } else {  // 64-bit RIP relative addressing.
-        address << StringPrintf("[RIP + 0x%x]",  *reinterpret_cast<const uint32_t*>(instr));
-      }
-      instr += 4;
-    } else if (rm == 4 && mod != 3) {  // SIB
-      uint8_t sib = *instr;
-      instr++;
-      uint8_t scale = (sib >> 6) & 3;
-      uint8_t index = (sib >> 3) & 7;
-      uint8_t base = sib & 7;
-      address << "[";
-      if (base != 5 || mod != 0) {
-        DumpBaseReg(address, rex64, base);
-        if (index != 4) {
-          address << " + ";
-        }
-      }
-      if (index != 4) {
-        DumpIndexReg(address, rex64, index);
-        if (scale != 0) {
-          address << StringPrintf(" * %d", 1 << scale);
-        }
-      }
-      if (mod == 0) {
-        if (base == 5) {
-          if (index != 4) {
-            address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
-          } else {
-            // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit.
-            address_bits = *reinterpret_cast<const uint32_t*>(instr);
-            address << StringPrintf("%d", address_bits);
-          }
-          instr += 4;
-        }
-      } else if (mod == 1) {
-        address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
-        instr++;
-      } else if (mod == 2) {
-        address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
-        instr += 4;
-      }
-      address << "]";
-    } else {
-      if (mod == 3) {
-        if (!no_ops) {
-          DumpRmReg(address, rex_w, rm, byte_operand || byte_second_operand,
-                    prefix[2], load ? src_reg_file : dst_reg_file);
-        }
-      } else {
-        address << "[";
-        DumpBaseReg(address, rex64, rm);
-        if (mod == 1) {
-          address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
-          instr++;
-        } else if (mod == 2) {
-          address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
-          instr += 4;
-        }
-        address << "]";
-      }
-    }
+    std::string address = DumpAddress(mod, rm, rex64, rex_w, no_ops, byte_operand,
+                                      byte_second_operand, prefix, load, src_reg_file, dst_reg_file,
+                                      &instr, &address_bits);
 
-    if (reg_is_opcode && modrm_opcodes != NULL) {
-      opcode << modrm_opcodes[reg_or_opcode];
+    if (reg_is_opcode && modrm_opcodes != nullptr) {
+      opcode3 = modrm_opcodes[reg_or_opcode];
     }
 
     // Add opcode suffixes to indicate size.
     if (byte_operand) {
-      opcode << 'b';
+      opcode4 = "b";
     } else if ((rex & REX_W) != 0) {
-      opcode << 'q';
+      opcode4 = "q";
     } else if (prefix[2] == 0x66) {
-      opcode << 'w';
+      opcode4 = "w";
     }
 
     if (load) {
@@ -1165,11 +1268,11 @@
         args << ", ";
       }
       DumpSegmentOverride(args, prefix[1]);
-      args << address.str();
+      args << address;
     } else {
       DCHECK(store);
       DumpSegmentOverride(args, prefix[1]);
-      args << address.str();
+      args << address;
       if (!reg_is_opcode) {
         args << ", ";
         DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
@@ -1227,21 +1330,17 @@
     args << "  ; ";
     Thread::DumpThreadOffset<8>(args, address_bits);
   }
-  std::stringstream hex;
-  for (size_t i = 0; begin_instr + i < instr; ++i) {
-    hex << StringPrintf("%02X", begin_instr[i]);
-  }
-  std::stringstream prefixed_opcode;
+  const char* prefix_str;
   switch (prefix[0]) {
-    case 0xF0: prefixed_opcode << "lock "; break;
-    case 0xF2: prefixed_opcode << "repne "; break;
-    case 0xF3: prefixed_opcode << "repe "; break;
-    case 0: break;
-    default: LOG(FATAL) << "Unreachable";
+    case 0xF0: prefix_str = "lock "; break;
+    case 0xF2: prefix_str = "repne "; break;
+    case 0xF3: prefix_str = "repe "; break;
+    case 0: prefix_str = ""; break;
+    default: LOG(FATAL) << "Unreachable"; UNREACHABLE();
   }
-  prefixed_opcode << opcode.str();
   os << FormatInstructionPointer(begin_instr)
-     << StringPrintf(": %22s    \t%-7s ", hex.str().c_str(), prefixed_opcode.str().c_str())
+     << StringPrintf(": %22s    \t%-7s%s%s%s%s%s ", DumpCodeHex(begin_instr, instr).c_str(),
+                     prefix_str, opcode0, opcode1, opcode2, opcode3, opcode4)
      << args.str() << '\n';
   return instr - begin_instr;
 }  // NOLINT(readability/fn_size)
diff --git a/disassembler/disassembler_x86.h b/disassembler/disassembler_x86.h
index f448662..71c3e41 100644
--- a/disassembler/disassembler_x86.h
+++ b/disassembler/disassembler_x86.h
@@ -22,6 +22,8 @@
 namespace art {
 namespace x86 {
 
+enum RegFile { GPR, MMX, SSE };
+
 class DisassemblerX86 FINAL : public Disassembler {
  public:
   DisassemblerX86(DisassemblerOptions* options, bool supports_rex)
@@ -33,6 +35,11 @@
  private:
   size_t DumpInstruction(std::ostream& os, const uint8_t* instr);
 
+  std::string DumpAddress(uint8_t mod, uint8_t rm, uint8_t rex64, uint8_t rex_w, bool no_ops,
+                          bool byte_operand, bool byte_second_operand, uint8_t* prefix, bool load,
+                          RegFile src_reg_file, RegFile dst_reg_file, const uint8_t** instr,
+                          uint32_t* address_bits);
+
   const bool supports_rex_;
 
   DISALLOW_COPY_AND_ASSIGN(DisassemblerX86);
diff --git a/imgdiag/Android.mk b/imgdiag/Android.mk
new file mode 100644
index 0000000..d5d7c22
--- /dev/null
+++ b/imgdiag/Android.mk
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include art/build/Android.executable.mk
+
+IMGDIAG_SRC_FILES := \
+	imgdiag.cc
+
+# Note that this tool needs to be built for both 32-bit and 64-bit since it requires
+# that the image it's analyzing be the same ISA as the runtime ISA.
+
+# Build variants {target,host} x {debug,ndebug} x {32,64}
+$(eval $(call build-art-multi-executable,imgdiag,$(IMGDIAG_SRC_FILES),libart-compiler libbacktrace,libcutils,libziparchive-host,art/compiler,both))
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
new file mode 100644
index 0000000..9b57ecb
--- /dev/null
+++ b/imgdiag/imgdiag.cc
@@ -0,0 +1,951 @@
+/*
+ * 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>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+
+#include "base/unix_file/fd_file.h"
+#include "base/stringprintf.h"
+#include "gc/space/image_space.h"
+#include "gc/heap.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/art_method-inl.h"
+#include "image.h"
+#include "scoped_thread_state_change.h"
+#include "os.h"
+#include "gc_map.h"
+
+#include "cmdline.h"
+#include "backtrace/BacktraceMap.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+
+namespace art {
+
+class ImgDiagDumper {
+ public:
+  explicit ImgDiagDumper(std::ostream* os,
+                       const ImageHeader& image_header,
+                       const char* image_location,
+                       pid_t image_diff_pid)
+      : os_(os),
+        image_header_(image_header),
+        image_location_(image_location),
+        image_diff_pid_(image_diff_pid) {}
+
+  bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    std::ostream& os = *os_;
+    os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
+
+    os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
+
+    bool ret = true;
+    if (image_diff_pid_ >= 0) {
+      os << "IMAGE DIFF PID (" << image_diff_pid_ << "): ";
+      ret = DumpImageDiff(image_diff_pid_);
+      os << "\n\n";
+    } else {
+      os << "IMAGE DIFF PID: disabled\n\n";
+    }
+
+    os << std::flush;
+
+    return ret;
+  }
+
+ private:
+  static bool EndsWith(const std::string& str, const std::string& suffix) {
+    return str.size() >= suffix.size() &&
+           str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+  }
+
+  // Return suffix of the file path after the last /. (e.g. /foo/bar -> bar, bar -> bar)
+  static std::string BaseName(const std::string& str) {
+    size_t idx = str.rfind("/");
+    if (idx == std::string::npos) {
+      return str;
+    }
+
+    return str.substr(idx + 1);
+  }
+
+  bool DumpImageDiff(pid_t image_diff_pid) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    std::ostream& os = *os_;
+
+    {
+      struct stat sts;
+      std::string proc_pid_str = StringPrintf("/proc/%ld", static_cast<long>(image_diff_pid));  // NOLINT [runtime/int]
+      if (stat(proc_pid_str.c_str(), &sts) == -1) {
+        os << "Process does not exist";
+        return false;
+      }
+    }
+
+    // Open /proc/$pid/maps to view memory maps
+    auto proc_maps = std::unique_ptr<BacktraceMap>(BacktraceMap::Create(image_diff_pid));
+    if (proc_maps == nullptr) {
+      os << "Could not read backtrace maps";
+      return false;
+    }
+
+    bool found_boot_map = false;
+    backtrace_map_t boot_map = backtrace_map_t();
+    // Find the memory map only for boot.art
+    for (const backtrace_map_t& map : *proc_maps) {
+      if (EndsWith(map.name, GetImageLocationBaseName())) {
+        if ((map.flags & PROT_WRITE) != 0) {
+          boot_map = map;
+          found_boot_map = true;
+          break;
+        }
+        // In actuality there's more than 1 map, but the second one is read-only.
+        // The one we care about is the write-able map.
+        // The readonly maps are guaranteed to be identical, so its not interesting to compare
+        // them.
+      }
+    }
+
+    if (!found_boot_map) {
+      os << "Could not find map for " << GetImageLocationBaseName();
+      return false;
+    }
+
+    // Future idea: diff against zygote so we can ignore the shared dirty pages.
+    return DumpImageDiffMap(image_diff_pid, boot_map);
+  }
+
+    // Look at /proc/$pid/mem and only diff the things from there
+  bool DumpImageDiffMap(pid_t image_diff_pid, const backtrace_map_t& boot_map)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    std::ostream& os = *os_;
+    const size_t pointer_size = InstructionSetPointerSize(
+        Runtime::Current()->GetInstructionSet());
+
+    std::string file_name = StringPrintf("/proc/%ld/mem", static_cast<long>(image_diff_pid));  // NOLINT [runtime/int]
+
+    size_t boot_map_size = boot_map.end - boot_map.start;
+
+    // Open /proc/$pid/mem as a file
+    auto map_file = std::unique_ptr<File>(OS::OpenFileForReading(file_name.c_str()));
+    if (map_file == nullptr) {
+      os << "Failed to open " << file_name << " for reading";
+      return false;
+    }
+
+    // Memory-map /proc/$pid/mem subset from the boot map
+    CHECK(boot_map.end >= boot_map.start);
+
+    std::string error_msg;
+
+    // Walk the bytes and diff against our boot image
+    const ImageHeader& boot_image_header = GetBootImageHeader();
+
+    os << "\nObserving boot image header at address "
+       << reinterpret_cast<const void*>(&boot_image_header)
+       << "\n\n";
+
+    const uint8_t* image_begin_unaligned = boot_image_header.GetImageBegin();
+    const uint8_t* image_end_unaligned = image_begin_unaligned + boot_image_header.GetImageSize();
+
+    // Adjust range to nearest page
+    const uint8_t* image_begin = AlignDown(image_begin_unaligned, kPageSize);
+    const uint8_t* image_end = AlignUp(image_end_unaligned, kPageSize);
+
+    ptrdiff_t page_off_begin = boot_image_header.GetImageBegin() - image_begin;
+
+    if (reinterpret_cast<uintptr_t>(image_begin) > boot_map.start ||
+        reinterpret_cast<uintptr_t>(image_end) < boot_map.end) {
+      // Sanity check that we aren't trying to read a completely different boot image
+      os << "Remote boot map is out of range of local boot map: " <<
+        "local begin " << reinterpret_cast<const void*>(image_begin) <<
+        ", local end " << reinterpret_cast<const void*>(image_end) <<
+        ", remote begin " << reinterpret_cast<const void*>(boot_map.start) <<
+        ", remote end " << reinterpret_cast<const void*>(boot_map.end);
+      return false;
+      // If we wanted even more validation we could map the ImageHeader from the file
+    }
+
+    std::vector<uint8_t> remote_contents(boot_map_size);
+    if (!map_file->PreadFully(&remote_contents[0], boot_map_size, boot_map.start)) {
+      os << "Could not fully read file " << file_name;
+      return false;
+    }
+
+    std::string page_map_file_name = StringPrintf("/proc/%ld/pagemap",
+                                                  static_cast<long>(image_diff_pid));  // NOLINT [runtime/int]
+    auto page_map_file = std::unique_ptr<File>(OS::OpenFileForReading(page_map_file_name.c_str()));
+    if (page_map_file == nullptr) {
+      os << "Failed to open " << page_map_file_name << " for reading: " << strerror(errno);
+      return false;
+    }
+
+    // Not truly clean, mmap-ing boot.art again would be more pristine, but close enough
+    const char* clean_page_map_file_name = "/proc/self/pagemap";
+    auto clean_page_map_file = std::unique_ptr<File>(
+        OS::OpenFileForReading(clean_page_map_file_name));
+    if (clean_page_map_file == nullptr) {
+      os << "Failed to open " << clean_page_map_file_name << " for reading: " << strerror(errno);
+      return false;
+    }
+
+    auto kpage_flags_file = std::unique_ptr<File>(OS::OpenFileForReading("/proc/kpageflags"));
+    if (kpage_flags_file == nullptr) {
+      os << "Failed to open /proc/kpageflags for reading: " << strerror(errno);
+      return false;
+    }
+
+    auto kpage_count_file = std::unique_ptr<File>(OS::OpenFileForReading("/proc/kpagecount"));
+    if (kpage_count_file == nullptr) {
+      os << "Failed to open /proc/kpagecount for reading:" << strerror(errno);
+      return false;
+    }
+
+    std::set<size_t> dirty_page_set_remote;  // Set of the remote virtual page indices that are dirty
+    std::set<size_t> dirty_page_set_local;   // Set of the local virtual page indices that are dirty
+
+    size_t different_int32s = 0;
+    size_t different_bytes = 0;
+    size_t different_pages = 0;
+    size_t virtual_page_idx = 0;   // Virtual page number (for an absolute memory address)
+    size_t page_idx = 0;           // Page index relative to 0
+    size_t previous_page_idx = 0;  // Previous page index relative to 0
+    size_t dirty_pages = 0;
+    size_t private_pages = 0;
+    size_t private_dirty_pages = 0;
+
+    // Iterate through one page at a time. Boot map begin/end already implicitly aligned.
+    for (uintptr_t begin = boot_map.start; begin != boot_map.end; begin += kPageSize) {
+      ptrdiff_t offset = begin - boot_map.start;
+
+      // We treat the image header as part of the memory map for now
+      // If we wanted to change this, we could pass base=start+sizeof(ImageHeader)
+      // But it might still be interesting to see if any of the ImageHeader data mutated
+      const uint8_t* local_ptr = reinterpret_cast<const uint8_t*>(&boot_image_header) + offset;
+      uint8_t* remote_ptr = &remote_contents[offset];
+
+      if (memcmp(local_ptr, remote_ptr, kPageSize) != 0) {
+        different_pages++;
+
+        // Count the number of 32-bit integers that are different.
+        for (size_t i = 0; i < kPageSize / sizeof(uint32_t); ++i) {
+          uint32_t* remote_ptr_int32 = reinterpret_cast<uint32_t*>(remote_ptr);
+          const uint32_t* local_ptr_int32 = reinterpret_cast<const uint32_t*>(local_ptr);
+
+          if (remote_ptr_int32[i] != local_ptr_int32[i]) {
+            different_int32s++;
+          }
+        }
+      }
+    }
+
+    // Iterate through one byte at a time.
+    for (uintptr_t begin = boot_map.start; begin != boot_map.end; ++begin) {
+      previous_page_idx = page_idx;
+      ptrdiff_t offset = begin - boot_map.start;
+
+      // We treat the image header as part of the memory map for now
+      // If we wanted to change this, we could pass base=start+sizeof(ImageHeader)
+      // But it might still be interesting to see if any of the ImageHeader data mutated
+      const uint8_t* local_ptr = reinterpret_cast<const uint8_t*>(&boot_image_header) + offset;
+      uint8_t* remote_ptr = &remote_contents[offset];
+
+      virtual_page_idx = reinterpret_cast<uintptr_t>(local_ptr) / kPageSize;
+
+      // Calculate the page index, relative to the 0th page where the image begins
+      page_idx = (offset + page_off_begin) / kPageSize;
+      if (*local_ptr != *remote_ptr) {
+        // Track number of bytes that are different
+        different_bytes++;
+      }
+
+      // Independently count the # of dirty pages on the remote side
+      size_t remote_virtual_page_idx = begin / kPageSize;
+      if (previous_page_idx != page_idx) {
+        uint64_t page_count = 0xC0FFEE;
+        // TODO: virtual_page_idx needs to be from the same process
+        int dirtiness = (IsPageDirty(page_map_file.get(),        // Image-diff-pid procmap
+                                     clean_page_map_file.get(),  // Self procmap
+                                     kpage_flags_file.get(),
+                                     kpage_count_file.get(),
+                                     remote_virtual_page_idx,    // potentially "dirty" page
+                                     virtual_page_idx,           // true "clean" page
+                                     &page_count,
+                                     &error_msg));
+        if (dirtiness < 0) {
+          os << error_msg;
+          return false;
+        } else if (dirtiness > 0) {
+          dirty_pages++;
+          dirty_page_set_remote.insert(dirty_page_set_remote.end(), remote_virtual_page_idx);
+          dirty_page_set_local.insert(dirty_page_set_local.end(), virtual_page_idx);
+        }
+
+        bool is_dirty = dirtiness > 0;
+        bool is_private = page_count == 1;
+
+        if (page_count == 1) {
+          private_pages++;
+        }
+
+        if (is_dirty && is_private) {
+          private_dirty_pages++;
+        }
+      }
+    }
+
+    // Walk each object in the remote image space and compare it against ours
+    size_t different_objects = 0;
+    std::map<mirror::Class*, int /*count*/> dirty_object_class_map;
+    // Track only the byte-per-byte dirtiness (in bytes)
+    std::map<mirror::Class*, int /*byte_count*/> dirty_object_byte_count;
+    // Track the object-by-object dirtiness (in bytes)
+    std::map<mirror::Class*, int /*byte_count*/> dirty_object_size_in_bytes;
+    std::map<mirror::Class*, int /*count*/> clean_object_class_map;
+
+    std::map<mirror::Class*, std::string> class_to_descriptor_map;
+
+    std::map<off_t /* field offset */, int /* count */> art_method_field_dirty_count;
+    std::vector<mirror::ArtMethod*> art_method_dirty_objects;
+
+    std::map<off_t /* field offset */, int /* count */> class_field_dirty_count;
+    std::vector<mirror::Class*> class_dirty_objects;
+
+    // List of local objects that are clean, but located on dirty pages.
+    std::vector<mirror::Object*> false_dirty_objects;
+    std::map<mirror::Class*, int /*byte_count*/> false_dirty_byte_count;
+    std::map<mirror::Class*, int /*object_count*/> false_dirty_object_count;
+    std::map<mirror::Class*, std::vector<mirror::Object*>> false_dirty_objects_map;
+    size_t false_dirty_object_bytes = 0;
+
+    // Remote pointers to dirty objects
+    std::map<mirror::Class*, std::vector<mirror::Object*>> dirty_objects_by_class;
+    // Look up remote classes by their descriptor
+    std::map<std::string, mirror::Class*> remote_class_map;
+    // Look up local classes by their descriptor
+    std::map<std::string, mirror::Class*> local_class_map;
+
+    size_t dirty_object_bytes = 0;
+    {
+      const uint8_t* begin_image_ptr = image_begin_unaligned;
+      const uint8_t* end_image_ptr = image_end_unaligned;
+
+      const uint8_t* current = begin_image_ptr + RoundUp(sizeof(ImageHeader), kObjectAlignment);
+      while (reinterpret_cast<const uintptr_t>(current)
+             < reinterpret_cast<const uintptr_t>(end_image_ptr)) {
+        CHECK_ALIGNED(current, kObjectAlignment);
+        mirror::Object* obj = reinterpret_cast<mirror::Object*>(const_cast<uint8_t*>(current));
+
+        // Sanity check that we are reading a real object
+        CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
+        if (kUseBakerOrBrooksReadBarrier) {
+          obj->AssertReadBarrierPointer();
+        }
+
+        // Iterate every page this object belongs to
+        bool on_dirty_page = false;
+        size_t page_off = 0;
+        size_t current_page_idx;
+        uintptr_t object_address;
+        do {
+          object_address = reinterpret_cast<uintptr_t>(current);
+          current_page_idx = object_address / kPageSize + page_off;
+
+          if (dirty_page_set_local.find(current_page_idx) != dirty_page_set_local.end()) {
+            // This object is on a dirty page
+            on_dirty_page = true;
+          }
+
+          page_off++;
+        } while ((current_page_idx * kPageSize) <
+                 RoundUp(object_address + obj->SizeOf(), kObjectAlignment));
+
+        mirror::Class* klass = obj->GetClass();
+
+        bool different_object = false;
+
+        // Check against the other object and see if they are different
+        ptrdiff_t offset = current - begin_image_ptr;
+        const uint8_t* current_remote = &remote_contents[offset];
+        mirror::Object* remote_obj = reinterpret_cast<mirror::Object*>(
+            const_cast<uint8_t*>(current_remote));
+        if (memcmp(current, current_remote, obj->SizeOf()) != 0) {
+          different_objects++;
+          dirty_object_bytes += obj->SizeOf();
+
+          ++dirty_object_class_map[klass];
+
+          // Go byte-by-byte and figure out what exactly got dirtied
+          size_t dirty_byte_count_per_object = 0;
+          for (size_t i = 0; i < obj->SizeOf(); ++i) {
+            if (current[i] != current_remote[i]) {
+              dirty_byte_count_per_object++;
+            }
+          }
+          dirty_object_byte_count[klass] += dirty_byte_count_per_object;
+          dirty_object_size_in_bytes[klass] += obj->SizeOf();
+
+          different_object = true;
+
+          dirty_objects_by_class[klass].push_back(remote_obj);
+        } else {
+          ++clean_object_class_map[klass];
+        }
+
+        std::string descriptor = GetClassDescriptor(klass);
+        if (different_object) {
+          if (strcmp(descriptor.c_str(), "Ljava/lang/Class;") == 0) {
+            // this is a "Class"
+            mirror::Class* obj_as_class  = reinterpret_cast<mirror::Class*>(remote_obj);
+
+            // print the fields that are dirty
+            for (size_t i = 0; i < obj->SizeOf(); ++i) {
+              if (current[i] != current_remote[i]) {
+                class_field_dirty_count[i]++;
+              }
+            }
+
+            class_dirty_objects.push_back(obj_as_class);
+          } else if (strcmp(descriptor.c_str(), "Ljava/lang/reflect/ArtMethod;") == 0) {
+            // this is an ArtMethod
+            mirror::ArtMethod* art_method = reinterpret_cast<mirror::ArtMethod*>(remote_obj);
+
+            // print the fields that are dirty
+            for (size_t i = 0; i < obj->SizeOf(); ++i) {
+              if (current[i] != current_remote[i]) {
+                art_method_field_dirty_count[i]++;
+              }
+            }
+
+            art_method_dirty_objects.push_back(art_method);
+          }
+        } else if (on_dirty_page) {
+          // This object was either never mutated or got mutated back to the same value.
+          // TODO: Do I want to distinguish a "different" vs a "dirty" page here?
+          false_dirty_objects.push_back(obj);
+          false_dirty_objects_map[klass].push_back(obj);
+          false_dirty_object_bytes += obj->SizeOf();
+          false_dirty_byte_count[obj->GetClass()] += obj->SizeOf();
+          false_dirty_object_count[obj->GetClass()] += 1;
+        }
+
+        if (strcmp(descriptor.c_str(), "Ljava/lang/Class;") == 0) {
+          local_class_map[descriptor] = reinterpret_cast<mirror::Class*>(obj);
+          remote_class_map[descriptor] = reinterpret_cast<mirror::Class*>(remote_obj);
+        }
+
+        // Unconditionally store the class descriptor in case we need it later
+        class_to_descriptor_map[klass] = descriptor;
+        current += RoundUp(obj->SizeOf(), kObjectAlignment);
+      }
+    }
+
+    // Looking at only dirty pages, figure out how many of those bytes belong to dirty objects.
+    float true_dirtied_percent = dirty_object_bytes * 1.0f / (dirty_pages * kPageSize);
+    size_t false_dirty_pages = dirty_pages - different_pages;
+
+    os << "Mapping at [" << reinterpret_cast<void*>(boot_map.start) << ", "
+       << reinterpret_cast<void*>(boot_map.end) << ") had: \n  "
+       << different_bytes << " differing bytes, \n  "
+       << different_int32s << " differing int32s, \n  "
+       << different_objects << " different objects, \n  "
+       << dirty_object_bytes << " different object [bytes], \n  "
+       << false_dirty_objects.size() << " false dirty objects,\n  "
+       << false_dirty_object_bytes << " false dirty object [bytes], \n  "
+       << true_dirtied_percent << " different objects-vs-total in a dirty page;\n  "
+       << different_pages << " different pages; \n  "
+       << dirty_pages << " pages are dirty; \n  "
+       << false_dirty_pages << " pages are false dirty; \n  "
+       << private_pages << " pages are private; \n  "
+       << private_dirty_pages << " pages are Private_Dirty\n  "
+       << "";
+
+    // vector of pairs (int count, Class*)
+    auto dirty_object_class_values = SortByValueDesc(dirty_object_class_map);
+    auto clean_object_class_values = SortByValueDesc(clean_object_class_map);
+
+    os << "\n" << "  Dirty object count by class:\n";
+    for (const auto& vk_pair : dirty_object_class_values) {
+      int dirty_object_count = vk_pair.first;
+      mirror::Class* klass = vk_pair.second;
+      int object_sizes = dirty_object_size_in_bytes[klass];
+      float avg_dirty_bytes_per_class = dirty_object_byte_count[klass] * 1.0f / object_sizes;
+      float avg_object_size = object_sizes * 1.0f / dirty_object_count;
+      const std::string& descriptor = class_to_descriptor_map[klass];
+      os << "    " << PrettyClass(klass) << " ("
+         << "objects: " << dirty_object_count << ", "
+         << "avg dirty bytes: " << avg_dirty_bytes_per_class << ", "
+         << "avg object size: " << avg_object_size << ", "
+         << "class descriptor: '" << descriptor << "'"
+         << ")\n";
+
+      constexpr size_t kMaxAddressPrint = 5;
+      if (strcmp(descriptor.c_str(), "Ljava/lang/reflect/ArtMethod;") == 0) {
+        os << "      sample object addresses: ";
+        for (size_t i = 0; i < art_method_dirty_objects.size() && i < kMaxAddressPrint; ++i) {
+          auto art_method = art_method_dirty_objects[i];
+
+          os << reinterpret_cast<void*>(art_method) << ", ";
+        }
+        os << "\n";
+
+        os << "      dirty byte +offset:count list = ";
+        auto art_method_field_dirty_count_sorted = SortByValueDesc(art_method_field_dirty_count);
+        for (auto pair : art_method_field_dirty_count_sorted) {
+          off_t offset = pair.second;
+          int count = pair.first;
+
+          os << "+" << offset << ":" << count << ", ";
+        }
+
+        os << "\n";
+
+        os << "      field contents:\n";
+        const auto& dirty_objects_list = dirty_objects_by_class[klass];
+        for (mirror::Object* obj : dirty_objects_list) {
+          // remote method
+          auto art_method = reinterpret_cast<mirror::ArtMethod*>(obj);
+
+          // remote class
+          mirror::Class* remote_declaring_class =
+            FixUpRemotePointer(art_method->GetDeclaringClass(), remote_contents, boot_map);
+
+          // local class
+          mirror::Class* declaring_class =
+            RemoteContentsPointerToLocal(remote_declaring_class,
+                                         remote_contents,
+                                         boot_image_header);
+
+          os << "        " << reinterpret_cast<void*>(obj) << " ";
+          os << "  entryPointFromJni: "
+             << reinterpret_cast<const void*>(
+                    art_method->GetEntryPointFromJniPtrSize(pointer_size)) << ", ";
+          os << "  entryPointFromInterpreter: "
+             << reinterpret_cast<const void*>(
+                    art_method->GetEntryPointFromInterpreterPtrSize<kVerifyNone>(pointer_size))
+             << ", ";
+          os << "  entryPointFromQuickCompiledCode: "
+             << reinterpret_cast<const void*>(
+                    art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
+             << ", ";
+          os << "  isNative? " << (art_method->IsNative() ? "yes" : "no") << ", ";
+          os << "  class_status (local): " << declaring_class->GetStatus();
+          os << "  class_status (remote): " << remote_declaring_class->GetStatus();
+          os << "\n";
+        }
+      }
+      if (strcmp(descriptor.c_str(), "Ljava/lang/Class;") == 0) {
+        os << "       sample object addresses: ";
+        for (size_t i = 0; i < class_dirty_objects.size() && i < kMaxAddressPrint; ++i) {
+          auto class_ptr = class_dirty_objects[i];
+
+          os << reinterpret_cast<void*>(class_ptr) << ", ";
+        }
+        os << "\n";
+
+        os << "       dirty byte +offset:count list = ";
+        auto class_field_dirty_count_sorted = SortByValueDesc(class_field_dirty_count);
+        for (auto pair : class_field_dirty_count_sorted) {
+          off_t offset = pair.second;
+          int count = pair.first;
+
+          os << "+" << offset << ":" << count << ", ";
+        }
+        os << "\n";
+
+        os << "      field contents:\n";
+        const auto& dirty_objects_list = dirty_objects_by_class[klass];
+        for (mirror::Object* obj : dirty_objects_list) {
+          // remote class object
+          auto remote_klass = reinterpret_cast<mirror::Class*>(obj);
+
+          // local class object
+          auto local_klass = RemoteContentsPointerToLocal(remote_klass,
+                                                          remote_contents,
+                                                          boot_image_header);
+
+          os << "        " << reinterpret_cast<void*>(obj) << " ";
+          os << "  class_status (remote): " << remote_klass->GetStatus() << ", ";
+          os << "  class_status (local): " << local_klass->GetStatus();
+          os << "\n";
+        }
+      }
+    }
+
+    auto false_dirty_object_class_values = SortByValueDesc(false_dirty_object_count);
+
+    os << "\n" << "  False-dirty object count by class:\n";
+    for (const auto& vk_pair : false_dirty_object_class_values) {
+      int object_count = vk_pair.first;
+      mirror::Class* klass = vk_pair.second;
+      int object_sizes = false_dirty_byte_count[klass];
+      float avg_object_size = object_sizes * 1.0f / object_count;
+      const std::string& descriptor = class_to_descriptor_map[klass];
+      os << "    " << PrettyClass(klass) << " ("
+         << "objects: " << object_count << ", "
+         << "avg object size: " << avg_object_size << ", "
+         << "total bytes: " << object_sizes << ", "
+         << "class descriptor: '" << descriptor << "'"
+         << ")\n";
+
+      if (strcmp(descriptor.c_str(), "Ljava/lang/reflect/ArtMethod;") == 0) {
+        auto& art_method_false_dirty_objects = false_dirty_objects_map[klass];
+
+        os << "      field contents:\n";
+        for (mirror::Object* obj : art_method_false_dirty_objects) {
+          // local method
+          auto art_method = reinterpret_cast<mirror::ArtMethod*>(obj);
+
+          // local class
+          mirror::Class* declaring_class = art_method->GetDeclaringClass();
+
+          os << "        " << reinterpret_cast<void*>(obj) << " ";
+          os << "  entryPointFromJni: "
+             << reinterpret_cast<const void*>(
+                    art_method->GetEntryPointFromJniPtrSize(pointer_size)) << ", ";
+          os << "  entryPointFromInterpreter: "
+             << reinterpret_cast<const void*>(
+                    art_method->GetEntryPointFromInterpreterPtrSize<kVerifyNone>(pointer_size))
+             << ", ";
+          os << "  entryPointFromQuickCompiledCode: "
+             << reinterpret_cast<const void*>(
+                    art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
+             << ", ";
+          os << "  isNative? " << (art_method->IsNative() ? "yes" : "no") << ", ";
+          os << "  class_status (local): " << declaring_class->GetStatus();
+          os << "\n";
+        }
+      }
+    }
+
+    os << "\n" << "  Clean object count by class:\n";
+    for (const auto& vk_pair : clean_object_class_values) {
+      os << "    " << PrettyClass(vk_pair.second) << " (" << vk_pair.first << ")\n";
+    }
+
+    return true;
+  }
+
+  // Fixup a remote pointer that we read from a foreign boot.art to point to our own memory.
+  // Returned pointer will point to inside of remote_contents.
+  template <typename T>
+  static T* FixUpRemotePointer(T* remote_ptr,
+                               std::vector<uint8_t>& remote_contents,
+                               const backtrace_map_t& boot_map) {
+    if (remote_ptr == nullptr) {
+      return nullptr;
+    }
+
+    uintptr_t remote = reinterpret_cast<uintptr_t>(remote_ptr);
+
+    CHECK_LE(boot_map.start, remote);
+    CHECK_GT(boot_map.end, remote);
+
+    off_t boot_offset = remote - boot_map.start;
+
+    return reinterpret_cast<T*>(&remote_contents[boot_offset]);
+  }
+
+  template <typename T>
+  static T* RemoteContentsPointerToLocal(T* remote_ptr,
+                                         std::vector<uint8_t>& remote_contents,
+                                         const ImageHeader& image_header) {
+    if (remote_ptr == nullptr) {
+      return nullptr;
+    }
+
+    uint8_t* remote = reinterpret_cast<uint8_t*>(remote_ptr);
+    ptrdiff_t boot_offset = remote - &remote_contents[0];
+
+    const uint8_t* local_ptr = reinterpret_cast<const uint8_t*>(&image_header) + boot_offset;
+
+    return reinterpret_cast<T*>(const_cast<uint8_t*>(local_ptr));
+  }
+
+  static std::string GetClassDescriptor(mirror::Class* klass)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CHECK(klass != nullptr);
+
+    std::string descriptor;
+    const char* descriptor_str = klass->GetDescriptor(&descriptor);
+
+    return std::string(descriptor_str);
+  }
+
+  template <typename K, typename V>
+  static std::vector<std::pair<V, K>> SortByValueDesc(const std::map<K, V> map) {
+    // Store value->key so that we can use the default sort from pair which
+    // sorts by value first and then key
+    std::vector<std::pair<V, K>> value_key_vector;
+
+    for (const auto& kv_pair : map) {
+      value_key_vector.push_back(std::make_pair(kv_pair.second, kv_pair.first));
+    }
+
+    // Sort in reverse (descending order)
+    std::sort(value_key_vector.rbegin(), value_key_vector.rend());
+    return value_key_vector;
+  }
+
+  static bool GetPageFrameNumber(File* page_map_file,
+                                size_t virtual_page_index,
+                                uint64_t* page_frame_number,
+                                std::string* error_msg) {
+    CHECK(page_map_file != nullptr);
+    CHECK(page_frame_number != nullptr);
+    CHECK(error_msg != nullptr);
+
+    constexpr size_t kPageMapEntrySize = sizeof(uint64_t);
+    constexpr uint64_t kPageFrameNumberMask = (1ULL << 55) - 1;  // bits 0-54 [in /proc/$pid/pagemap]
+    constexpr uint64_t kPageSoftDirtyMask = (1ULL << 55);  // bit 55 [in /proc/$pid/pagemap]
+
+    uint64_t page_map_entry = 0;
+
+    // Read 64-bit entry from /proc/$pid/pagemap to get the physical page frame number
+    if (!page_map_file->PreadFully(&page_map_entry, kPageMapEntrySize,
+                                  virtual_page_index * kPageMapEntrySize)) {
+      *error_msg = StringPrintf("Failed to read the virtual page index entry from %s",
+                                page_map_file->GetPath().c_str());
+      return false;
+    }
+
+    // TODO: seems useless, remove this.
+    bool soft_dirty = (page_map_entry & kPageSoftDirtyMask) != 0;
+    if ((false)) {
+      LOG(VERBOSE) << soft_dirty;  // Suppress unused warning
+      UNREACHABLE();
+    }
+
+    *page_frame_number = page_map_entry & kPageFrameNumberMask;
+
+    return true;
+  }
+
+  static int IsPageDirty(File* page_map_file,
+                         File* clean_page_map_file,
+                         File* kpage_flags_file,
+                         File* kpage_count_file,
+                         size_t virtual_page_idx,
+                         size_t clean_virtual_page_idx,
+                         // Out parameters:
+                         uint64_t* page_count, std::string* error_msg) {
+    CHECK(page_map_file != nullptr);
+    CHECK(clean_page_map_file != nullptr);
+    CHECK_NE(page_map_file, clean_page_map_file);
+    CHECK(kpage_flags_file != nullptr);
+    CHECK(kpage_count_file != nullptr);
+    CHECK(page_count != nullptr);
+    CHECK(error_msg != nullptr);
+
+    // Constants are from https://www.kernel.org/doc/Documentation/vm/pagemap.txt
+
+    constexpr size_t kPageFlagsEntrySize = sizeof(uint64_t);
+    constexpr size_t kPageCountEntrySize = sizeof(uint64_t);
+    constexpr uint64_t kPageFlagsDirtyMask = (1ULL << 4);  // in /proc/kpageflags
+    constexpr uint64_t kPageFlagsNoPageMask = (1ULL << 20);  // in /proc/kpageflags
+    constexpr uint64_t kPageFlagsMmapMask = (1ULL << 11);  // in /proc/kpageflags
+
+    uint64_t page_frame_number = 0;
+    if (!GetPageFrameNumber(page_map_file, virtual_page_idx, &page_frame_number, error_msg)) {
+      return -1;
+    }
+
+    uint64_t page_frame_number_clean = 0;
+    if (!GetPageFrameNumber(clean_page_map_file, clean_virtual_page_idx, &page_frame_number_clean,
+                            error_msg)) {
+      return -1;
+    }
+
+    // Read 64-bit entry from /proc/kpageflags to get the dirty bit for a page
+    uint64_t kpage_flags_entry = 0;
+    if (!kpage_flags_file->PreadFully(&kpage_flags_entry,
+                                     kPageFlagsEntrySize,
+                                     page_frame_number * kPageFlagsEntrySize)) {
+      *error_msg = StringPrintf("Failed to read the page flags from %s",
+                                kpage_flags_file->GetPath().c_str());
+      return -1;
+    }
+
+    // Read 64-bit entyry from /proc/kpagecount to get mapping counts for a page
+    if (!kpage_count_file->PreadFully(page_count /*out*/,
+                                     kPageCountEntrySize,
+                                     page_frame_number * kPageCountEntrySize)) {
+      *error_msg = StringPrintf("Failed to read the page count from %s",
+                                kpage_count_file->GetPath().c_str());
+      return -1;
+    }
+
+    // There must be a page frame at the requested address.
+    CHECK_EQ(kpage_flags_entry & kPageFlagsNoPageMask, 0u);
+    // The page frame must be memory mapped
+    CHECK_NE(kpage_flags_entry & kPageFlagsMmapMask, 0u);
+
+    // Page is dirty, i.e. has diverged from file, if the 4th bit is set to 1
+    bool flags_dirty = (kpage_flags_entry & kPageFlagsDirtyMask) != 0;
+
+    // page_frame_number_clean must come from the *same* process
+    // but a *different* mmap than page_frame_number
+    if (flags_dirty) {
+      CHECK_NE(page_frame_number, page_frame_number_clean);
+    }
+
+    return page_frame_number != page_frame_number_clean;
+  }
+
+  static const ImageHeader& GetBootImageHeader() {
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    gc::space::ImageSpace* image_space = heap->GetImageSpace();
+    CHECK(image_space != nullptr);
+    const ImageHeader& image_header = image_space->GetImageHeader();
+    return image_header;
+  }
+
+ private:
+  // Return the image location, stripped of any directories, e.g. "boot.art" or "core.art"
+  std::string GetImageLocationBaseName() const {
+    return BaseName(std::string(image_location_));
+  }
+
+  std::ostream* os_;
+  const ImageHeader& image_header_;
+  const char* image_location_;
+  pid_t image_diff_pid_;  // Dump image diff against boot.art if pid is non-negative
+
+  DISALLOW_COPY_AND_ASSIGN(ImgDiagDumper);
+};
+
+static int DumpImage(Runtime* runtime, const char* image_location,
+                     std::ostream* os, pid_t image_diff_pid) {
+  ScopedObjectAccess soa(Thread::Current());
+  gc::Heap* heap = runtime->GetHeap();
+  gc::space::ImageSpace* image_space = heap->GetImageSpace();
+  CHECK(image_space != nullptr);
+  const ImageHeader& image_header = image_space->GetImageHeader();
+  if (!image_header.IsValid()) {
+    fprintf(stderr, "Invalid image header %s\n", image_location);
+    return EXIT_FAILURE;
+  }
+
+  ImgDiagDumper img_diag_dumper(os, image_header, image_location, image_diff_pid);
+
+  bool success = img_diag_dumper.Dump();
+  return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+struct ImgDiagArgs : public CmdlineArgs {
+ protected:
+  using Base = CmdlineArgs;
+
+  virtual ParseStatus ParseCustom(const StringPiece& option,
+                                  std::string* error_msg) OVERRIDE {
+    {
+      ParseStatus base_parse = Base::ParseCustom(option, error_msg);
+      if (base_parse != kParseUnknownArgument) {
+        return base_parse;
+      }
+    }
+
+    if (option.starts_with("--image-diff-pid=")) {
+      const char* image_diff_pid = option.substr(strlen("--image-diff-pid=")).data();
+
+      if (!ParseInt(image_diff_pid, &image_diff_pid_)) {
+        *error_msg = "Image diff pid out of range";
+        return kParseError;
+      }
+    } else {
+      return kParseUnknownArgument;
+    }
+
+    return kParseOk;
+  }
+
+  virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
+    // Perform the parent checks.
+    ParseStatus parent_checks = Base::ParseChecks(error_msg);
+    if (parent_checks != kParseOk) {
+      return parent_checks;
+    }
+
+    // Perform our own checks.
+
+    if (kill(image_diff_pid_,
+             /*sig*/0) != 0) {  // No signal is sent, perform error-checking only.
+      // Check if the pid exists before proceeding.
+      if (errno == ESRCH) {
+        *error_msg = "Process specified does not exist";
+      } else {
+        *error_msg = StringPrintf("Failed to check process status: %s", strerror(errno));
+      }
+      return kParseError;
+    } else if (instruction_set_ != kRuntimeISA) {
+      // Don't allow different ISAs since the images are ISA-specific.
+      // Right now the code assumes both the runtime ISA and the remote ISA are identical.
+      *error_msg = "Must use the default runtime ISA; changing ISA is not supported.";
+      return kParseError;
+    }
+
+    return kParseOk;
+  }
+
+  virtual std::string GetUsage() const {
+    std::string usage;
+
+    usage +=
+        "Usage: imgdiag [options] ...\n"
+        "    Example: imgdiag --image-diff-pid=$(pidof dex2oat)\n"
+        "    Example: adb shell imgdiag --image-diff-pid=$(pid zygote)\n"
+        "\n";
+
+    usage += Base::GetUsage();
+
+    usage +=  // Optional.
+        "  --image-diff-pid=<pid>: provide the PID of a process whose boot.art you want to diff.\n"
+        "      Example: --image-diff-pid=$(pid zygote)\n"
+        "\n";
+
+    return usage;
+  }
+
+ public:
+  pid_t image_diff_pid_ = -1;
+};
+
+struct ImgDiagMain : public CmdlineMain<ImgDiagArgs> {
+  virtual bool ExecuteWithRuntime(Runtime* runtime) {
+    CHECK(args_ != nullptr);
+
+    return DumpImage(runtime,
+                     args_->boot_image_location_,
+                     args_->os_,
+                     args_->image_diff_pid_) == EXIT_SUCCESS;
+  }
+};
+
+}  // namespace art
+
+int main(int argc, char** argv) {
+  art::ImgDiagMain main;
+  return main.Main(argc, argv);
+}
diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc
new file mode 100644
index 0000000..1ac7930
--- /dev/null
+++ b/imgdiag/imgdiag_test.cc
@@ -0,0 +1,138 @@
+/*
+ * 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 <string>
+#include <vector>
+#include <sstream>
+
+#include "common_runtime_test.h"
+
+#include "runtime/os.h"
+#include "runtime/arch/instruction_set.h"
+#include "runtime/utils.h"
+#include "runtime/gc/space/image_space.h"
+#include "runtime/gc/heap.h"
+#include "base/stringprintf.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace art {
+
+static const char* kImgDiagDiffPid = "--image-diff-pid";
+static const char* kImgDiagBootImage = "--boot-image";
+static const char* kImgDiagBinaryName = "imgdiag";
+
+class ImgDiagTest : public CommonRuntimeTest {
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTest::SetUp();
+
+    // We loaded the runtime with an explicit image. Therefore the image space must exist.
+    gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
+    ASSERT_TRUE(image_space != nullptr);
+    boot_image_location_ = image_space->GetImageLocation();
+  }
+
+  virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
+    // Needs to live until CommonRuntimeTest::SetUp finishes, since we pass it a cstring.
+    runtime_args_image_ = StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str());
+    options->push_back(std::make_pair(runtime_args_image_, nullptr));
+  }
+
+  // Path to the imgdiag(d?)[32|64] binary.
+  std::string GetImgDiagFilePath() {
+    std::string root = GetTestAndroidRoot();
+
+    root += "/bin/";
+    root += kImgDiagBinaryName;
+
+    if (kIsDebugBuild) {
+      root += "d";
+    }
+
+    std::string root32 = root + "32";
+    // If we have both a 32-bit and a 64-bit build, the 32-bit file will have a 32 suffix.
+    if (OS::FileExists(root32.c_str()) && !Is64BitInstructionSet(kRuntimeISA)) {
+      return root32;
+    // Only a single build exists, so the filename never has an extra suffix.
+    } else {
+      return root;
+    }
+  }
+
+  // Run imgdiag with a custom boot image location.
+  bool Exec(pid_t image_diff_pid, const std::string& boot_image, std::string* error_msg) {
+    // Invoke 'img_diag' against the current process.
+    // This should succeed because we have a runtime and so it should
+    // be able to map in the boot.art and do a diff for it.
+    std::string file_path = GetImgDiagFilePath();
+    EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
+
+    // Run imgdiag --image-diff-pid=$image_diff_pid and wait until it's done with a 0 exit code.
+    std::string diff_pid_args;
+    {
+      std::stringstream diff_pid_args_ss;
+      diff_pid_args_ss << kImgDiagDiffPid << "=" << image_diff_pid;
+      diff_pid_args = diff_pid_args_ss.str();
+    }
+    std::string boot_image_args;
+    {
+      boot_image_args = boot_image_args + kImgDiagBootImage + "=" + boot_image;
+    }
+
+    std::vector<std::string> exec_argv = { file_path, diff_pid_args, boot_image_args };
+
+    return ::art::Exec(exec_argv, error_msg);
+  }
+
+  // Run imgdiag with the default boot image location.
+  bool ExecDefaultBootImage(pid_t image_diff_pid, std::string* error_msg) {
+    return Exec(image_diff_pid, boot_image_location_, error_msg);
+  }
+
+ private:
+  std::string runtime_args_image_;
+  std::string boot_image_location_;
+};
+
+#if defined (ART_TARGET)
+TEST_F(ImgDiagTest, ImageDiffPidSelf) {
+#else
+// Can't run this test on the host, it will fail when trying to open /proc/kpagestats
+// because it's root read-only.
+TEST_F(ImgDiagTest, DISABLED_ImageDiffPidSelf) {
+#endif
+  // Invoke 'img_diag' against the current process.
+  // This should succeed because we have a runtime and so it should
+  // be able to map in the boot.art and do a diff for it.
+
+  // Run imgdiag --image-diff-pid=$(self pid) and wait until it's done with a 0 exit code.
+  std::string error_msg;
+  ASSERT_TRUE(ExecDefaultBootImage(getpid(), &error_msg)) << "Failed to execute -- because: "
+                                                          << error_msg;
+}
+
+TEST_F(ImgDiagTest, ImageDiffBadPid) {
+  // Invoke 'img_diag' against a non-existing process. This should fail.
+
+  // Run imgdiag --image-diff-pid=some_bad_pid and wait until it's done with a 0 exit code.
+  std::string error_msg;
+  ASSERT_FALSE(ExecDefaultBootImage(-12345, &error_msg)) << "Incorrectly executed";
+  UNUSED(error_msg);
+}
+
+}  // namespace art
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index 25d10bd..f01afc5 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -21,19 +21,8 @@
 OATDUMP_SRC_FILES := \
 	oatdump.cc
 
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils libart-disassembler libart-compiler,art/disassembler art/compiler,target,ndebug))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils libartd-disassembler libart-compiler,art/disassembler art/compiler,target,debug))
-endif
-
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libart-disassembler libart-compiler,art/disassembler art/compiler,host,ndebug))
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libartd-disassembler libart-compiler,art/disassembler art/compiler,host,debug))
-endif
+# Build variants {target,host} x {debug,ndebug}
+$(eval $(call build-art-multi-executable,oatdump,$(OATDUMP_SRC_FILES),libart-compiler libart-disassembler,libcutils,,art/compiler art/disassembler))
 
 ########################################################################
 # oatdump targets
@@ -53,14 +42,14 @@
 
 .PHONY: dump-oat-core-host
 ifeq ($(ART_BUILD_HOST),true)
-dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(OATDUMP)
+dump-oat-core-host: $(HOST_CORE_IMG_OUTS) $(OATDUMP)
 	$(OATDUMP) --image=$(HOST_CORE_IMG_LOCATION) --output=$(ART_DUMP_OAT_PATH)/core.host.oatdump.txt
 	@echo Output in $(ART_DUMP_OAT_PATH)/core.host.oatdump.txt
 endif
 
 .PHONY: dump-oat-core-target
 ifeq ($(ART_BUILD_TARGET),true)
-dump-oat-core-target: $(TARGET_CORE_IMG_OUT) $(OATDUMP)
+dump-oat-core-target: $(TARGET_CORE_IMAGE_default_no-pic_32) $(OATDUMP)
 	$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
 	  --output=$(ART_DUMP_OAT_PATH)/core.target.oatdump.txt --instruction-set=$(TARGET_ARCH)
 	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.oatdump.txt
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d5e766f..931cca7 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -19,11 +19,13 @@
 
 #include <fstream>
 #include <iostream>
+#include <map>
+#include <set>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
-#include "base/stringpiece.h"
+#include "arch/instruction_set_features.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
@@ -31,7 +33,6 @@
 #include "dex_instruction.h"
 #include "disassembler.h"
 #include "elf_builder.h"
-#include "field_helper.h"
 #include "gc_map.h"
 #include "gc/space/image_space.h"
 #include "gc/space/large_object_space.h"
@@ -45,12 +46,10 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "noop_compiler_callbacks.h"
 #include "oat.h"
 #include "oat_file-inl.h"
 #include "os.h"
 #include "output_stream.h"
-#include "runtime.h"
 #include "safe_map.h"
 #include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
@@ -60,58 +59,15 @@
 #include "vmap_table.h"
 #include "well_known_classes.h"
 
-namespace art {
+#include <sys/stat.h>
+#include "cmdline.h"
 
-static void usage() {
-  fprintf(stderr,
-          "Usage: oatdump [options] ...\n"
-          "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
-          "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
-          "\n");
-  fprintf(stderr,
-          "  --oat-file=<file.oat>: specifies an input oat filename.\n"
-          "      Example: --oat-file=/system/framework/boot.oat\n"
-          "\n");
-  fprintf(stderr,
-          "  --image=<file.art>: specifies an input image filename.\n"
-          "      Example: --image=/system/framework/boot.art\n"
-          "\n");
-  fprintf(stderr,
-          "  --boot-image=<file.art>: provide the image file for the boot class path.\n"
-          "      Example: --boot-image=/system/framework/boot.art\n"
-          "\n");
-  fprintf(stderr,
-          "  --instruction-set=(arm|arm64|mips|x86|x86_64): for locating the image\n"
-          "      file based on the image location set.\n"
-          "      Example: --instruction-set=x86\n"
-          "      Default: %s\n"
-          "\n",
-          GetInstructionSetString(kRuntimeISA));
-  fprintf(stderr,
-          "  --output=<file> may be used to send the output to a file.\n"
-          "      Example: --output=/tmp/oatdump.txt\n"
-          "\n");
-  fprintf(stderr,
-          "  --dump:raw_mapping_table enables dumping of the mapping table.\n"
-          "      Example: --dump:raw_mapping_table\n"
-          "\n");
-  fprintf(stderr,
-          "  --dump:raw_mapping_table enables dumping of the GC map.\n"
-          "      Example: --dump:raw_gc_map\n"
-          "\n");
-  fprintf(stderr,
-          "  --no-dump:vmap may be used to disable vmap dumping.\n"
-          "      Example: --no-dump:vmap\n"
-          "\n");
-  fprintf(stderr,
-          "  --no-disassemble may be used to disable disassembly.\n"
-          "      Example: --no-disassemble\n"
-          "\n");
-}
+namespace art {
 
 const char* image_roots_descriptions_[] = {
   "kResolutionMethod",
   "kImtConflictMethod",
+  "kImtUnimplementedMethod",
   "kDefaultImt",
   "kCalleeSaveMethod",
   "kRefsOnlySaveMethod",
@@ -120,10 +76,12 @@
   "kClassRoots",
 };
 
-class OatSymbolizer : public CodeOutput {
+class OatSymbolizer FINAL : public CodeOutput {
  public:
-  explicit OatSymbolizer(const OatFile* oat_file, std::string& output_name) :
-      oat_file_(oat_file), builder_(nullptr), elf_output_(nullptr), output_name_(output_name) {}
+  explicit OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
+      oat_file_(oat_file), builder_(nullptr), elf_output_(nullptr),
+      output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
+  }
 
   bool Init() {
     Elf32_Word oat_data_size = oat_file_->GetOatHeader().GetExecutableOffset();
@@ -131,9 +89,6 @@
     uint32_t diff = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
     uint32_t oat_exec_size = diff - oat_data_size;
 
-    if (output_name_.empty()) {
-      output_name_ = "symbolized.oat";
-    }
     elf_output_ = OS::CreateEmptyFile(output_name_.c_str());
 
     builder_.reset(new ElfBuilder<Elf32_Word, Elf32_Sword, Elf32_Addr, Elf32_Dyn,
@@ -177,8 +132,8 @@
 
     bool result = builder_->Write();
 
-    elf_output_->Flush();
-    elf_output_->Close();
+    // Ignore I/O errors.
+    UNUSED(elf_output_->FlushClose());
 
     return result;
   }
@@ -220,7 +175,7 @@
 
   void WalkOatClass(const OatFile::OatClass& oat_class, const DexFile& dex_file,
                     const DexFile::ClassDef& class_def, Callback callback) {
-    const byte* class_data = dex_file.GetClassData(class_def);
+    const uint8_t* class_data = dex_file.GetClassData(class_def);
     if (class_data == nullptr) {  // empty class such as a marker interface?
       return;
     }
@@ -263,10 +218,13 @@
                       method_access_flags);
   }
 
-  void RegisterForDedup(const DexFile::ClassDef& class_def, uint32_t class_method_index,
-                        const OatFile::OatMethod& oat_method, const DexFile& dex_file,
-                        uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
-                        uint32_t method_access_flags) {
+  void RegisterForDedup(const DexFile::ClassDef& class_def ATTRIBUTE_UNUSED,
+                        uint32_t class_method_index ATTRIBUTE_UNUSED,
+                        const OatFile::OatMethod& oat_method,
+                        const DexFile& dex_file ATTRIBUTE_UNUSED,
+                        uint32_t dex_method_idx ATTRIBUTE_UNUSED,
+                        const DexFile::CodeItem* code_item ATTRIBUTE_UNUSED,
+                        uint32_t method_access_flags ATTRIBUTE_UNUSED) {
     state_[oat_method.GetCodeOffset()]++;
   }
 
@@ -294,10 +252,13 @@
     return DedupState::kDeduplicatedFirst;
   }
 
-  void AddSymbol(const DexFile::ClassDef& class_def, uint32_t class_method_index,
-                 const OatFile::OatMethod& oat_method, const DexFile& dex_file,
-                 uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
-                 uint32_t method_access_flags) {
+  void AddSymbol(const DexFile::ClassDef& class_def ATTRIBUTE_UNUSED,
+                 uint32_t class_method_index ATTRIBUTE_UNUSED,
+                 const OatFile::OatMethod& oat_method,
+                 const DexFile& dex_file,
+                 uint32_t dex_method_idx,
+                 const DexFile::CodeItem* code_item ATTRIBUTE_UNUSED,
+                 uint32_t method_access_flags ATTRIBUTE_UNUSED) {
     DedupState dedup = IsDuplicated(oat_method.GetCodeOffset());
     if (dedup != DedupState::kDeduplicatedOther) {
       std::string pretty_name = PrettyMethod(dex_method_idx, dex_file, true);
@@ -307,16 +268,16 @@
       }
 
       ElfSymtabBuilder<Elf32_Word, Elf32_Sword, Elf32_Addr,
-      Elf32_Sym, Elf32_Shdr>* symtab = &builder_->symtab_builder_;
+      Elf32_Sym, Elf32_Shdr>* symtab = builder_->GetSymtabBuilder();
 
-      symtab->AddSymbol(pretty_name, &builder_->text_builder_, oat_method.GetCodeOffset() -
-                        oat_file_->GetOatHeader().GetExecutableOffset(), true,
-                        oat_method.GetQuickCodeSize(), STB_GLOBAL, STT_FUNC);
+      symtab->AddSymbol(pretty_name, &builder_->GetTextBuilder(),
+          oat_method.GetCodeOffset() - oat_file_->GetOatHeader().GetExecutableOffset(),
+          true, oat_method.GetQuickCodeSize(), STB_GLOBAL, STT_FUNC);
     }
   }
 
   // Set oat data offset. Required by ElfBuilder/CodeOutput.
-  void SetCodeOffset(size_t offset) {
+  void SetCodeOffset(size_t offset ATTRIBUTE_UNUSED) {
     // Nothing to do.
   }
 
@@ -340,7 +301,7 @@
                               Elf32_Sym, Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr> > builder_;
   File* elf_output_;
   std::unordered_map<uint32_t, uint32_t> state_;
-  std::string output_name_;
+  const std::string output_name_;
 };
 
 class OatDumperOptions {
@@ -350,19 +311,21 @@
                    bool dump_vmap,
                    bool disassemble_code,
                    bool absolute_addresses,
-                   Handle<mirror::ClassLoader>* class_loader)
+                   const char* method_filter)
     : dump_raw_mapping_table_(dump_raw_mapping_table),
       dump_raw_gc_map_(dump_raw_gc_map),
       dump_vmap_(dump_vmap),
       disassemble_code_(disassemble_code),
       absolute_addresses_(absolute_addresses),
-      class_loader_(class_loader) {}
+      method_filter_(method_filter),
+      class_loader_(nullptr) {}
 
   const bool dump_raw_mapping_table_;
   const bool dump_raw_gc_map_;
   const bool dump_vmap_;
   const bool disassemble_code_;
   const bool absolute_addresses_;
+  const char* const method_filter_;
   Handle<mirror::ClassLoader>* class_loader_;
 };
 
@@ -372,9 +335,11 @@
     : oat_file_(oat_file),
       oat_dex_files_(oat_file.GetOatDexFiles()),
       options_(options),
-      disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet(),
+      instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
+      disassembler_(Disassembler::Create(instruction_set_,
                                          new DisassemblerOptions(options_->absolute_addresses_,
-                                                                 oat_file.Begin()))) {
+                                                                 oat_file.Begin(),
+                                                                 true /* can_read_litals_ */))) {
     CHECK(options_->class_loader_ != nullptr);
     AddAllOffsets();
   }
@@ -384,6 +349,10 @@
     delete disassembler_;
   }
 
+  InstructionSet GetInstructionSet() {
+    return instruction_set_;
+  }
+
   bool Dump(std::ostream& os) {
     bool success = true;
     const OatHeader& oat_header = oat_file_.GetOatHeader();
@@ -397,8 +366,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";
@@ -418,12 +392,6 @@
                            GetInterpreterToCompiledCodeBridgeOffset);
     DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
                            GetJniDlsymLookupOffset);
-    DUMP_OAT_HEADER_OFFSET("PORTABLE IMT CONFLICT TRAMPOLINE",
-                           GetPortableImtConflictTrampolineOffset);
-    DUMP_OAT_HEADER_OFFSET("PORTABLE RESOLUTION TRAMPOLINE",
-                           GetPortableResolutionTrampolineOffset);
-    DUMP_OAT_HEADER_OFFSET("PORTABLE TO INTERPRETER BRIDGE",
-                           GetPortableToInterpreterBridgeOffset);
     DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
                            GetQuickGenericJniTrampolineOffset);
     DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
@@ -483,8 +451,8 @@
   }
 
   size_t ComputeSize(const void* oat_data) {
-    if (reinterpret_cast<const byte*>(oat_data) < oat_file_.Begin() ||
-        reinterpret_cast<const byte*>(oat_data) > oat_file_.End()) {
+    if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
+        reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
       return 0;  // Address not in oat file
     }
     uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
@@ -495,7 +463,7 @@
     return end_offset - begin_offset;
   }
 
-  InstructionSet GetInstructionSet() {
+  InstructionSet GetOatInstructionSet() {
     return oat_file_.GetOatHeader().GetInstructionSet();
   }
 
@@ -509,8 +477,9 @@
         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
             << "': " << error_msg;
       } else {
+        const char* descriptor = m->GetDeclaringClassDescriptor();
         const DexFile::ClassDef* class_def =
-            dex_file->FindClassDef(m->GetDeclaringClassDescriptor());
+            dex_file->FindClassDef(descriptor, ComputeModifiedUtf8Hash(descriptor));
         if (class_def != nullptr) {
           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
@@ -544,7 +513,7 @@
            class_def_index++) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
-        const byte* class_data = dex_file->GetClassData(class_def);
+        const uint8_t* class_data = dex_file->GetClassData(class_def);
         if (class_data != nullptr) {
           ClassDataItemIterator it(*dex_file, class_data);
           SkipAllFields(it);
@@ -579,7 +548,7 @@
     offsets_.insert(code_offset);
     offsets_.insert(oat_method.GetMappingTableOffset());
     offsets_.insert(oat_method.GetVmapTableOffset());
-    offsets_.insert(oat_method.GetNativeGcMapOffset());
+    offsets_.insert(oat_method.GetGcMapOffset());
   }
 
   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
@@ -632,7 +601,7 @@
   bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
                     const DexFile::ClassDef& class_def) {
     bool success = true;
-    const byte* class_data = dex_file.GetClassData(class_def);
+    const uint8_t* class_data = dex_file.GetClassData(class_def);
     if (class_data == nullptr) {  // empty class such as a marker interface?
       os << std::flush;
       return success;
@@ -674,8 +643,13 @@
                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
                      uint32_t method_access_flags) {
     bool success = true;
+    std::string pretty_method = PrettyMethod(dex_method_idx, dex_file, true);
+    if (pretty_method.find(options_->method_filter_) == std::string::npos) {
+      return success;
+    }
+
     os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
-                       class_method_index, PrettyMethod(dex_method_idx, dex_file, true).c_str(),
+                       class_method_index, pretty_method.c_str(),
                        dex_method_idx);
     Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
     std::unique_ptr<std::ostream> indent1_os(new std::ostream(&indent1_filter));
@@ -724,9 +698,9 @@
 
       *indent2_os << "gc_map: ";
       if (options_->absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetNativeGcMap());
+        *indent2_os << StringPrintf("%p ", oat_method.GetGcMap());
       }
-      uint32_t gc_map_offset = oat_method.GetNativeGcMapOffset();
+      uint32_t gc_map_offset = oat_method.GetGcMapOffset();
       *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
       if (gc_map_offset > oat_file_.Size()) {
         *indent2_os << StringPrintf("WARNING: "
@@ -821,11 +795,6 @@
       } else {
         const void* code = oat_method.GetQuickCode();
         uint32_t code_size = oat_method.GetQuickCodeSize();
-        if (code == nullptr) {
-          code = oat_method.GetPortableCode();
-          code_size = oat_method.GetPortableCodeSize();
-          code_size_offset = 0;
-        }
         uint32_t code_offset = oat_method.GetCodeOffset();
         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
         uint64_t aligned_code_end = aligned_code_begin + code_size;
@@ -904,7 +873,7 @@
     // If the native GC map is null, then this method has been compiled with the
     // optimizing compiler. The optimizing compiler currently outputs its stack map
     // in the vmap table, and the code below does not work with such a stack map.
-    if (oat_method.GetNativeGcMap() == nullptr) {
+    if (oat_method.GetGcMap() == nullptr) {
       return;
     }
     const uint8_t* raw_table = oat_method.GetVmapTable();
@@ -1019,28 +988,17 @@
   }
   void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method,
                  const DexFile::CodeItem* code_item) {
-    const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
+    const uint8_t* gc_map_raw = oat_method.GetGcMap();
     if (gc_map_raw == nullptr) {
       return;  // No GC map.
     }
     const void* quick_code = oat_method.GetQuickCode();
-    if (quick_code != nullptr) {
-      NativePcOffsetToReferenceMap map(gc_map_raw);
-      for (size_t entry = 0; entry < map.NumEntries(); entry++) {
-        const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(quick_code) +
-            map.GetNativePcOffset(entry);
-        os << StringPrintf("%p", native_pc);
-        DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry));
-      }
-    } else {
-      const void* portable_code = oat_method.GetPortableCode();
-      CHECK(portable_code != nullptr);
-      verifier::DexPcToReferenceMap map(gc_map_raw);
-      for (size_t entry = 0; entry < map.NumEntries(); entry++) {
-        uint32_t dex_pc = map.GetDexPc(entry);
-        os << StringPrintf("0x%08x", dex_pc);
-        DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry));
-      }
+    NativePcOffsetToReferenceMap map(gc_map_raw);
+    for (size_t entry = 0; entry < map.NumEntries(); entry++) {
+      const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(quick_code) +
+          map.GetNativePcOffset(entry);
+      os << StringPrintf("%p", native_pc);
+      DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry));
     }
   }
 
@@ -1097,7 +1055,7 @@
 
   void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
                                  const DexFile::CodeItem* code_item, size_t native_pc_offset) {
-    const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
+    const uint8_t* gc_map_raw = oat_method.GetGcMap();
     if (gc_map_raw != nullptr) {
       NativePcOffsetToReferenceMap map(gc_map_raw);
       if (map.HasEntry(native_pc_offset)) {
@@ -1198,16 +1156,15 @@
   void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier,
                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
                 bool bad_input, size_t code_size) {
-    const void* portable_code = oat_method.GetPortableCode();
     const void* quick_code = oat_method.GetQuickCode();
 
     if (code_size == 0) {
       code_size = oat_method.GetQuickCodeSize();
     }
-    if ((code_size == 0) || ((portable_code == nullptr) && (quick_code == nullptr))) {
+    if (code_size == 0 || quick_code == nullptr) {
       os << "NO CODE!\n";
       return;
-    } else if (quick_code != nullptr) {
+    } else {
       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
       size_t offset = 0;
       while (offset < code_size) {
@@ -1225,15 +1182,13 @@
           }
         }
       }
-    } else {
-      CHECK(portable_code != nullptr);
-      CHECK_EQ(code_size, 0U);  // TODO: disassembly of portable is currently not supported.
     }
   }
 
   const OatFile& oat_file_;
   const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
   const OatDumperOptions* options_;
+  InstructionSet instruction_set_;
   std::set<uintptr_t> offsets_;
   Disassembler* disassembler_;
 };
@@ -1268,6 +1223,8 @@
 
     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
 
+    os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
+
     {
       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
       Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
@@ -1283,26 +1240,26 @@
           std::ostream indent2_os(&indent2_filter);
           mirror::ObjectArray<mirror::Object>* image_root_object_array
               = image_root_object->AsObjectArray<mirror::Object>();
-          for (int i = 0; i < image_root_object_array->GetLength(); i++) {
-            mirror::Object* value = image_root_object_array->Get(i);
+          for (int j = 0; j < image_root_object_array->GetLength(); j++) {
+            mirror::Object* value = image_root_object_array->Get(j);
             size_t run = 0;
-            for (int32_t j = i + 1; j < image_root_object_array->GetLength(); j++) {
-              if (value == image_root_object_array->Get(j)) {
+            for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
+              if (value == image_root_object_array->Get(k)) {
                 run++;
               } else {
                 break;
               }
             }
             if (run == 0) {
-              indent2_os << StringPrintf("%d: ", i);
+              indent2_os << StringPrintf("%d: ", j);
             } else {
-              indent2_os << StringPrintf("%d to %zd: ", i, i + run);
-              i = i + run;
+              indent2_os << StringPrintf("%d to %zd: ", j, j + run);
+              j = j + run;
             }
             if (value != nullptr) {
               PrettyObjectValue(indent2_os, value->GetClass(), value);
             } else {
-              indent2_os << i << ": null\n";
+              indent2_os << j << ": null\n";
             }
           }
         }
@@ -1318,7 +1275,7 @@
     std::string error_msg;
     const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location);
     if (oat_file == nullptr) {
-      oat_file = OatFile::Open(oat_location, oat_location, nullptr, false, &error_msg);
+      oat_file = OatFile::Open(oat_location, oat_location, nullptr, nullptr, false, &error_msg);
       if (oat_file == nullptr) {
         os << "NOT FOUND: " << error_msg << "\n";
         return false;
@@ -1425,50 +1382,54 @@
 
   static void PrintField(std::ostream& os, mirror::ArtField* field, mirror::Object* obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const char* descriptor = field->GetTypeDescriptor();
     os << StringPrintf("%s: ", field->GetName());
-    if (descriptor[0] != 'L' && descriptor[0] != '[') {
-      StackHandleScope<1> hs(Thread::Current());
-      FieldHelper fh(hs.NewHandle(field));
-      mirror::Class* type = fh.GetType();
-      DCHECK(type->IsPrimitive());
-      if (type->IsPrimitiveLong()) {
+    switch (field->GetTypeAsPrimitiveType()) {
+      case Primitive::kPrimLong:
         os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
-      } else if (type->IsPrimitiveDouble()) {
+        break;
+      case Primitive::kPrimDouble:
         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
-      } else if (type->IsPrimitiveFloat()) {
+        break;
+      case Primitive::kPrimFloat:
         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
-      } else if (type->IsPrimitiveInt()) {
+        break;
+      case Primitive::kPrimInt:
         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
-      } else if (type->IsPrimitiveChar()) {
+        break;
+      case Primitive::kPrimChar:
         os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
-      } else if (type->IsPrimitiveShort()) {
+        break;
+      case Primitive::kPrimShort:
         os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
-      } else if (type->IsPrimitiveBoolean()) {
+        break;
+      case Primitive::kPrimBoolean:
         os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj)? "true" : "false",
             field->GetBoolean(obj));
-      } else if (type->IsPrimitiveByte()) {
+        break;
+      case Primitive::kPrimByte:
         os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
-      } else {
-        LOG(FATAL) << "Unknown type: " << PrettyClass(type);
-      }
-    } else {
-      // Get the value, don't compute the type unless it is non-null as we don't want
-      // to cause class loading.
-      mirror::Object* value = field->GetObj(obj);
-      if (value == nullptr) {
-        os << StringPrintf("null   %s\n", PrettyDescriptor(descriptor).c_str());
-      } else {
-        // Grab the field type without causing resolution.
-        StackHandleScope<1> hs(Thread::Current());
-        FieldHelper fh(hs.NewHandle(field));
-        mirror::Class* field_type = fh.GetType(false);
-        if (field_type != nullptr) {
-          PrettyObjectValue(os, field_type, value);
+        break;
+      case Primitive::kPrimNot: {
+        // Get the value, don't compute the type unless it is non-null as we don't want
+        // to cause class loading.
+        mirror::Object* value = field->GetObj(obj);
+        if (value == nullptr) {
+          os << StringPrintf("null   %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
         } else {
-          os << StringPrintf("%p   %s\n", value, PrettyDescriptor(descriptor).c_str());
+          // Grab the field type without causing resolution.
+          mirror::Class* field_type = field->GetType(false);
+          if (field_type != nullptr) {
+            PrettyObjectValue(os, field_type, value);
+          } else {
+            os << StringPrintf("%p   %s\n", value,
+                               PrettyDescriptor(field->GetTypeDescriptor()).c_str());
+          }
         }
+        break;
       }
+      default:
+        os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
+        break;
     }
   }
 
@@ -1493,8 +1454,9 @@
 
   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()) {
+    const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
+        InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet()));
+    if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
       quick_code = oat_dumper_->GetQuickOatCode(m);
     }
     if (oat_dumper_->GetInstructionSet() == kThumb2) {
@@ -1594,11 +1556,12 @@
         }
       }
     } else if (obj->IsArtMethod()) {
+      const size_t image_pointer_size = InstructionSetPointerSize(
+          state->oat_dumper_->GetOatInstructionSet());
       mirror::ArtMethod* method = obj->AsArtMethod();
       if (method->IsNative()) {
-        // TODO: portable dumping.
-        DCHECK(method->GetNativeGcMap() == nullptr) << PrettyMethod(method);
-        DCHECK(method->GetMappingTable() == nullptr) << PrettyMethod(method);
+        DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
+        DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
         bool first_occurrence;
         const void* quick_oat_code = state->GetQuickOatCodeBegin(method);
         uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
@@ -1606,38 +1569,39 @@
         if (first_occurrence) {
           state->stats_.native_to_managed_code_bytes += quick_oat_code_size;
         }
-        if (quick_oat_code != method->GetEntryPointFromQuickCompiledCode()) {
+        if (quick_oat_code != method->GetEntryPointFromQuickCompiledCodePtrSize(
+            image_pointer_size)) {
           indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code);
         }
       } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
           method->IsResolutionMethod() || method->IsImtConflictMethod() ||
-          method->IsClassInitializer()) {
-        DCHECK(method->GetNativeGcMap() == nullptr) << PrettyMethod(method);
-        DCHECK(method->GetMappingTable() == nullptr) << PrettyMethod(method);
+          method->IsImtUnimplementedMethod() || method->IsClassInitializer()) {
+        DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
+        DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
       } else {
         const DexFile::CodeItem* code_item = method->GetCodeItem();
         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
 
         bool first_occurrence;
-        size_t gc_map_bytes = state->ComputeOatSize(method->GetNativeGcMap(), &first_occurrence);
+        size_t gc_map_bytes =
+            state->ComputeOatSize(method->GetNativeGcMap(image_pointer_size), &first_occurrence);
         if (first_occurrence) {
           state->stats_.gc_map_bytes += gc_map_bytes;
         }
 
         size_t pc_mapping_table_bytes =
-            state->ComputeOatSize(method->GetMappingTable(), &first_occurrence);
+            state->ComputeOatSize(method->GetMappingTable(image_pointer_size), &first_occurrence);
         if (first_occurrence) {
           state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
         }
 
         size_t vmap_table_bytes =
-            state->ComputeOatSize(method->GetVmapTable(), &first_occurrence);
+            state->ComputeOatSize(method->GetVmapTable(image_pointer_size), &first_occurrence);
         if (first_occurrence) {
           state->stats_.vmap_table_bytes += vmap_table_bytes;
         }
 
-        // TODO: portable dumping.
         const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method);
         const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method);
         uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
@@ -1734,20 +1698,20 @@
           dex_instruction_bytes(0) {}
 
     struct SizeAndCount {
-      SizeAndCount(size_t bytes, size_t count) : bytes(bytes), count(count) {}
+      SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
       size_t bytes;
       size_t count;
     };
     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
     SizeAndCountTable sizes_and_counts;
 
-    void Update(const char* descriptor, size_t object_bytes) {
+    void Update(const char* descriptor, size_t object_bytes_in) {
       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
       if (it != sizes_and_counts.end()) {
-        it->second.bytes += object_bytes;
+        it->second.bytes += object_bytes_in;
         it->second.count += 1;
       } else {
-        sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes, 1));
+        sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1));
       }
     }
 
@@ -1969,45 +1933,6 @@
   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
 };
 
-static NoopCompilerCallbacks callbacks;
-
-static Runtime* StartRuntime(const char* boot_image_location, const char* image_location,
-                             InstructionSet instruction_set) {
-  RuntimeOptions options;
-  std::string image_option;
-  std::string oat_option;
-  std::string boot_image_option;
-  std::string boot_oat_option;
-
-  // We are more like a compiler than a run-time. We don't want to execute code.
-  options.push_back(std::make_pair("compilercallbacks", &callbacks));
-
-  if (boot_image_location != nullptr) {
-    boot_image_option += "-Ximage:";
-    boot_image_option += boot_image_location;
-    options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
-  }
-  if (image_location != nullptr) {
-    image_option += "-Ximage:";
-    image_option += image_location;
-    options.push_back(std::make_pair(image_option.c_str(), nullptr));
-  }
-  options.push_back(
-      std::make_pair("imageinstructionset",
-                     reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
-
-  if (!Runtime::Create(options, false)) {
-    fprintf(stderr, "Failed to create runtime\n");
-    return nullptr;
-  }
-
-  // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
-  // give it away now and then switch to a more manageable ScopedObjectAccess.
-  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
-
-  return Runtime::Current();
-}
-
 static int DumpImage(Runtime* runtime, const char* image_location, OatDumperOptions* options,
                      std::ostream* os) {
   // Dumping the image, no explicit class loader.
@@ -2023,7 +1948,9 @@
     fprintf(stderr, "Invalid image header %s\n", image_location);
     return EXIT_FAILURE;
   }
+
   ImageDumper image_dumper(os, *image_space, image_header, options);
+
   bool success = image_dumper.Dump();
   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
@@ -2041,13 +1968,13 @@
   ScopedObjectAccess soa(self);
   ClassLinker* class_linker = runtime->GetClassLinker();
   class_linker->RegisterOatFile(oat_file);
-  std::vector<const DexFile*> dex_files;
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
   for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
     std::string error_msg;
-    const DexFile* dex_file = odf->OpenDexFile(&error_msg);
+    std::unique_ptr<const DexFile> dex_file = odf->OpenDexFile(&error_msg);
     CHECK(dex_file != nullptr) << error_msg;
     class_linker->RegisterDexFile(*dex_file);
-    dex_files.push_back(dex_file);
+    dex_files.push_back(std::move(dex_file));
   }
 
   // Need a class loader.
@@ -2056,7 +1983,11 @@
       soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
   jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
   // Fake that we're a compiler.
-  runtime->SetCompileTimeClassPath(class_loader, dex_files);
+  std::vector<const DexFile*> class_path;
+  for (auto& dex_file : dex_files) {
+    class_path.push_back(dex_file.get());
+  }
+  runtime->SetCompileTimeClassPath(class_loader, class_path);
 
   // Use the class loader while dumping.
   StackHandleScope<1> scope(self);
@@ -2082,7 +2013,8 @@
 static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
                    std::ostream* os) {
   std::string error_msg;
-  OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, false, &error_msg);
+  OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
+                                    &error_msg);
   if (oat_file == nullptr) {
     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
     return EXIT_FAILURE;
@@ -2097,7 +2029,8 @@
 
 static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
   std::string error_msg;
-  OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, false, &error_msg);
+  OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
+                                    &error_msg);
   if (oat_file == nullptr) {
     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
     return EXIT_FAILURE;
@@ -2116,83 +2049,110 @@
   return EXIT_SUCCESS;
 }
 
-struct OatdumpArgs {
-  bool Parse(int argc, char** argv) {
-    // Skip over argv[0].
-    argv++;
-    argc--;
+struct OatdumpArgs : public CmdlineArgs {
+ protected:
+  using Base = CmdlineArgs;
 
-    if (argc == 0) {
-      fprintf(stderr, "No arguments specified\n");
-      usage();
-      return false;
-    }
-
-    for (int i = 0; i < argc; i++) {
-      const StringPiece option(argv[i]);
-      if (option.starts_with("--oat-file=")) {
-        oat_filename_ = option.substr(strlen("--oat-file=")).data();
-      } else if (option.starts_with("--image=")) {
-        image_location_ = option.substr(strlen("--image=")).data();
-      } else if (option.starts_with("--boot-image=")) {
-        boot_image_location_ = option.substr(strlen("--boot-image=")).data();
-      } else if (option.starts_with("--instruction-set=")) {
-        StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
-        instruction_set_ = GetInstructionSetFromString(instruction_set_str.data());
-        if (instruction_set_ == kNone) {
-          fprintf(stderr, "Unsupported instruction set %s\n", instruction_set_str.data());
-          usage();
-          return false;
-        }
-      } else if (option =="--dump:raw_mapping_table") {
-        dump_raw_mapping_table_ = true;
-      } else if (option == "--dump:raw_gc_map") {
-        dump_raw_gc_map_ = true;
-      } else if (option == "--no-dump:vmap") {
-        dump_vmap_ = false;
-      } else if (option == "--no-disassemble") {
-        disassemble_code_ = false;
-      } else if (option.starts_with("--output=")) {
-        output_name_ = option.substr(strlen("--output=")).ToString();
-        const char* filename = output_name_.c_str();
-        out_.reset(new std::ofstream(filename));
-        if (!out_->good()) {
-          fprintf(stderr, "Failed to open output filename %s\n", filename);
-          usage();
-          return false;
-        }
-        os_ = out_.get();
-      } else if (option.starts_with("--symbolize=")) {
-        oat_filename_ = option.substr(strlen("--symbolize=")).data();
-        symbolize_ = true;
-      } else {
-        fprintf(stderr, "Unknown argument %s\n", option.data());
-        usage();
-        return false;
+  virtual ParseStatus ParseCustom(const StringPiece& option,
+                                  std::string* error_msg) OVERRIDE {
+    {
+      ParseStatus base_parse = Base::ParseCustom(option, error_msg);
+      if (base_parse != kParseUnknownArgument) {
+        return base_parse;
       }
     }
 
-    if (image_location_ == nullptr && oat_filename_ == nullptr) {
-      fprintf(stderr, "Either --image or --oat must be specified\n");
-      return false;
+    if (option.starts_with("--oat-file=")) {
+      oat_filename_ = option.substr(strlen("--oat-file=")).data();
+    } else if (option.starts_with("--image=")) {
+      image_location_ = option.substr(strlen("--image=")).data();
+    } else if (option =="--dump:raw_mapping_table") {
+      dump_raw_mapping_table_ = true;
+    } else if (option == "--dump:raw_gc_map") {
+      dump_raw_gc_map_ = true;
+    } else if (option == "--no-dump:vmap") {
+      dump_vmap_ = false;
+    } else if (option == "--no-disassemble") {
+      disassemble_code_ = false;
+    } else if (option.starts_with("--symbolize=")) {
+      oat_filename_ = option.substr(strlen("--symbolize=")).data();
+      symbolize_ = true;
+    } else if (option.starts_with("--method-filter=")) {
+      method_filter_ = option.substr(strlen("--method-filter=")).data();
+    } else {
+      return kParseUnknownArgument;
     }
 
-    if (image_location_ != nullptr && oat_filename_ != nullptr) {
-      fprintf(stderr, "Either --image or --oat must be specified but not both\n");
-      return false;
-    }
-
-    return true;
+    return kParseOk;
   }
 
+  virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
+    // Infer boot image location from the image location if possible.
+    if (boot_image_location_ == nullptr) {
+      boot_image_location_ = image_location_;
+    }
+
+    // Perform the parent checks.
+    ParseStatus parent_checks = Base::ParseChecks(error_msg);
+    if (parent_checks != kParseOk) {
+      return parent_checks;
+    }
+
+    // Perform our own checks.
+    if (image_location_ == nullptr && oat_filename_ == nullptr) {
+      *error_msg = "Either --image or --oat-file must be specified";
+      return kParseError;
+    } else if (image_location_ != nullptr && oat_filename_ != nullptr) {
+      *error_msg = "Either --image or --oat-file must be specified but not both";
+      return kParseError;
+    }
+
+    return kParseOk;
+  }
+
+  virtual std::string GetUsage() const {
+    std::string usage;
+
+    usage +=
+        "Usage: oatdump [options] ...\n"
+        "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
+        "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
+        "\n"
+        // Either oat-file or image is required.
+        "  --oat-file=<file.oat>: specifies an input oat filename.\n"
+        "      Example: --oat-file=/system/framework/boot.oat\n"
+        "\n"
+        "  --image=<file.art>: specifies an input image location.\n"
+        "      Example: --image=/system/framework/boot.art\n"
+        "\n";
+
+    usage += Base::GetUsage();
+
+    usage +=  // Optional.
+        "  --dump:raw_mapping_table enables dumping of the mapping table.\n"
+        "      Example: --dump:raw_mapping_table\n"
+        "\n"
+        "  --dump:raw_mapping_table enables dumping of the GC map.\n"
+        "      Example: --dump:raw_gc_map\n"
+        "\n"
+        "  --no-dump:vmap may be used to disable vmap dumping.\n"
+        "      Example: --no-dump:vmap\n"
+        "\n"
+        "  --no-disassemble may be used to disable disassembly.\n"
+        "      Example: --no-disassemble\n"
+        "\n"
+        "  --method-filter=<method name>: only dumps methods that contain the filter.\n"
+        "      Example: --method-filter=foo\n"
+        "\n";
+
+    return usage;
+  }
+
+ public:
   const char* oat_filename_ = nullptr;
+  const char* method_filter_ = "";
   const char* image_location_ = nullptr;
-  const char* boot_image_location_ = nullptr;
-  InstructionSet instruction_set_ = kRuntimeISA;
   std::string elf_filename_prefix_;
-  std::ostream* os_ = &std::cout;
-  std::unique_ptr<std::ofstream> out_;
-  std::string output_name_;
   bool dump_raw_mapping_table_ = false;
   bool dump_raw_gc_map_ = false;
   bool dump_vmap_ = true;
@@ -2200,52 +2160,61 @@
   bool symbolize_ = false;
 };
 
-static int oatdump(int argc, char** argv) {
-  InitLogging(argv);
+struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
+  virtual bool NeedsRuntime() OVERRIDE {
+    CHECK(args_ != nullptr);
 
-  OatdumpArgs args;
-  if (!args.Parse(argc, argv)) {
-    return EXIT_FAILURE;
+    // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
+    bool absolute_addresses = (args_->oat_filename_ == nullptr);
+
+    oat_dumper_options_ = std::unique_ptr<OatDumperOptions>(new OatDumperOptions(
+        args_->dump_raw_mapping_table_,
+        args_->dump_raw_gc_map_,
+        args_->dump_vmap_,
+        args_->disassemble_code_,
+        absolute_addresses,
+        args_->method_filter_));
+
+    return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) &&
+          !args_->symbolize_;
   }
 
-  // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
-  bool absolute_addresses = (args.oat_filename_ == nullptr);
+  virtual bool ExecuteWithoutRuntime() OVERRIDE {
+    CHECK(args_ != nullptr);
+    CHECK(args_->oat_filename_ != nullptr);
 
-  std::unique_ptr<OatDumperOptions> oat_dumper_options(new OatDumperOptions(
-      args.dump_raw_mapping_table_,
-      args.dump_raw_gc_map_,
-      args.dump_vmap_,
-      args.disassemble_code_,
-      absolute_addresses,
-      nullptr));
+    MemMap::Init();
 
-  std::unique_ptr<Runtime> runtime;
-  if ((args.boot_image_location_ != nullptr || args.image_location_ != nullptr) &&
-      !args.symbolize_) {
-    // If we have a boot image option, try to start the runtime; except when just symbolizing.
-    runtime.reset(StartRuntime(args.boot_image_location_,
-                               args.image_location_,
-                               args.instruction_set_));
-  }
-
-  if (args.oat_filename_ != nullptr) {
-    if (args.symbolize_) {
-      return SymbolizeOat(args.oat_filename_, args.output_name_);
+    if (args_->symbolize_) {
+      return SymbolizeOat(args_->oat_filename_, args_->output_name_) == EXIT_SUCCESS;
     } else {
-      return DumpOat(runtime.get(), args.oat_filename_, oat_dumper_options.release(), args.os_);
+      return DumpOat(nullptr,
+                     args_->oat_filename_,
+                     oat_dumper_options_.release(),
+                     args_->os_) == EXIT_SUCCESS;
     }
   }
 
-  if (runtime.get() == nullptr) {
-    // We need the runtime when printing an image.
-    return EXIT_FAILURE;
+  virtual bool ExecuteWithRuntime(Runtime* runtime) {
+    CHECK(args_ != nullptr);
+
+    if (args_->oat_filename_ != nullptr) {
+      return DumpOat(runtime,
+                     args_->oat_filename_,
+                     oat_dumper_options_.release(),
+                     args_->os_) == EXIT_SUCCESS;
+    }
+
+    return DumpImage(runtime, args_->image_location_, oat_dumper_options_.release(), args_->os_)
+      == EXIT_SUCCESS;
   }
 
-  return DumpImage(runtime.get(), args.image_location_, oat_dumper_options.release(), args.os_);
-}
+  std::unique_ptr<OatDumperOptions> oat_dumper_options_;
+};
 
 }  // namespace art
 
 int main(int argc, char** argv) {
-  return art::oatdump(argc, argv);
+  art::OatdumpMain main;
+  return main.Main(argc, argv);
 }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 50b4ece..6c86c7b 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -24,19 +24,18 @@
 #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"
 #include "gc/space/image_space.h"
 #include "image.h"
-#include "instruction_set.h"
-#include "mirror/art_field.h"
 #include "mirror/art_field-inl.h"
-#include "mirror/art_method.h"
 #include "mirror/art_method-inl.h"
-#include "mirror/object.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference.h"
 #include "noop_compiler_callbacks.h"
@@ -49,7 +48,7 @@
 
 namespace art {
 
-static InstructionSet ElfISAToInstructionSet(Elf32_Word isa) {
+static InstructionSet ElfISAToInstructionSet(Elf32_Word isa, Elf32_Word e_flags) {
   switch (isa) {
     case EM_ARM:
       return kArm;
@@ -60,7 +59,14 @@
     case EM_X86_64:
       return kX86_64;
     case EM_MIPS:
-      return kMips;
+      if (((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2) ||
+          ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6)) {
+        return kMips;
+      } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
+        return kMips64;
+      } else {
+        return kNone;
+      }
     default:
       return kNone;
   }
@@ -71,7 +77,7 @@
   bool has_system = false;
   bool has_cache = false;
   // image_location = /system/framework/boot.art
-  // system_image_location = /system/framework/<image_isa>/boot.art
+  // system_image_filename = /system/framework/<image_isa>/boot.art
   std::string system_filename(GetSystemImageFilename(location.c_str(), isa));
   if (OS::FileExists(system_filename.c_str())) {
     has_system = true;
@@ -130,6 +136,7 @@
                << " for location " << image_location;
     return false;
   }
+
   int64_t image_len = input_image->GetLength();
   if (image_len < 0) {
     LOG(ERROR) << "Error while getting image length";
@@ -142,6 +149,10 @@
     return false;
   }
 
+  /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath());
+  // Nothing special to do right now since the image always needs to get patched.
+  // Perhaps in some far-off future we may have images with relative addresses that are true-PIC.
+
   // Set up the runtime
   RuntimeOptions options;
   NoopCompilerCallbacks callbacks;
@@ -171,7 +182,7 @@
   }
   gc::space::ImageSpace* ispc = Runtime::Current()->GetHeap()->GetImageSpace();
 
-  PatchOat p(image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(),
+  PatchOat p(isa, image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(),
              delta, timings);
   t.NewTiming("Patching files");
   if (!p.PatchImage()) {
@@ -186,9 +197,11 @@
   return true;
 }
 
-bool PatchOat::Patch(const File* input_oat, const std::string& image_location, off_t delta,
+bool PatchOat::Patch(File* input_oat, const std::string& image_location, off_t delta,
                      File* output_oat, File* output_image, InstructionSet isa,
-                     TimingLogger* timings) {
+                     TimingLogger* timings,
+                     bool output_oat_opened_from_fd,
+                     bool new_oat_out) {
   CHECK(Runtime::Current() == nullptr);
   CHECK(output_image != nullptr);
   CHECK_GE(output_image->Fd(), 0);
@@ -206,7 +219,7 @@
       LOG(ERROR) << "unable to read elf header";
       return false;
     }
-    isa = ElfISAToInstructionSet(elf_hdr.e_machine);
+    isa = ElfISAToInstructionSet(elf_hdr.e_machine, elf_hdr.e_flags);
   }
   const char* isa_name = GetInstructionSetString(isa);
   std::string image_filename;
@@ -231,6 +244,10 @@
     LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath();
   }
 
+  /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath());
+  // Nothing special to do right now since the image always needs to get patched.
+  // Perhaps in some far-off future we may have images with relative addresses that are true-PIC.
+
   // Set up the runtime
   RuntimeOptions options;
   NoopCompilerCallbacks callbacks;
@@ -260,17 +277,37 @@
   }
   gc::space::ImageSpace* ispc = Runtime::Current()->GetHeap()->GetImageSpace();
 
-  std::unique_ptr<ElfFile> elf(ElfFile::Open(const_cast<File*>(input_oat),
+  std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat,
                                              PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg));
   if (elf.get() == nullptr) {
     LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
     return false;
   }
 
-  PatchOat p(elf.release(), image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(),
+  bool skip_patching_oat = false;
+  MaybePic is_oat_pic = IsOatPic(elf.get());
+  if (is_oat_pic >= ERROR_FIRST) {
+    // Error logged by IsOatPic
+    return false;
+  } else if (is_oat_pic == PIC) {
+    // Do not need to do ELF-file patching. Create a symlink and skip the ELF patching.
+    if (!ReplaceOatFileWithSymlink(input_oat->GetPath(),
+                                   output_oat->GetPath(),
+                                   output_oat_opened_from_fd,
+                                   new_oat_out)) {
+      // Errors already logged by above call.
+      return false;
+    }
+    // Don't patch the OAT, since we just symlinked it. Image still needs patching.
+    skip_patching_oat = true;
+  } else {
+    CHECK(is_oat_pic == NOT_PIC);
+  }
+
+  PatchOat p(isa, elf.release(), image.release(), ispc->GetLiveBitmap(), ispc->GetMemMap(),
              delta, timings);
   t.NewTiming("Patching files");
-  if (!p.PatchElf()) {
+  if (!skip_patching_oat && !p.PatchElf()) {
     LOG(ERROR) << "Failed to patch oat file " << input_oat->GetPath();
     return false;
   }
@@ -280,10 +317,12 @@
   }
 
   t.NewTiming("Writing files");
-  if (!p.WriteElf(output_oat)) {
+  if (!skip_patching_oat && !p.WriteElf(output_oat)) {
+    LOG(ERROR) << "Failed to write oat file " << input_oat->GetPath();
     return false;
   }
   if (!p.WriteImage(output_image)) {
+    LOG(ERROR) << "Failed to write image file " << input_image->GetPath();
     return false;
   }
   return true;
@@ -323,6 +362,83 @@
   }
 }
 
+bool PatchOat::IsImagePic(const ImageHeader& image_header, const std::string& image_path) {
+  if (!image_header.CompilePic()) {
+    if (kIsDebugBuild) {
+      LOG(INFO) << "image at location " << image_path << " was *not* compiled pic";
+    }
+    return false;
+  }
+
+  if (kIsDebugBuild) {
+    LOG(INFO) << "image at location " << image_path << " was compiled PIC";
+  }
+
+  return true;
+}
+
+PatchOat::MaybePic PatchOat::IsOatPic(const ElfFile* oat_in) {
+  if (oat_in == nullptr) {
+    LOG(ERROR) << "No ELF input oat fie available";
+    return ERROR_OAT_FILE;
+  }
+
+  const std::string& file_path = oat_in->GetFile().GetPath();
+
+  const OatHeader* oat_header = GetOatHeader(oat_in);
+  if (oat_header == nullptr) {
+    LOG(ERROR) << "Failed to find oat header in oat file " << file_path;
+    return ERROR_OAT_FILE;
+  }
+
+  if (!oat_header->IsValid()) {
+    LOG(ERROR) << "Elf file " << file_path << " has an invalid oat header";
+    return ERROR_OAT_FILE;
+  }
+
+  bool is_pic = oat_header->IsPic();
+  if (kIsDebugBuild) {
+    LOG(INFO) << "Oat file at " << file_path << " is " << (is_pic ? "PIC" : "not pic");
+  }
+
+  return is_pic ? PIC : NOT_PIC;
+}
+
+bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
+                                         const std::string& output_oat_filename,
+                                         bool output_oat_opened_from_fd,
+                                         bool new_oat_out) {
+  // Need a file when we are PIC, since we symlink over it. Refusing to symlink into FD.
+  if (output_oat_opened_from_fd) {
+    // TODO: installd uses --output-oat-fd. Should we change class linking logic for PIC?
+    LOG(ERROR) << "No output oat filename specified, needs filename for when we are PIC";
+    return false;
+  }
+
+  // Image was PIC. Create symlink where the oat is supposed to go.
+  if (!new_oat_out) {
+    LOG(ERROR) << "Oat file " << output_oat_filename << " already exists, refusing to overwrite";
+    return false;
+  }
+
+  // Delete the original file, since we won't need it.
+  TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
+
+  // Create a symlink from the old oat to the new oat
+  if (symlink(input_oat_filename.c_str(), output_oat_filename.c_str()) < 0) {
+    int err = errno;
+    LOG(ERROR) << "Failed to create symlink at " << output_oat_filename
+               << " error(" << err << "): " << strerror(err);
+    return false;
+  }
+
+  if (kIsDebugBuild) {
+    LOG(INFO) << "Created symlink " << output_oat_filename << " -> " << input_oat_filename;
+  }
+
+  return true;
+}
+
 bool PatchOat::PatchImage() {
   ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
   CHECK_GT(image_->Size(), sizeof(ImageHeader));
@@ -353,14 +469,15 @@
 }
 
 void PatchOat::PatchVisitor::operator() (mirror::Object* obj, MemberOffset off,
-                                         bool is_static_unused) const {
+                                         bool is_static_unused ATTRIBUTE_UNUSED) const {
   mirror::Object* referent = obj->GetFieldObject<mirror::Object, kVerifyNone>(off);
   DCHECK(patcher_->InHeap(referent)) << "Referent is not in the heap.";
   mirror::Object* moved_object = patcher_->RelocatedAddressOf(referent);
   copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object);
 }
 
-void PatchOat::PatchVisitor::operator() (mirror::Class* cls, mirror::Reference* ref) const {
+void PatchOat::PatchVisitor::operator() (mirror::Class* cls ATTRIBUTE_UNUSED,
+                                         mirror::Reference* ref) const {
   MemberOffset off = mirror::Reference::ReferentOffset();
   mirror::Object* referent = ref->GetReferent();
   DCHECK(patcher_->InHeap(referent)) << "Referent is not in the heap.";
@@ -384,10 +501,29 @@
   if (obj == nullptr) {
     return nullptr;
   } else {
-    return reinterpret_cast<mirror::Object*>(reinterpret_cast<byte*>(obj) + delta_);
+    return reinterpret_cast<mirror::Object*>(reinterpret_cast<uint8_t*>(obj) + delta_);
   }
 }
 
+const OatHeader* PatchOat::GetOatHeader(const ElfFile* elf_file) {
+  if (elf_file->Is64Bit()) {
+    return GetOatHeader<ElfFileImpl64>(elf_file->GetImpl64());
+  } else {
+    return GetOatHeader<ElfFileImpl32>(elf_file->GetImpl32());
+  }
+}
+
+template <typename ElfFileImpl>
+const OatHeader* PatchOat::GetOatHeader(const ElfFileImpl* elf_file) {
+  auto rodata_sec = elf_file->FindSectionByName(".rodata");
+  if (rodata_sec == nullptr) {
+    return nullptr;
+  }
+
+  OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + rodata_sec->sh_offset);
+  return oat_header;
+}
+
 // Called by BitmapCallback
 void PatchOat::VisitObject(mirror::Object* object) {
   mirror::Object* copy = RelocatedCopyOf(object);
@@ -403,43 +539,37 @@
   PatchOat::PatchVisitor visitor(this, copy);
   object->VisitReferences<true, kVerifyNone>(visitor, visitor);
   if (object->IsArtMethod<kVerifyNone>()) {
-    FixupMethod(static_cast<mirror::ArtMethod*>(object),
-                static_cast<mirror::ArtMethod*>(copy));
+    FixupMethod(down_cast<mirror::ArtMethod*>(object), down_cast<mirror::ArtMethod*>(copy));
   }
 }
 
 void PatchOat::FixupMethod(mirror::ArtMethod* object, mirror::ArtMethod* copy) {
+  const size_t pointer_size = InstructionSetPointerSize(isa_);
   // Just update the entry points if it looks like we should.
   // TODO: sanity check all the pointers' values
-  uintptr_t portable = reinterpret_cast<uintptr_t>(
-      object->GetEntryPointFromPortableCompiledCode<kVerifyNone>());
-  if (portable != 0) {
-    copy->SetEntryPointFromPortableCompiledCode(reinterpret_cast<void*>(portable + delta_));
-  }
   uintptr_t quick= reinterpret_cast<uintptr_t>(
-      object->GetEntryPointFromQuickCompiledCode<kVerifyNone>());
+      object->GetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(pointer_size));
   if (quick != 0) {
-    copy->SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>(quick + delta_));
+    copy->SetEntryPointFromQuickCompiledCodePtrSize(reinterpret_cast<void*>(quick + delta_),
+                                                    pointer_size);
   }
   uintptr_t interpreter = reinterpret_cast<uintptr_t>(
-      object->GetEntryPointFromInterpreter<kVerifyNone>());
+      object->GetEntryPointFromInterpreterPtrSize<kVerifyNone>(pointer_size));
   if (interpreter != 0) {
-    copy->SetEntryPointFromInterpreter(
-        reinterpret_cast<mirror::EntryPointFromInterpreter*>(interpreter + delta_));
+    copy->SetEntryPointFromInterpreterPtrSize(
+        reinterpret_cast<mirror::EntryPointFromInterpreter*>(interpreter + delta_), pointer_size);
   }
 
-  uintptr_t native_method = reinterpret_cast<uintptr_t>(object->GetNativeMethod());
+  uintptr_t native_method = reinterpret_cast<uintptr_t>(
+      object->GetEntryPointFromJniPtrSize(pointer_size));
   if (native_method != 0) {
-    copy->SetNativeMethod(reinterpret_cast<void*>(native_method + delta_));
-  }
-
-  uintptr_t native_gc_map = reinterpret_cast<uintptr_t>(object->GetNativeGcMap());
-  if (native_gc_map != 0) {
-    copy->SetNativeGcMap(reinterpret_cast<uint8_t*>(native_gc_map + delta_));
+    copy->SetEntryPointFromJniPtrSize(reinterpret_cast<void*>(native_method + delta_),
+                                      pointer_size);
   }
 }
 
-bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings) {
+bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings,
+                     bool output_oat_opened_from_fd, bool new_oat_out) {
   CHECK(input_oat != nullptr);
   CHECK(output_oat != nullptr);
   CHECK_GE(input_oat->Fd(), 0);
@@ -447,13 +577,28 @@
   TimingLogger::ScopedTiming t("Setup Oat File Patching", timings);
 
   std::string error_msg;
-  std::unique_ptr<ElfFile> elf(ElfFile::Open(const_cast<File*>(input_oat),
+  std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat,
                                              PROT_READ | PROT_WRITE, MAP_PRIVATE, &error_msg));
   if (elf.get() == nullptr) {
     LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
     return false;
   }
 
+  MaybePic is_oat_pic = IsOatPic(elf.get());
+  if (is_oat_pic >= ERROR_FIRST) {
+    // Error logged by IsOatPic
+    return false;
+  } else if (is_oat_pic == PIC) {
+    // Do not need to do ELF-file patching. Create a symlink and skip the rest.
+    // Any errors will be logged by the function call.
+    return ReplaceOatFileWithSymlink(input_oat->GetPath(),
+                                     output_oat->GetPath(),
+                                     output_oat_opened_from_fd,
+                                     new_oat_out);
+  } else {
+    CHECK(is_oat_pic == NOT_PIC);
+  }
+
   PatchOat p(elf.release(), delta, timings);
   t.NewTiming("Patch Oat file");
   if (!p.PatchElf()) {
@@ -467,15 +612,16 @@
   return true;
 }
 
-template <typename ptr_t>
-bool PatchOat::CheckOatFile(const Elf32_Shdr& patches_sec) {
-  if (patches_sec.sh_type != SHT_OAT_PATCH) {
+template <typename ElfFileImpl, typename ptr_t>
+bool PatchOat::CheckOatFile(ElfFileImpl* oat_file) {
+  auto patches_sec = oat_file->FindSectionByName(".oat_patches");
+  if (patches_sec->sh_type != SHT_OAT_PATCH) {
     return false;
   }
-  ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset);
-  ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t));
-  Elf32_Shdr* oat_data_sec = oat_file_->FindSectionByName(".rodata");
-  Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text");
+  ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file->Begin() + patches_sec->sh_offset);
+  ptr_t* patches_end = patches + (patches_sec->sh_size / sizeof(ptr_t));
+  auto oat_data_sec = oat_file->FindSectionByName(".rodata");
+  auto oat_text_sec = oat_file->FindSectionByName(".text");
   if (oat_data_sec == nullptr) {
     return false;
   }
@@ -495,14 +641,15 @@
   return true;
 }
 
-bool PatchOat::PatchOatHeader() {
-  Elf32_Shdr *rodata_sec = oat_file_->FindSectionByName(".rodata");
+template <typename ElfFileImpl>
+bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) {
+  auto rodata_sec = oat_file->FindSectionByName(".rodata");
   if (rodata_sec == nullptr) {
     return false;
   }
-  OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file_->Begin() + rodata_sec->sh_offset);
+  OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset);
   if (!oat_header->IsValid()) {
-    LOG(ERROR) << "Elf file " << oat_file_->GetFile().GetPath() << " has an invalid oat header";
+    LOG(ERROR) << "Elf file " << oat_file->GetFile().GetPath() << " has an invalid oat header";
     return false;
   }
   oat_header->RelocateOat(delta_);
@@ -510,28 +657,30 @@
 }
 
 bool PatchOat::PatchElf() {
+  if (oat_file_->Is64Bit())
+    return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64());
+  else
+    return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32());
+}
+
+template <typename ElfFileImpl>
+bool PatchOat::PatchElf(ElfFileImpl* oat_file) {
   TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_);
-  if (!PatchTextSection()) {
+  if (!PatchTextSection<ElfFileImpl>(oat_file)) {
     return false;
   }
 
-  if (!PatchOatHeader()) {
+  if (!PatchOatHeader<ElfFileImpl>(oat_file)) {
     return false;
   }
 
   bool need_fixup = false;
-  t.NewTiming("Fixup Elf Headers");
-  // Fixup Phdr's
-  for (unsigned int i = 0; i < oat_file_->GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* hdr = oat_file_->GetProgramHeader(i);
-    CHECK(hdr != nullptr);
-    if (hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) {
+  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) ||
+        (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset)) {
       need_fixup = true;
-      hdr->p_vaddr += delta_;
-    }
-    if (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset) {
-      need_fixup = true;
-      hdr->p_paddr += delta_;
+      break;
     }
   }
   if (!need_fixup) {
@@ -539,67 +688,39 @@
     // their addr. Therefore we do not need to update these parts.
     return true;
   }
+
+  t.NewTiming("Fixup Elf Headers");
+  // Fixup Phdr's
+  oat_file->FixupProgramHeaders(delta_);
+
   t.NewTiming("Fixup Section Headers");
-  for (unsigned int i = 0; i < oat_file_->GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* hdr = oat_file_->GetSectionHeader(i);
-    CHECK(hdr != nullptr);
-    if (hdr->sh_addr != 0) {
-      hdr->sh_addr += delta_;
-    }
-  }
+  // Fixup Shdr's
+  oat_file->FixupSectionHeaders(delta_);
 
   t.NewTiming("Fixup Dynamics");
-  for (Elf32_Word i = 0; i < oat_file_->GetDynamicNum(); i++) {
-    Elf32_Dyn& dyn = oat_file_->GetDynamic(i);
-    if (IsDynamicSectionPointer(dyn.d_tag, oat_file_->GetHeader().e_machine)) {
-      dyn.d_un.d_ptr += delta_;
-    }
-  }
+  oat_file->FixupDynamic(delta_);
 
   t.NewTiming("Fixup Elf Symbols");
   // Fixup dynsym
-  Elf32_Shdr* dynsym_sec = oat_file_->FindSectionByName(".dynsym");
-  CHECK(dynsym_sec != nullptr);
-  if (!PatchSymbols(dynsym_sec)) {
+  if (!oat_file->FixupSymbols(delta_, true)) {
     return false;
   }
-
   // Fixup symtab
-  Elf32_Shdr* symtab_sec = oat_file_->FindSectionByName(".symtab");
-  if (symtab_sec != nullptr) {
-    if (!PatchSymbols(symtab_sec)) {
-      return false;
-    }
+  if (!oat_file->FixupSymbols(delta_, false)) {
+    return false;
   }
 
   t.NewTiming("Fixup Debug Sections");
-  if (!oat_file_->FixupDebugSections(delta_)) {
+  if (!oat_file->FixupDebugSections(delta_)) {
     return false;
   }
 
   return true;
 }
 
-bool PatchOat::PatchSymbols(Elf32_Shdr* section) {
-  Elf32_Sym* syms = reinterpret_cast<Elf32_Sym*>(oat_file_->Begin() + section->sh_offset);
-  const Elf32_Sym* last_sym =
-      reinterpret_cast<Elf32_Sym*>(oat_file_->Begin() + section->sh_offset + section->sh_size);
-  CHECK_EQ(section->sh_size % sizeof(Elf32_Sym), 0u)
-      << "Symtab section size is not multiple of symbol size";
-  for (; syms < last_sym; syms++) {
-    uint8_t sttype = ELF32_ST_TYPE(syms->st_info);
-    Elf32_Word shndx = syms->st_shndx;
-    if (shndx != SHN_ABS && shndx != SHN_COMMON && shndx != SHN_UNDEF &&
-        (sttype == STT_FUNC || sttype == STT_OBJECT)) {
-      CHECK_NE(syms->st_value, 0u);
-      syms->st_value += delta_;
-    }
-  }
-  return true;
-}
-
-bool PatchOat::PatchTextSection() {
-  Elf32_Shdr* patches_sec = oat_file_->FindSectionByName(".oat_patches");
+template <typename ElfFileImpl>
+bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) {
+  auto patches_sec = oat_file->FindSectionByName(".oat_patches");
   if (patches_sec == nullptr) {
     LOG(ERROR) << ".oat_patches section not found. Aborting patch";
     return false;
@@ -611,9 +732,9 @@
 
   switch (patches_sec->sh_entsize) {
     case sizeof(uint32_t):
-      return PatchTextSection<uint32_t>(*patches_sec);
+      return PatchTextSection<ElfFileImpl, uint32_t>(oat_file);
     case sizeof(uint64_t):
-      return PatchTextSection<uint64_t>(*patches_sec);
+      return PatchTextSection<ElfFileImpl, uint64_t>(oat_file);
     default:
       LOG(ERROR) << ".oat_patches Entsize of " << patches_sec->sh_entsize << "bits "
                  << "is not valid";
@@ -621,14 +742,16 @@
   }
 }
 
-template <typename ptr_t>
-bool PatchOat::PatchTextSection(const Elf32_Shdr& patches_sec) {
-  DCHECK(CheckOatFile<ptr_t>(patches_sec)) << "Oat file invalid";
-  ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset);
-  ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t));
-  Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text");
+template <typename ElfFileImpl, typename patch_loc_t>
+bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) {
+  bool oat_file_valid = CheckOatFile<ElfFileImpl, patch_loc_t>(oat_file);
+  CHECK(oat_file_valid) << "Oat file invalid";
+  auto patches_sec = oat_file->FindSectionByName(".oat_patches");
+  patch_loc_t* patches = reinterpret_cast<patch_loc_t*>(oat_file->Begin() + patches_sec->sh_offset);
+  patch_loc_t* patches_end = patches + (patches_sec->sh_size / sizeof(patch_loc_t));
+  auto oat_text_sec = oat_file->FindSectionByName(".text");
   CHECK(oat_text_sec != nullptr);
-  byte* to_patch = oat_file_->Begin() + oat_text_sec->sh_offset;
+  uint8_t* to_patch = oat_file->Begin() + oat_text_sec->sh_offset;
   uintptr_t to_patch_end = reinterpret_cast<uintptr_t>(to_patch) + oat_text_sec->sh_size;
 
   for (; patches < patches_end; patches++) {
@@ -664,7 +787,7 @@
   va_end(ap);
 }
 
-static void Usage(const char *fmt, ...) {
+[[noreturn]] static void Usage(const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   UsageErrorV(fmt, ap);
@@ -768,7 +891,7 @@
     if (f.get() != nullptr) {
       if (fchmod(f->Fd(), 0644) != 0) {
         PLOG(ERROR) << "Unable to make " << name << " world readable";
-        unlink(name);
+        TEMP_FAILURE_RETRY(unlink(name));
         return nullptr;
       }
     }
@@ -776,8 +899,23 @@
   }
 }
 
+// Either try to close the file (close=true), or erase it.
+static bool FinishFile(File* file, bool close) {
+  if (close) {
+    if (file->FlushCloseOrErase() != 0) {
+      PLOG(ERROR) << "Failed to flush and close file.";
+      return false;
+    }
+    return true;
+  } else {
+    file->Erase();
+    return false;
+  }
+}
+
 static int patchoat(int argc, char **argv) {
   InitLogging(argv);
+  MemMap::Init();
   const bool debug = kIsDebugBuild;
   orig_argc = argc;
   orig_argv = argv;
@@ -820,7 +958,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) {
@@ -1046,7 +1184,7 @@
       if (output_image_filename.empty()) {
         output_image_filename = "output-image-file";
       }
-      output_image.reset(new File(output_image_fd, output_image_filename));
+      output_image.reset(new File(output_image_fd, output_image_filename, true));
     } else {
       CHECK(!output_image_filename.empty());
       output_image.reset(CreateOrOpen(output_image_filename.c_str(), &new_image_out));
@@ -1060,12 +1198,18 @@
       if (input_oat_filename.empty()) {
         input_oat_filename = "input-oat-file";
       }
-      input_oat.reset(new File(input_oat_fd, input_oat_filename));
+      input_oat.reset(new File(input_oat_fd, input_oat_filename, false));
+      if (input_oat == nullptr) {
+        // Unlikely, but ensure exhaustive logging in non-0 exit code case
+        LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd;
+      }
     } else {
       CHECK(!input_oat_filename.empty());
       input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str()));
-      if (input_oat.get() == nullptr) {
-        LOG(ERROR) << "Could not open input oat file: " << strerror(errno);
+      if (input_oat == nullptr) {
+        int err = errno;
+        LOG(ERROR) << "Failed to open input oat file " << input_oat_filename
+                   << ": " << strerror(err) << "(" << err << ")";
       }
     }
 
@@ -1073,37 +1217,62 @@
       if (output_oat_filename.empty()) {
         output_oat_filename = "output-oat-file";
       }
-      output_oat.reset(new File(output_oat_fd, output_oat_filename));
+      output_oat.reset(new File(output_oat_fd, output_oat_filename, true));
+      if (output_oat == nullptr) {
+        // Unlikely, but ensure exhaustive logging in non-0 exit code case
+        LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd;
+      }
     } else {
       CHECK(!output_oat_filename.empty());
       output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
+      if (output_oat == nullptr) {
+        int err = errno;
+        LOG(ERROR) << "Failed to open output oat file " << output_oat_filename
+                   << ": " << strerror(err) << "(" << err << ")";
+      }
     }
   }
 
+  // TODO: get rid of this.
   auto cleanup = [&output_image_filename, &output_oat_filename,
                   &new_oat_out, &new_image_out, &timings, &dump_timings](bool success) {
     timings.EndTiming();
     if (!success) {
       if (new_oat_out) {
         CHECK(!output_oat_filename.empty());
-        unlink(output_oat_filename.c_str());
+        TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
       }
       if (new_image_out) {
         CHECK(!output_image_filename.empty());
-        unlink(output_image_filename.c_str());
+        TEMP_FAILURE_RETRY(unlink(output_image_filename.c_str()));
       }
     }
     if (dump_timings) {
       LOG(INFO) << Dumpable<TimingLogger>(timings);
     }
+
+    if (kIsDebugBuild) {
+      LOG(INFO) << "Cleaning up.. success? " << success;
+    }
   };
 
-  if ((have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) ||
-      (have_image_files && output_image.get() == nullptr)) {
+  if (have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) {
+    LOG(ERROR) << "Failed to open input/output oat files";
+    cleanup(false);
+    return EXIT_FAILURE;
+  } else if (have_image_files && output_image.get() == nullptr) {
+    LOG(ERROR) << "Failed to open output image file";
     cleanup(false);
     return EXIT_FAILURE;
   }
 
+  if (debug) {
+    LOG(INFO) << "moving offset by " << base_delta
+              << " (0x" << std::hex << base_delta << ") bytes or "
+              << std::dec << (base_delta/kPageSize) << " pages.";
+  }
+
+  // TODO: is it going to be promatic to unlink a file that was flock-ed?
   ScopedFlock output_oat_lock;
   if (lock_output) {
     std::string error_msg;
@@ -1114,24 +1283,34 @@
     }
   }
 
-  if (debug) {
-    LOG(INFO) << "moving offset by " << base_delta
-              << " (0x" << std::hex << base_delta << ") bytes or "
-              << std::dec << (base_delta/kPageSize) << " pages.";
-  }
-
   bool ret;
   if (have_image_files && have_oat_files) {
     TimingLogger::ScopedTiming pt("patch image and oat", &timings);
     ret = PatchOat::Patch(input_oat.get(), input_image_location, base_delta,
-                          output_oat.get(), output_image.get(), isa, &timings);
+                          output_oat.get(), output_image.get(), isa, &timings,
+                          output_oat_fd >= 0,  // was it opened from FD?
+                          new_oat_out);
+    // The order here doesn't matter. If the first one is successfully saved and the second one
+    // erased, ImageSpace will still detect a problem and not use the files.
+    ret = ret && FinishFile(output_image.get(), ret);
+    ret = ret && FinishFile(output_oat.get(), ret);
   } else if (have_oat_files) {
     TimingLogger::ScopedTiming pt("patch oat", &timings);
-    ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings);
-  } else {
+    ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings,
+                          output_oat_fd >= 0,  // was it opened from FD?
+                          new_oat_out);
+    ret = ret && FinishFile(output_oat.get(), ret);
+  } else if (have_image_files) {
     TimingLogger::ScopedTiming pt("patch image", &timings);
-    CHECK(have_image_files);
     ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings);
+    ret = ret && FinishFile(output_image.get(), ret);
+  } else {
+    CHECK(false);
+    ret = true;
+  }
+
+  if (kIsDebugBuild) {
+    LOG(INFO) << "Exiting with return ... " << ret;
   }
   cleanup(ret);
   return (ret) ? EXIT_SUCCESS : EXIT_FAILURE;
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 9086d58..578df3a 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -17,19 +17,20 @@
 #ifndef ART_PATCHOAT_PATCHOAT_H_
 #define ART_PATCHOAT_PATCHOAT_H_
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "instruction_set.h"
-#include "os.h"
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "gc/accounting/space_bitmap.h"
 #include "gc/heap.h"
+#include "os.h"
 #include "utils.h"
 
 namespace art {
 
 class ImageHeader;
+class OatHeader;
 
 namespace mirror {
 class Object;
@@ -40,29 +41,58 @@
 
 class PatchOat {
  public:
-  static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings);
+  // Patch only the oat file
+  static bool Patch(File* oat_in, off_t delta, File* oat_out, TimingLogger* timings,
+                    bool output_oat_opened_from_fd,  // Was this using --oatput-oat-fd ?
+                    bool new_oat_out);               // Output oat was a new file created by us?
 
+  // Patch only the image (art file)
   static bool Patch(const std::string& art_location, off_t delta, File* art_out, InstructionSet isa,
                     TimingLogger* timings);
 
-  static bool Patch(const File* oat_in, const std::string& art_location,
+  // Patch both the image and the oat file
+  static bool Patch(File* oat_in, const std::string& art_location,
                     off_t delta, File* oat_out, File* art_out, InstructionSet isa,
-                    TimingLogger* timings);
+                    TimingLogger* timings,
+                    bool output_oat_opened_from_fd,  // Was this using --oatput-oat-fd ?
+                    bool new_oat_out);               // Output oat was a new file created by us?
 
  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) {}
-  PatchOat(MemMap* image, gc::accounting::ContinuousSpaceBitmap* bitmap,
+      : oat_file_(oat_file), image_(nullptr), bitmap_(nullptr), heap_(nullptr), delta_(delta),
+        isa_(kNone), timings_(timings) {}
+  PatchOat(InstructionSet isa, MemMap* image, gc::accounting::ContinuousSpaceBitmap* bitmap,
            MemMap* heap, off_t delta, TimingLogger* timings)
       : image_(image), bitmap_(bitmap), heap_(heap),
-        delta_(delta), timings_(timings) {}
-  PatchOat(ElfFile* oat_file, MemMap* image, gc::accounting::ContinuousSpaceBitmap* bitmap,
-           MemMap* heap, off_t delta, TimingLogger* timings)
+        delta_(delta), isa_(isa), timings_(timings) {}
+  PatchOat(InstructionSet isa, ElfFile* oat_file, MemMap* image,
+           gc::accounting::ContinuousSpaceBitmap* bitmap, MemMap* heap, off_t delta,
+           TimingLogger* timings)
       : oat_file_(oat_file), image_(image), bitmap_(bitmap), heap_(heap),
-        delta_(delta), timings_(timings) {}
+        delta_(delta), isa_(isa), timings_(timings) {}
   ~PatchOat() {}
 
+  // Was the .art image at image_path made with --compile-pic ?
+  static bool IsImagePic(const ImageHeader& image_header, const std::string& image_path);
+
+  enum MaybePic {
+      NOT_PIC,            // Code not pic. Patch as usual.
+      PIC,                // Code was pic. Create symlink; skip OAT patching.
+      ERROR_OAT_FILE,     // Failed to symlink oat file
+      ERROR_FIRST = ERROR_OAT_FILE,
+  };
+
+  // Was the .oat image at oat_in made with --compile-pic ?
+  static MaybePic IsOatPic(const ElfFile* oat_in);
+
+  // Attempt to replace the file with a symlink
+  // Returns false if it fails
+  static bool ReplaceOatFileWithSymlink(const std::string& input_oat_filename,
+                                        const std::string& output_oat_filename,
+                                        bool output_oat_opened_from_fd,
+                                        bool new_oat_out);  // Output oat was newly created?
+
   static void BitmapCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     reinterpret_cast<PatchOat*>(arg)->VisitObject(obj);
@@ -76,12 +106,15 @@
 
   // Patches oat in place, modifying the oat_file given to the constructor.
   bool PatchElf();
-  bool PatchTextSection();
+  template <typename ElfFileImpl>
+  bool PatchElf(ElfFileImpl* oat_file);
+  template <typename ElfFileImpl>
+  bool PatchTextSection(ElfFileImpl* oat_file);
   // Templatized version to actually do the patching with the right sized offsets.
-  template <typename ptr_t> bool PatchTextSection(const Elf32_Shdr& patches_sec);
-  template <typename ptr_t> bool CheckOatFile(const Elf32_Shdr& patches_sec);
-  bool PatchOatHeader();
-  bool PatchSymbols(Elf32_Shdr* section);
+  template <typename ElfFileImpl, typename patch_loc_t> bool PatchTextSection(ElfFileImpl* oat_file);
+  template <typename ElfFileImpl, typename patch_loc_t> bool CheckOatFile(ElfFileImpl* oat_filec);
+  template <typename ElfFileImpl>
+  bool PatchOatHeader(ElfFileImpl* oat_file);
 
   bool PatchImage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -91,6 +124,13 @@
   mirror::Object* RelocatedCopyOf(mirror::Object*);
   mirror::Object* RelocatedAddressOf(mirror::Object* obj);
 
+  // Look up the oat header from any elf file.
+  static const OatHeader* GetOatHeader(const ElfFile* elf_file);
+
+  // Templatized version to actually look up the oat header
+  template <typename ElfFileImpl>
+  static const OatHeader* GetOatHeader(const ElfFileImpl* elf_file);
+
   // Walks through the old image and patches the mmap'd copy of it to the new offset. It does not
   // change the heap.
   class PatchVisitor {
@@ -103,20 +143,23 @@
     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_;
+  const off_t delta_;
+  // Active instruction set, used to know the entrypoint size.
+  const InstructionSet isa_;
+
   TimingLogger* timings_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(PatchOat);
diff --git a/runtime/Android.mk b/runtime/Android.mk
index e954476..d104077 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -31,10 +31,7 @@
   base/stringprintf.cc \
   base/timing_logger.cc \
   base/unix_file/fd_file.cc \
-  base/unix_file/mapped_file.cc \
-  base/unix_file/null_file.cc \
   base/unix_file/random_access_file_utils.cc \
-  base/unix_file/string_file.cc \
   check_jni.cc \
   class_linker.cc \
   common_throws.cc \
@@ -43,7 +40,6 @@
   dex_file_verifier.cc \
   dex_instruction.cc \
   elf_file.cc \
-  field_helper.cc \
   gc/allocator/dlmalloc.cc \
   gc/allocator/rosalloc.cc \
   gc/accounting/card_table.cc \
@@ -71,10 +67,10 @@
   gc/space/rosalloc_space.cc \
   gc/space/space.cc \
   gc/space/zygote_space.cc \
+  gc/task_processor.cc \
   hprof/hprof.cc \
   image.cc \
   indirect_reference_table.cc \
-  instruction_set.cc \
   instrumentation.cc \
   intern_table.cc \
   interpreter/interpreter.cc \
@@ -93,7 +89,6 @@
   jobject_comparator.cc \
   mem_map.cc \
   memory_region.cc \
-  method_helper.cc \
   mirror/art_field.cc \
   mirror/art_method.cc \
   mirror/array.cc \
@@ -166,26 +161,24 @@
 
 LIBART_COMMON_SRC_FILES += \
   arch/context.cc \
+  arch/instruction_set.cc \
+  arch/instruction_set_features.cc \
   arch/memcmp16.cc \
+  arch/arm/instruction_set_features_arm.cc \
   arch/arm/registers_arm.cc \
+  arch/arm64/instruction_set_features_arm64.cc \
   arch/arm64/registers_arm64.cc \
-  arch/x86/registers_x86.cc \
+  arch/mips/instruction_set_features_mips.cc \
   arch/mips/registers_mips.cc \
+  arch/mips64/instruction_set_features_mips64.cc \
+  arch/mips64/registers_mips64.cc \
+  arch/x86/instruction_set_features_x86.cc \
+  arch/x86/registers_x86.cc \
+  arch/x86_64/registers_x86_64.cc \
   entrypoints/entrypoint_utils.cc \
   entrypoints/interpreter/interpreter_entrypoints.cc \
   entrypoints/jni/jni_entrypoints.cc \
   entrypoints/math_entrypoints.cc \
-  entrypoints/portable/portable_alloc_entrypoints.cc \
-  entrypoints/portable/portable_cast_entrypoints.cc \
-  entrypoints/portable/portable_dexcache_entrypoints.cc \
-  entrypoints/portable/portable_field_entrypoints.cc \
-  entrypoints/portable/portable_fillarray_entrypoints.cc \
-  entrypoints/portable/portable_invoke_entrypoints.cc \
-  entrypoints/portable/portable_jni_entrypoints.cc \
-  entrypoints/portable/portable_lock_entrypoints.cc \
-  entrypoints/portable/portable_thread_entrypoints.cc \
-  entrypoints/portable/portable_throw_entrypoints.cc \
-  entrypoints/portable/portable_trampoline_entrypoints.cc \
   entrypoints/quick/quick_alloc_entrypoints.cc \
   entrypoints/quick/quick_cast_entrypoints.cc \
   entrypoints/quick/quick_deoptimization_entrypoints.cc \
@@ -209,7 +202,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 +210,11 @@
 LIBART_TARGET_SRC_FILES_arm := \
   arch/arm/context_arm.cc.arm \
   arch/arm/entrypoints_init_arm.cc \
+  arch/arm/instruction_set_features_assembly_tests.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/quick_entrypoints_cc_arm.cc \
   arch/arm/thread_arm.cc \
   arch/arm/fault_handler_arm.cc
 
@@ -231,7 +223,6 @@
   arch/arm64/entrypoints_init_arm64.cc \
   arch/arm64/jni_entrypoints_arm64.S \
   arch/arm64/memcmp16_arm64.S \
-  arch/arm64/portable_entrypoints_arm64.S \
   arch/arm64/quick_entrypoints_arm64.S \
   arch/arm64/thread_arm64.cc \
   monitor_pool.cc \
@@ -242,7 +233,6 @@
   arch/x86/entrypoints_init_x86.cc \
   arch/x86/jni_entrypoints_x86.S \
   arch/x86/memcmp16_x86.S \
-  arch/x86/portable_entrypoints_x86.S \
   arch/x86/quick_entrypoints_x86.S \
   arch/x86/thread_x86.cc \
   arch/x86/fault_handler_x86.cc
@@ -257,7 +247,6 @@
   arch/x86_64/entrypoints_init_x86_64.cc \
   arch/x86_64/jni_entrypoints_x86_64.S \
   arch/x86_64/memcmp16_x86_64.S \
-  arch/x86_64/portable_entrypoints_x86_64.S \
   arch/x86_64/quick_entrypoints_x86_64.S \
   arch/x86_64/thread_x86_64.cc \
   monitor_pool.cc \
@@ -271,18 +260,22 @@
   arch/mips/entrypoints_init_mips.cc \
   arch/mips/jni_entrypoints_mips.S \
   arch/mips/memcmp16_mips.S \
-  arch/mips/portable_entrypoints_mips.S \
   arch/mips/quick_entrypoints_mips.S \
   arch/mips/thread_mips.cc \
   arch/mips/fault_handler_mips.cc
 
-ifeq ($(TARGET_ARCH),mips64)
-$(info TODOMips64: $(LOCAL_PATH)/Android.mk Add mips64 specific runtime files)
-endif # TARGET_ARCH != mips64
+LIBART_TARGET_SRC_FILES_mips64 := \
+  arch/mips64/context_mips64.cc \
+  arch/mips64/entrypoints_init_mips64.cc \
+  arch/mips64/jni_entrypoints_mips64.S \
+  arch/mips64/memcmp16_mips64.S \
+  arch/mips64/quick_entrypoints_mips64.S \
+  arch/mips64/thread_mips64.cc \
+  monitor_pool.cc \
+  arch/mips64/fault_handler_mips64.cc
 
 LIBART_HOST_SRC_FILES := \
   $(LIBART_COMMON_SRC_FILES) \
-  base/logging_linux.cc \
   monitor_linux.cc \
   runtime_linux.cc \
   thread_linux.cc
@@ -294,17 +287,22 @@
   $(LIBART_SRC_FILES_x86_64)
 
 LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
-  arch/x86_64/registers_x86_64.h \
+  arch/instruction_set.h \
   base/allocator.h \
   base/mutex.h \
+  debugger.h \
+  base/unix_file/fd_file.h \
   dex_file.h \
   dex_instruction.h \
+  gc_root.h \
+  gc/allocator/rosalloc.h \
   gc/collector/gc_type.h \
+  gc/allocator_type.h \
   gc/collector_type.h \
   gc/space/space.h \
   gc/heap.h \
+  instrumentation.h \
   indirect_reference_table.h \
-  instruction_set.h \
   invoke_type.h \
   jdwp/jdwp.h \
   jdwp/jdwp_constants.h \
@@ -312,15 +310,15 @@
   mirror/class.h \
   oat.h \
   object_callbacks.h \
+  profiler_options.h \
   quick/inline_method_analyser.h \
+  runtime.h \
+  stack.h \
   thread.h \
   thread_state.h \
   verifier/method_verifier.h
 
-LIBART_CFLAGS :=
-ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-  LIBART_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
-endif
+LIBART_CFLAGS := -DBUILDING_LIBART=1
 
 ifeq ($(MALLOC_IMPL),dlmalloc)
   LIBART_CFLAGS += -DUSE_DLMALLOC
@@ -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 := atomic_ldrd_strd,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 := atomic_ldrd_strd,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,10 +367,19 @@
   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
-    LOCAL_FDO_SUPPORT := true
+    ifeq ($$(art_target_or_host),target)
+      LOCAL_FDO_SUPPORT := true
+    endif
   else # debug
     LOCAL_MODULE := libartd
   endif
@@ -393,6 +423,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,48 +434,48 @@
       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)
   LOCAL_C_INCLUDES += art/sigchainlib
 
-  LOCAL_SHARED_LIBRARIES += liblog libnativehelper libnativebridge
+  LOCAL_SHARED_LIBRARIES := libnativehelper libnativebridge libsigchain
   include external/libcxx/libcxx.mk
-  LOCAL_SHARED_LIBRARIES += libbacktrace_libc++
+  LOCAL_SHARED_LIBRARIES += libbacktrace
   ifeq ($$(art_target_or_host),target)
-    LOCAL_SHARED_LIBRARIES += libcutils libdl libutils libsigchain
+    LOCAL_SHARED_LIBRARIES += libdl
+    # ZipArchive support, the order matters here to get all symbols.
     LOCAL_STATIC_LIBRARIES := libziparchive libz
+    # For android::FileMap used by libziparchive.
+    LOCAL_SHARED_LIBRARIES += libutils
+    # For liblog, atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted.
+    LOCAL_SHARED_LIBRARIES += libcutils
   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)
-    ifeq ($$(art_target_or_host),target)
-      include $$(LLVM_DEVICE_BUILD_MK)
-    else # host
-      include $$(LLVM_HOST_BUILD_MK)
-    endif
+    LOCAL_SHARED_LIBRARIES += libziparchive-host
+    # For ashmem_create_region.
+    LOCAL_STATIC_LIBRARIES += libcutils
   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 :=
@@ -496,6 +532,7 @@
 LIBART_TARGET_SRC_FILES_x86 :=
 LIBART_TARGET_SRC_FILES_x86_64 :=
 LIBART_TARGET_SRC_FILES_mips :=
+LIBART_TARGET_SRC_FILES_mips64 :=
 LIBART_HOST_SRC_FILES :=
 LIBART_HOST_SRC_FILES_32 :=
 LIBART_HOST_SRC_FILES_64 :=
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index 5220dc3..ab6b00b 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -32,7 +32,7 @@
     t->TransitionFromSuspendedToRunnable();  // So we can create callee-save methods.
 
     r->SetInstructionSet(isa);
-    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(type);
+    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod();
     r->SetCalleeSaveMethod(save_method, type);
     QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo();
     EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for "
@@ -43,398 +43,115 @@
   }
 };
 
+// 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 mips64 {
+#include "arch/mips64/asm_support_mips64.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, MIPS64) {
+  CheckFrameSize(InstructionSet::kMips64, Runtime::kSaveAll, mips64::kFrameSizeSaveAllCalleeSave);
+  CheckFrameSize(InstructionSet::kMips64, Runtime::kRefsOnly, mips64::kFrameSizeRefsOnlyCalleeSave);
+  CheckFrameSize(InstructionSet::kMips64, Runtime::kRefsAndArgs,
+                 mips64::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..1fa566b 100644
--- a/runtime/arch/arm/asm_support_arm.h
+++ b/runtime/arch/arm/asm_support_arm.h
@@ -19,22 +19,11 @@
 
 #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_SAVE_ALL_CALLEE_SAVE 112
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 32
-#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 48
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 112
 
-// Expected size of a heap reference
-#define HEAP_REFERENCE_SIZE 4
 // Flag for enabling R4 optimization in arm runtime
-#define ARM_R4_SUSPEND_FLAG
+// #define ARM_R4_SUSPEND_FLAG
 
 #endif  // ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_
diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc
index 96ffc93..9e8d282 100644
--- a/runtime/arch/arm/context_arm.cc
+++ b/runtime/arch/arm/context_arm.cc
@@ -17,10 +17,8 @@
 #include "context_arm.h"
 
 #include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
 #include "quick/quick_method_frame_info.h"
-#include "stack.h"
-#include "thread.h"
+#include "utils.h"
 
 namespace art {
 namespace arm {
@@ -97,6 +95,23 @@
   gprs_[R1] = const_cast<uint32_t*>(&gZero);
   gprs_[R2] = nullptr;
   gprs_[R3] = nullptr;
+
+  fprs_[S0] = nullptr;
+  fprs_[S1] = nullptr;
+  fprs_[S2] = nullptr;
+  fprs_[S3] = nullptr;
+  fprs_[S4] = nullptr;
+  fprs_[S5] = nullptr;
+  fprs_[S6] = nullptr;
+  fprs_[S7] = nullptr;
+  fprs_[S8] = nullptr;
+  fprs_[S9] = nullptr;
+  fprs_[S10] = nullptr;
+  fprs_[S11] = nullptr;
+  fprs_[S12] = nullptr;
+  fprs_[S13] = nullptr;
+  fprs_[S14] = nullptr;
+  fprs_[S15] = nullptr;
 }
 
 extern "C" void art_quick_do_long_jump(uint32_t*, uint32_t*);
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 2780d1b..ce0e614 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -16,131 +16,39 @@
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/jni/jni_entrypoints.h"
-#include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/quick/quick_default_externs.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*);
-
 // Cast entrypoints.
 extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
                                             const mirror::Class* ref_class);
-extern "C" void art_quick_check_cast(void*, void*);
 
-// DexCache entrypoints.
-extern "C" void* art_quick_initialize_static_storage(uint32_t, void*);
-extern "C" void* art_quick_initialize_type(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, void*);
-extern "C" void* art_quick_resolve_string(void*, uint32_t);
 
-// Field entrypoints.
-extern "C" int art_quick_set8_instance(uint32_t, void*, int8_t);
-extern "C" int art_quick_set8_static(uint32_t, int8_t);
-extern "C" int art_quick_set16_instance(uint32_t, void*, int16_t);
-extern "C" int art_quick_set16_static(uint32_t, int16_t);
-extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t);
-extern "C" int art_quick_set32_static(uint32_t, int32_t);
-extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t);
-extern "C" int art_quick_set64_static(uint32_t, int64_t);
-extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*);
-extern "C" int art_quick_set_obj_static(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_instance(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_instance(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_static(uint32_t);
-extern "C" uint8_t art_quick_get_boolean_static(uint32_t);
-extern "C" int16_t art_quick_get_short_instance(uint32_t, void*);
-extern "C" uint16_t art_quick_get_char_instance(uint32_t, void*);
-extern "C" int16_t art_quick_get_short_static(uint32_t);
-extern "C" uint16_t art_quick_get_char_static(uint32_t);
-extern "C" int32_t art_quick_get32_instance(uint32_t, void*);
-extern "C" int32_t art_quick_get32_static(uint32_t);
-extern "C" int64_t art_quick_get64_instance(uint32_t, void*);
-extern "C" int64_t art_quick_get64_static(uint32_t);
-extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
-extern "C" void* art_quick_get_obj_static(uint32_t);
-
-// Array entrypoints.
-extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
-extern "C" void art_quick_handle_fill_data(void*, void*);
-
-// Lock entrypoints.
-extern "C" void art_quick_lock_object(void*);
-extern "C" void art_quick_unlock_object(void*);
-
-// Math entrypoints.
-extern int32_t CmpgDouble(double a, double b);
-extern int32_t CmplDouble(double a, double b);
-extern int32_t CmpgFloat(float a, float b);
-extern int32_t CmplFloat(float a, float b);
-
-// Math conversions.
-extern "C" int32_t __aeabi_f2iz(float op1);        // FLOAT_TO_INT
-extern "C" int32_t __aeabi_d2iz(double op1);       // DOUBLE_TO_INT
-extern "C" float __aeabi_l2f(int64_t op1);         // LONG_TO_FLOAT
-extern "C" double __aeabi_l2d(int64_t op1);        // LONG_TO_DOUBLE
-
+// Used by soft float.
 // Single-precision FP arithmetics.
-extern "C" float fmodf(float a, float b);          // REM_FLOAT[_2ADDR]
-
+extern "C" float fmodf(float a, float b);              // REM_FLOAT[_2ADDR]
 // Double-precision FP arithmetics.
-extern "C" double fmod(double a, double b);         // REM_DOUBLE[_2ADDR]
+extern "C" double fmod(double a, double b);            // REM_DOUBLE[_2ADDR]
+
+// Used by hard float.
+extern "C" float art_quick_fmodf(float a, float b);    // REM_FLOAT[_2ADDR]
+extern "C" double art_quick_fmod(double a, double b);  // REM_DOUBLE[_2ADDR]
 
 // Integer arithmetics.
 extern "C" int __aeabi_idivmod(int32_t, int32_t);  // [DIV|REM]_INT[_2ADDR|_LIT8|_LIT16]
 
 // Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR]
 extern "C" int64_t __aeabi_ldivmod(int64_t, int64_t);
-extern "C" int64_t art_quick_mul_long(int64_t, int64_t);
-extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
-
-// Intrinsic entrypoints.
-extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
-extern "C" int32_t art_quick_string_compareto(void*, void*);
-
-// Invoke entrypoints.
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-
-// Thread entrypoints.
-extern "C" void art_quick_test_suspend();
-
-// Throw entrypoints.
-extern "C" void art_quick_deliver_exception(void*);
-extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
-extern "C" void art_quick_throw_div_zero();
-extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
-extern "C" void art_quick_throw_null_pointer_exception();
-extern "C" void art_quick_throw_stack_overflow(void*);
-
-// Generic JNI downcall
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
-                     PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
+                     QuickEntryPoints* qpoints) {
   // Interpreter
   ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge;
   ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge;
@@ -148,10 +56,6 @@
   // JNI
   jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
 
-  // Portable
-  ppoints->pPortableResolutionTrampoline = art_portable_resolution_trampoline;
-  ppoints->pPortableToInterpreterBridge = art_portable_to_interpreter_bridge;
-
   // Alloc
   ResetQuickAllocEntryPoints(qpoints);
 
@@ -211,25 +115,24 @@
   qpoints->pUnlockObject = art_quick_unlock_object;
 
   // Math
-  qpoints->pCmpgDouble = CmpgDouble;
-  qpoints->pCmpgFloat = CmpgFloat;
-  qpoints->pCmplDouble = CmplDouble;
-  qpoints->pCmplFloat = CmplFloat;
-  qpoints->pFmod = fmod;
-  qpoints->pL2d = __aeabi_l2d;
-  qpoints->pFmodf = fmodf;
-  qpoints->pL2f = __aeabi_l2f;
-  qpoints->pD2iz = __aeabi_d2iz;
-  qpoints->pF2iz = __aeabi_f2iz;
   qpoints->pIdivmod = __aeabi_idivmod;
-  qpoints->pD2l = art_d2l;
-  qpoints->pF2l = art_f2l;
   qpoints->pLdiv = __aeabi_ldivmod;
   qpoints->pLmod = __aeabi_ldivmod;  // result returned in r2:r3
   qpoints->pLmul = art_quick_mul_long;
   qpoints->pShlLong = art_quick_shl_long;
   qpoints->pShrLong = art_quick_shr_long;
   qpoints->pUshrLong = art_quick_ushr_long;
+  if (kArm32QuickCodeUseSoftFloat) {
+    qpoints->pFmod = fmod;
+    qpoints->pFmodf = fmodf;
+    qpoints->pD2l = art_d2l;
+    qpoints->pF2l = art_f2l;
+  } else {
+    qpoints->pFmod = art_quick_fmod;
+    qpoints->pFmodf = art_quick_fmodf;
+    qpoints->pD2l = art_quick_d2l;
+    qpoints->pF2l = art_quick_f2l;
+  }
 
   // Intrinsics
   qpoints->pIndexOf = art_quick_indexof;
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 564fcba..325b283 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -23,7 +23,6 @@
 #include "globals.h"
 #include "base/logging.h"
 #include "base/hex_dump.h"
-#include "instruction_set.h"
 #include "mirror/art_method.h"
 #include "mirror/art_method-inl.h"
 #include "thread.h"
@@ -47,7 +46,8 @@
   return instr_size;
 }
 
-void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                      void* context) {
   // Note that in this handler we set up the registers and return to
   // longjmp directly rather than going through an assembly language stub.  The
   // reason for this is that longjmp is (currently) in ARM mode and that would
@@ -64,7 +64,7 @@
   VLOG(signals) << "longjmp address: " << reinterpret_cast<void*>(sc->arm_pc);
 }
 
-void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
   struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
@@ -100,7 +100,8 @@
   *out_return_pc = (sc->arm_pc + instr_size) | 1;
 }
 
-bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
+bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                void* context) {
   // The code that looks for the catch location needs to know the value of the
   // ARM PC at the point of call.  For Null checks we insert a GC map that is immediately after
   // the load/store instruction that might cause the fault.  However the mapping table has
@@ -127,7 +128,8 @@
 // The offset from r9 is Thread::ThreadSuspendTriggerOffset().
 // To check for a suspend check, we examine the instructions that caused
 // the fault (at PC-4 and PC).
-bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
+bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                               void* context) {
   // These are the instructions to check for.  The first one is the ldr r0,[r9,#xxx]
   // where xxx is the offset of the suspend trigger.
   uint32_t checkinst1 = 0xf8d90000 + Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
@@ -196,7 +198,8 @@
 // If we determine this is a stack overflow we need to move the stack pointer
 // to the overflow region below the protected region.
 
-bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
+bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                  void* context) {
   struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
new file mode 100644
index 0000000..f8590d3
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -0,0 +1,289 @@
+/*
+ * 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 "instruction_set_features_arm.h"
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+#include "signal.h"
+#include <fstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+#if defined(__arm__)
+extern "C" bool artCheckForArmSdivInstruction();
+#endif
+
+namespace art {
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
+    const std::string& variant, std::string* error_msg) {
+  // Assume all ARM processors are SMP.
+  // TODO: set the SMP support based on variant.
+  const bool smp = true;
+
+  // Look for variants that have divide support.
+  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"};
+
+  bool has_div = FindVariantInArray(arm_variants_with_div, arraysize(arm_variants_with_div),
+                                    variant);
+
+  // Look for variants that have LPAE support.
+  static const char* arm_variants_with_lpae[] = {
+      "cortex-a7", "cortex-a15", "krait", "denver"
+  };
+  bool has_lpae = FindVariantInArray(arm_variants_with_lpae, arraysize(arm_variants_with_lpae),
+                                     variant);
+
+  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"
+    };
+    if (FindVariantInArray(unsupported_arm_variants, arraysize(unsupported_arm_variants),
+                           variant)) {
+      *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str());
+      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[] = {
+        "default",
+        "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"
+    };
+    if (!FindVariantInArray(arm_variants_without_known_features,
+                            arraysize(arm_variants_without_known_features),
+                            variant)) {
+      LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
+          << ") using conservative defaults";
+    }
+  }
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool has_div = (bitmap & kDivBitfield) != 0;
+  bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0;
+  return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
+  const bool smp = true;
+#if defined(__ARM_ARCH_EXT_IDIV__)
+  const bool has_div = true;
+#else
+  const bool has_div = false;
+#endif
+#if defined(__ARM_FEATURE_LPAE)
+  const bool has_lpae = true;
+#else
+  const bool has_lpae = false;
+#endif
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+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 smp = false;
+  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;
+          }
+        } else if (line.find("processor") != std::string::npos &&
+            line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
+  bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
+
+  bool has_div = false;
+  bool has_lpae = 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(smp, has_div, has_lpae);
+}
+
+// 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 ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED,
+                                   void* data) {
+#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
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
+  const bool smp = true;
+
+  // 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)
+  const bool has_lpae = true;
+#else
+  const bool has_lpae = false;
+#endif
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kArm != other->GetInstructionSet()) {
+    return false;
+  }
+  const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
+  return IsSmp() == other_as_arm->IsSmp() &&
+      has_div_ == other_as_arm->has_div_ &&
+      has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_;
+}
+
+uint32_t ArmInstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) |
+      (has_div_ ? kDivBitfield : 0) |
+      (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0);
+}
+
+std::string ArmInstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (has_div_) {
+    result += ",div";
+  } else {
+    result += ",-div";
+  }
+  if (has_atomic_ldrd_strd_) {
+    result += ",atomic_ldrd_strd";
+  } else {
+    result += ",-atomic_ldrd_strd";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* ArmInstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_;
+  bool has_div = has_div_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "div") {
+      has_div = true;
+    } else if (feature == "-div") {
+      has_div = false;
+    } else if (feature == "atomic_ldrd_strd") {
+      has_atomic_ldrd_strd = true;
+    } else if (feature == "-atomic_ldrd_strd") {
+      has_atomic_ldrd_strd = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_arm.h b/runtime/arch/arm/instruction_set_features_arm.h
new file mode 100644
index 0000000..221bf1f
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.h
@@ -0,0 +1,99 @@
+/*
+ * 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_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
+#define ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// 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 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_;
+  }
+
+  // Are the ldrd and strd instructions atomic? This is commonly true when the Large Physical
+  // Address Extension (LPAE) is present.
+  bool HasAtomicLdrdAndStrd() const {
+    return has_atomic_ldrd_strd_;
+  }
+
+  virtual ~ArmInstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "div", "lpae" adding these to a new ArmInstructionSetFeatures.
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  ArmInstructionSetFeatures(bool smp, bool has_div, bool has_atomic_ldrd_strd)
+      : InstructionSetFeatures(smp),
+        has_div_(has_div), has_atomic_ldrd_strd_(has_atomic_ldrd_strd) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kDivBitfield = 2,
+    kAtomicLdrdStrdBitfield = 4,
+  };
+
+  const bool has_div_;
+  const bool has_atomic_ldrd_strd_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
diff --git a/runtime/arch/arm/instruction_set_features_arm_test.cc b/runtime/arch/arm/instruction_set_features_arm_test.cc
new file mode 100644
index 0000000..44b1640
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm_test.cc
@@ -0,0 +1,115 @@
+/*
+ * 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 "instruction_set_features_arm.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(ArmInstructionSetFeaturesTest, 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()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
+  EXPECT_EQ(krait_features->AsBitmap(), 7U);
+
+  // 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()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
+  EXPECT_EQ(denver_features->AsBitmap(), 7U);
+
+  // 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()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+
+  // 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(ArmInstructionSetFeaturesTest, ArmAddFeaturesFromString) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> base_features(
+      InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+  ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+  // Build features for a 32-bit ARM with LPAE and div processor.
+  std::unique_ptr<const InstructionSetFeatures> krait_features(
+      base_features->AddFeaturesFromString("atomic_ldrd_strd,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()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
+  EXPECT_EQ(krait_features->AsBitmap(), 7U);
+
+  // Build features for a 32-bit ARM processor with LPAE and div flipped.
+  std::unique_ptr<const InstructionSetFeatures> denver_features(
+      base_features->AddFeaturesFromString("div,atomic_ldrd_strd", &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()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
+  EXPECT_EQ(denver_features->AsBitmap(), 7U);
+
+  // Build features for a 32-bit default ARM processor.
+  std::unique_ptr<const InstructionSetFeatures> arm7_features(
+      base_features->AddFeaturesFromString("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()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_assembly_tests.S b/runtime/arch/arm/instruction_set_features_assembly_tests.S
new file mode 100644
index 0000000..c1086df
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_assembly_tests.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/memcmp16_arm.S b/runtime/arch/arm/memcmp16_arm.S
index 3762194..b623a2a 100644
--- a/runtime/arch/arm/memcmp16_arm.S
+++ b/runtime/arch/arm/memcmp16_arm.S
@@ -65,7 +65,7 @@
 
 
         /* save registers */
-0:      stmfd       sp!, {r4, lr}
+0:      push        {r4, lr}
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r4, 0
         .cfi_rel_offset lr, 4
@@ -79,7 +79,7 @@
         sub         r2, r2, #1
         subs        r0, r0, ip
         /* restore registers and return */
-        ldmnefd     sp!, {r4, lr}
+        popne       {r4, lr}
         bxne        lr
 
 
@@ -110,25 +110,25 @@
         eors        r0, r0, ip
         ldreq       r0, [r3], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         ldreq       r0, [r3], #4
         ldreq       lr, [r1, #4]!
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         ldreq       r0, [r3], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         ldreq       r0, [r3], #4
         ldreq       lr, [r1, #4]!
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         ldreq       r0, [r3], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         ldreq       r0, [r3], #4
         ldreq       lr, [r1, #4]!
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         ldreq       r0, [r3], #4
         ldreq       ip, [r1, #4]!
-        eoreqs      r0, r0, lr
+        eorseq      r0, r0, lr
         bne         2f
         subs        r2, r2, #16
         bhs         0b
@@ -150,18 +150,24 @@
         bne         8f
         /* restore registers and return */
         mov         r0, #0
-        ldmfd       sp!, {r4, lr}
+        pop         {r4, lr}
+        .cfi_restore r4
+        .cfi_restore lr
+        .cfi_adjust_cfa_offset -8
         bx          lr
 
 2:      /* the last 2 words are different, restart them */
         ldrh        r0, [r3, #-4]
         ldrh        ip, [r1, #-4]
         subs        r0, r0, ip
-        ldreqh      r0, [r3, #-2]
-        ldreqh      ip, [r1, #-2]
-        subeqs      r0, r0, ip
+        ldrheq      r0, [r3, #-2]
+        ldrheq      ip, [r1, #-2]
+        subseq      r0, r0, ip
         /* restore registers and return */
-        ldmfd       sp!, {r4, lr}
+        pop         {r4, lr}
+        .cfi_restore r4
+        .cfi_restore lr
+        .cfi_adjust_cfa_offset -8
         bx          lr
 
         /* process the last few words */
@@ -173,7 +179,10 @@
         bne         8b
 
 9:      /* restore registers and return */
-        ldmfd       sp!, {r4, lr}
+        pop         {r4, lr}
+        .cfi_restore r4
+        .cfi_restore lr
+        .cfi_adjust_cfa_offset -8
         bx          lr
 
 
@@ -196,17 +205,17 @@
         ldreq       lr, [r1], #4
         ldreq       r0, [r3], #4
         orreq       ip, ip, lr, lsl #16
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         moveq       ip, lr, lsr #16
         ldreq       lr, [r1], #4
         ldreq       r0, [r3], #4
         orreq       ip, ip, lr, lsl #16
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         moveq       ip, lr, lsr #16
         ldreq       lr, [r1], #4
         ldreq       r0, [r3], #4
         orreq       ip, ip, lr, lsl #16
-        eoreqs      r0, r0, ip
+        eorseq      r0, r0, ip
         bne         7f
         subs        r2, r2, #8
         bhs         6b
diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S
deleted file mode 100644
index 3491c18..0000000
--- a/runtime/arch/arm/portable_entrypoints_arm.S
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "asm_support_arm.S"
-
-    /*
-     * Portable invocation stub.
-     * On entry:
-     *   r0 = method pointer
-     *   r1 = argument array or NULL for no argument methods
-     *   r2 = size of argument array in bytes
-     *   r3 = (managed) thread pointer
-     *   [sp] = JValue* result
-     *   [sp + 4] = result type char
-     */
-ENTRY art_portable_invoke_stub
-    push   {r0, r4, r5, r9, r11, lr}       @ spill regs
-    .save  {r0, r4, r5, r9, r11, lr}
-    .cfi_adjust_cfa_offset 24
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset r4, 4
-    .cfi_rel_offset r5, 8
-    .cfi_rel_offset r9, 12
-    .cfi_rel_offset r11, 16
-    .cfi_rel_offset lr, 20
-    mov    r11, sp                         @ save the stack pointer
-    .cfi_def_cfa_register r11
-    @.movsp r11
-    mov    r9, r3                          @ move managed thread pointer into r9
-    mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
-    add    r5, r2, #16                     @ create space for method pointer in frame
-    and    r5, #0xFFFFFFF0                 @ align frame size to 16 bytes
-    sub    sp, r5                          @ reserve stack space for argument array
-    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
-    bl     memcpy                          @ memcpy (dest, src, bytes)
-    ldr    r0, [r11]                       @ restore method*
-    ldr    r1, [sp, #4]                    @ copy arg value for r1
-    ldr    r2, [sp, #8]                    @ copy arg value for r2
-    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
-    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
-    blx    ip                              @ call the method
-    mov    sp, r11                         @ restore the stack pointer
-    ldr    ip, [sp, #24]                   @ load the result pointer
-    strd   r0, [ip]                        @ store r0/r1 into result pointer
-    pop    {r0, r4, r5, r9, r11, lr}       @ restore spill regs
-    .cfi_adjust_cfa_offset -24
-    bx     lr
-END art_portable_invoke_stub
-
-    .extern artPortableProxyInvokeHandler
-ENTRY art_portable_proxy_invoke_handler
-    @ 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.
-    push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
-    .save {r1-r3, r5-r8, r10-r11, lr}
-    .cfi_adjust_cfa_offset 40
-    .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
-    sub sp, #8                        @ 2 words of space, bottom word will hold Method*
-    .pad #8
-    .cfi_adjust_cfa_offset 8
-    @ Begin argument set up.
-    str     r0, [sp, #0]           @ place proxy method at bottom of frame
-    mov     r2, r9                 @ pass Thread::Current
-    mov     r3, sp                 @ pass SP
-    blx     artPortableProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
-    ldr     r12, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
-    ldr     lr,  [sp, #44]         @ restore lr
-    add     sp,  #48               @ pop frame
-    .cfi_adjust_cfa_offset -48
-    bx      lr                     @ return
-END art_portable_proxy_invoke_handler
-
-    .extern artPortableResolutionTrampoline
-ENTRY art_portable_resolution_trampoline
-    @ 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 artPortableResolutionTrampoline.
-    push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
-    .save {r1-r3, r5-r8, r10-r11, lr}
-    .cfi_adjust_cfa_offset 40
-    .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
-    sub sp, #8                     @ 2 words of space, bottom word will hold Method*
-    .pad #8
-    .cfi_adjust_cfa_offset 8
-    mov     r2, r9                 @ pass Thread::Current
-    mov     r3, sp                 @ pass SP
-    blx     artPortableResolutionTrampoline  @ (Method* called, receiver, Thread*, SP)
-    cmp     r0, #0                 @ is code pointer null?
-    beq     1f                     @ goto exception
-    mov     r12, r0
-    ldr  r0, [sp, #0]              @ load resolved method in r0
-    ldr  r1, [sp, #8]              @ restore non-callee save r1
-    ldrd r2, [sp, #12]             @ restore non-callee saves r2-r3
-    ldr  lr, [sp, #44]             @ restore lr
-    add  sp, #48                   @ rewind sp
-    .cfi_adjust_cfa_offset -48
-    bx      r12                    @ tail-call into actual code
-1:
-    ldr  r1, [sp, #8]          @ restore non-callee save r1
-    ldrd r2, [sp, #12]         @ restore non-callee saves r2-r3
-    ldr  lr, [sp, #44]         @ restore lr
-    add  sp, #48               @ rewind sp
-    .cfi_adjust_cfa_offset -48
-    bx lr
-END art_portable_resolution_trampoline
-
-    .extern artPortableToInterpreterBridge
-ENTRY_NO_HIDE 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
-    .save {r1-r3, r5-r8, r10-r11, lr}
-    .cfi_adjust_cfa_offset 40
-    .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
-    sub sp, #8                     @ 2 words of space, bottom word will hold Method*
-    .pad #8
-    .cfi_adjust_cfa_offset 8
-    mov     r1, r9                 @ pass Thread::Current
-    mov     r2, sp                 @ pass SP
-    blx     artPortableToInterpreterBridge    @ (Method* method, Thread*, SP)
-    ldr     lr,  [sp, #44]         @ restore lr
-    add     sp,  #48               @ pop frame
-    .cfi_adjust_cfa_offset -48
-    bx      lr                     @ return
-END art_portable_to_interpreter_bridge
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 51bcd3c..fec1ce5 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -27,9 +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
-    .save {r4-r11, lr}
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME rTemp1, rTemp2
+    push {r4-r11, lr}                             @ 9 words (36 bytes) of callee saves.
     .cfi_adjust_cfa_offset 36
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
@@ -40,15 +39,18 @@
     .cfi_rel_offset r10, 24
     .cfi_rel_offset r11, 28
     .cfi_rel_offset lr, 32
-    vpush {s0-s31}
-    .pad #128
-    .cfi_adjust_cfa_offset 128
-    sub sp, #12       @ 3 words of space, bottom word will hold Method*
-    .pad #12
+    vpush {s16-s31}                               @ 16 words (64 bytes) of floats.
+    .cfi_adjust_cfa_offset 64
+    sub sp, #12                                   @ 3 words of space, bottom word will hold Method*
     .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)
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 36 + 64 + 12)
 #error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM) size not as expected."
 #endif
 .endm
@@ -57,9 +59,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
-    .save {r5-r8, r10-r11, lr}
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME rTemp1, rTemp2
+    push {r5-r8, r10-r11, lr}                     @ 7 words of callee saves
     .cfi_adjust_cfa_offset 28
     .cfi_rel_offset r5, 0
     .cfi_rel_offset r6, 4
@@ -68,9 +69,13 @@
     .cfi_rel_offset r10, 16
     .cfi_rel_offset r11, 20
     .cfi_rel_offset lr, 24
-    sub sp, #4                @ bottom word will hold Method*
-    .pad #4
+    sub sp, #4                                    @ bottom word will hold Method*
     .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,8 +83,9 @@
 #endif
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     add sp, #4               @ bottom word holds Method*
+    .cfi_adjust_cfa_offset -4
     pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
     .cfi_restore r5
     .cfi_restore r6
@@ -87,19 +93,12 @@
     .cfi_restore r8
     .cfi_restore r10
     .cfi_restore r11
-    .cfi_adjust_cfa_offset -32
+    .cfi_restore lr
+    .cfi_adjust_cfa_offset -28
 .endm
 
-.macro RESTORE_REF_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
-    .cfi_restore r6
-    .cfi_restore r7
-    .cfi_restore r8
-    .cfi_restore r10
-    .cfi_restore r11
-    .cfi_adjust_cfa_offset -32
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     bx  lr                   @ return
 .endm
 
@@ -107,9 +106,9 @@
      * 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
-    .save {r1-r3, r5-r8, r10-r11, lr}
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
+    push {r1-r3, r5-r8, r10-r11, lr}   @ 10 words of callee saves and args.
+    .cfi_adjust_cfa_offset 40
     .cfi_rel_offset r1, 0
     .cfi_rel_offset r2, 4
     .cfi_rel_offset r3, 8
@@ -120,19 +119,37 @@
     .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
+    vpush {s0-s15}                     @ 16 words of float args.
+    .cfi_adjust_cfa_offset 64
+    sub sp, #8                         @ 2 words of space, bottom word will hold Method*
     .cfi_adjust_cfa_offset 8
-
     // Ugly compile-time check, but we only have the preprocessor.
-#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 40 + 8)
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 40 + 64 + 8)
 #error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM) size not as expected."
 #endif
 .endm
 
-.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME rTemp1, rTemp2
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
+    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.
+.endm
+
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
+    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
+    .cfi_adjust_cfa_offset -8
+    vpop {s0-s15}
+    .cfi_adjust_cfa_offset -64
     pop {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
     .cfi_restore r1
     .cfi_restore r2
@@ -143,9 +160,11 @@
     .cfi_restore r8
     .cfi_restore r10
     .cfi_restore r11
-    .cfi_adjust_cfa_offset -48
+    .cfi_restore lr
+    .cfi_adjust_cfa_offset -40
 .endm
 
+
 .macro RETURN_IF_RESULT_IS_ZERO
     cbnz   r0, 1f              @ result non-zero branch over
     bx     lr                  @ return
@@ -165,41 +184,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
 
@@ -220,16 +233,20 @@
     DELIVER_PENDING_EXCEPTION
 .endm
 
+.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+    RETURN_IF_RESULT_IS_NON_ZERO
+    DELIVER_PENDING_EXCEPTION
+.endm
+
 // Macros taking opportunity of code similarities for downcalls with referrer for non-wide fields.
 .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,39 +254,26 @@
 .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
 
-.macro  THREE_ARG_REF_DOWNCALL name, entrypoint, return
+.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
+    .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,18 +329,17 @@
 .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
-    .pad #16
     .cfi_adjust_cfa_offset 16
     bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
     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:
@@ -353,60 +356,88 @@
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
     /*
-     * Quick invocation stub.
+     * Quick invocation stub internal.
      * On entry:
      *   r0 = method pointer
      *   r1 = argument array or NULL for no argument methods
      *   r2 = size of argument array in bytes
      *   r3 = (managed) thread pointer
      *   [sp] = JValue* result
-     *   [sp + 4] = shorty
+     *   [sp + 4] = result_in_float
+     *   [sp + 8] = core register argument array
+     *   [sp + 12] = fp register argument array
+     *  +-------------------------+
+     *  | uint32_t* fp_reg_args   |
+     *  | uint32_t* core_reg_args |
+     *  |   result_in_float       | <- Caller frame
+     *  |   Jvalue* result        |
+     *  +-------------------------+
+     *  |          lr             |
+     *  |          r11            |
+     *  |          r9             |
+     *  |          r4             | <- r11
+     *  +-------------------------+
+     *  | uint32_t out[n-1]       |
+     *  |    :      :             |        Outs
+     *  | uint32_t out[0]         |
+     *  | StackRef<ArtMethod>     | <- SP  value=null
+     *  +-------------------------+
      */
-ENTRY art_quick_invoke_stub
-    push   {r0, r4, r5, r9, r11, lr}       @ spill regs
-    .save  {r0, r4, r5, r9, r11, lr}
-    .pad #24
-    .cfi_adjust_cfa_offset 24
-    .cfi_rel_offset r0, 0
-    .cfi_rel_offset r4, 4
-    .cfi_rel_offset r5, 8
-    .cfi_rel_offset r9, 12
-    .cfi_rel_offset r11, 16
-    .cfi_rel_offset lr, 20
+ENTRY art_quick_invoke_stub_internal
+    push   {r4, r5, r6, r7, r8, r9, r10, r11, lr}               @ spill regs
+    .cfi_adjust_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
+    .cfi_rel_offset r8, 16
+    .cfi_rel_offset r9, 20
+    .cfi_rel_offset r10, 24
+    .cfi_rel_offset r11, 28
+    .cfi_rel_offset lr, 32
     mov    r11, sp                         @ save the stack pointer
     .cfi_def_cfa_register r11
+
     mov    r9, r3                          @ move managed thread pointer into r9
+
+    add    r4, r2, #4                      @ create space for method pointer in frame
+    sub    r4, sp, r4                      @ reserve & align *stack* to 16 bytes: native calling
+    and    r4, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART
+    mov    sp, r4                          @ 16B alignment ourselves.
+
+    mov    r4, r0                          @ save method*
+    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
+    bl     memcpy                          @ memcpy (dest, src, bytes)
+    mov    ip, #0                          @ set ip to 0
+    str    ip, [sp]                        @ store NULL for method* at bottom of frame
+
+    ldr    ip, [r11, #48]                  @ load fp register argument array pointer
+    vldm   ip, {s0-s15}                    @ copy s0 - s15
+
+    ldr    ip, [r11, #44]                  @ load core register argument array pointer
+    mov    r0, r4                          @ restore method*
+    add    ip, ip, #4                      @ skip r0
+    ldm    ip, {r1-r3}                     @ copy r1 - r3
+
 #ifdef ARM_R4_SUSPEND_FLAG
     mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
 #endif
-    add    r5, r2, #4                      @ create space for method pointer in frame
 
-    sub    r5, sp, r5                      @ reserve & align *stack* to 16 bytes: native calling
-    and    r5, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART
-    mov    sp, r5                          @ 16B alignment ourselves.
-
-    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
-    bl     memcpy                          @ memcpy (dest, src, bytes)
-    ldr    r0, [r11]                       @ restore method*
-    ldr    r1, [sp, #4]                    @ copy arg value for r1
-    ldr    r2, [sp, #8]                    @ copy arg value for r2
-    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_32]  @ 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
-    strd   r0, [ip]                        @ store r0/r1 into result pointer
-    pop    {r0, r4, r5, r9, r11, lr}       @ restore spill regs
-    .cfi_restore r0
-    .cfi_restore r4
-    .cfi_restore r5
-    .cfi_restore r9
-    .cfi_restore lr
-    .cfi_adjust_cfa_offset -24
-    bx     lr
-END art_quick_invoke_stub
+    .cfi_def_cfa_register sp
+
+    ldr    r4, [sp, #40]                   @ load result_is_float
+    ldr    r9, [sp, #36]                   @ load the result pointer
+    cmp    r4, #0
+    ite    eq
+    strdeq r0, [r9]                        @ store r0/r1 into result pointer
+    vstrne d0, [r9]                        @ store s0-s1/d0 into result pointer
+
+    pop    {r4, r5, r6, r7, r8, r9, r10, r11, pc}               @ restore spill regs
+END art_quick_invoke_stub_internal
 
     /*
      * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
@@ -426,16 +457,7 @@
      * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
      * failure.
      */
-    .extern artHandleFillArrayDataFromCode
-ENTRY art_quick_handle_fill_data
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case exception allocation triggers GC
-    mov    r2, r9                          @ pass Thread::Current
-    mov    r3, sp                          @ pass SP
-    bl     artHandleFillArrayDataFromCode  @ (Array*, const DexFile::Payload*, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    RETURN_IF_RESULT_IS_ZERO
-    DELIVER_PENDING_EXCEPTION
-END art_quick_handle_fill_data
+TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
 
     /*
      * Entry from managed code that calls artLockObjectFromCode, may block for GC. r0 holds the
@@ -446,10 +468,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
@@ -465,14 +487,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
@@ -484,7 +505,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]
@@ -495,18 +516,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
@@ -518,29 +539,29 @@
     .extern artThrowClassCastException
 ENTRY art_quick_check_cast
     push {r0-r1, lr}                    @ save arguments, link register and pad
-    .save {r0-r1, lr}
     .cfi_adjust_cfa_offset 12
     .cfi_rel_offset r0, 0
     .cfi_rel_offset r1, 4
     .cfi_rel_offset lr, 8
     sub sp, #4
-    .pad #4
     .cfi_adjust_cfa_offset 4
     bl artIsAssignableFromCode
     cbz    r0, .Lthrow_class_cast_exception
     add sp, #4
     .cfi_adjust_cfa_offset -4
     pop {r0-r1, pc}
+    .cfi_adjust_cfa_offset 4        @ Reset unwind info so following code unwinds.
 .Lthrow_class_cast_exception:
     add sp, #4
     .cfi_adjust_cfa_offset -4
     pop {r0-r1, lr}
+    .cfi_adjust_cfa_offset -12
     .cfi_restore r0
     .cfi_restore r1
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    .cfi_restore lr
+    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
 
@@ -557,7 +578,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
@@ -568,25 +589,24 @@
     .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:
     push {r0-r2, lr}             @ save arguments
-    .save {r0-r2, lr}
     .cfi_adjust_cfa_offset 16
     .cfi_rel_offset r0, 0
     .cfi_rel_offset r1, 4
@@ -602,7 +622,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
@@ -610,66 +630,43 @@
     blx lr
 .Lthrow_array_store_exception:
     pop {r0-r2, lr}
-    .cfi_restore r0
-    .cfi_restore r1
-    .cfi_restore r2
-    .cfi_restore lr
-    .cfi_adjust_cfa_offset -16
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    /* No need to repeat restore cfi directives, the ones above apply here. */
+    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
 
-    /*
-     * Entry from managed code when uninitialized static storage, this stub will run the class
-     * initializer and deliver the exception on error. On success the static storage base is
-     * returned.
-     */
-    .extern artInitializeStaticStorageFromCode
-ENTRY art_quick_initialize_static_storage
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ 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)
-    bl     artInitializeStaticStorageFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    RETURN_IF_RESULT_IS_NON_ZERO
-    DELIVER_PENDING_EXCEPTION
-END art_quick_initialize_static_storage
+// Macro to facilitate adding new allocation entrypoints.
+.macro TWO_ARG_DOWNCALL name, entrypoint, return
+    .extern \entrypoint
+ENTRY \name
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
+    mov    r2, r9                     @ pass Thread::Current
+    bl     \entrypoint     @ (uint32_t type_idx, Method* method, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    \return
+END \name
+.endm
 
-    /*
-     * Entry from managed code when dex cache misses for a type_idx
-     */
-    .extern artInitializeTypeFromCode
-ENTRY art_quick_initialize_type
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ 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)
-    bl     artInitializeTypeFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    RETURN_IF_RESULT_IS_NON_ZERO
-    DELIVER_PENDING_EXCEPTION
-END art_quick_initialize_type
+// Macro to facilitate adding new array allocation entrypoints.
+.macro THREE_ARG_DOWNCALL name, entrypoint, return
+    .extern \entrypoint
+ENTRY \name
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r3, r12  @ save callee saves in case of GC
+    mov    r3, r9                     @ pass Thread::Current
+    @ (uint32_t type_idx, Method* method, int32_t component_count, Thread*)
+    bl     \entrypoint
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    \return
+END \name
+.endm
 
-    /*
-     * Entry from managed code when type_idx needs to be checked for access and dex cache may also
-     * miss.
-     */
-    .extern artInitializeTypeAndVerifyAccessFromCode
-ENTRY art_quick_initialize_type_and_verify_access
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ 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)
-    bl     artInitializeTypeAndVerifyAccessFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    RETURN_IF_RESULT_IS_NON_ZERO
-    DELIVER_PENDING_EXCEPTION
-END art_quick_initialize_type_and_verify_access
+TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 
     /*
      * Called by managed code to resolve a static field and load a non-wide value.
@@ -685,13 +682,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:
@@ -712,18 +708,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:
@@ -743,22 +733,16 @@
      */
     .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
+    .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
@@ -775,19 +759,16 @@
      */
     .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
+    .cfi_adjust_cfa_offset 12
+    str    r12, [sp, #-4]!               @ expand the frame and pass the referrer
+    .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
@@ -798,51 +779,7 @@
      * R1 holds the string index. The fast path check for hit in strings cache has already been
      * performed.
      */
-    .extern artResolveStringFromCode
-ENTRY art_quick_resolve_string
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ 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)
-    bl     artResolveStringFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    RETURN_IF_RESULT_IS_NON_ZERO
-    DELIVER_PENDING_EXCEPTION
-END art_quick_resolve_string
-
-// Macro to facilitate adding new allocation entrypoints.
-.macro TWO_ARG_DOWNCALL name, entrypoint, return
-    .extern \entrypoint
-ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ 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
-    \return
-    DELIVER_PENDING_EXCEPTION
-END \name
-.endm
-
-// Macro to facilitate adding new array allocation entrypoints.
-.macro THREE_ARG_DOWNCALL name, entrypoint, return
-    .extern \entrypoint
-ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ 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)
-    bl     \entrypoint
-    add    sp, #16                    @ strip the extra frame
-    .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    \return
-    DELIVER_PENDING_EXCEPTION
-END \name
-.endm
+TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 
 // Generate the allocation entrypoints for each allocator.
 GENERATE_ALL_ALLOC_ENTRYPOINTS
@@ -853,25 +790,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
 
     /*
@@ -881,19 +817,19 @@
      */
      .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)
     ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
-    add     sp, #16                @ skip r1-r3, 4 bytes padding.
-    .cfi_adjust_cfa_offset -16
+    // Tear down the callee-save frame. Skip arg registers.
+    add     sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     cbnz    r2, 1f                 @ success if no exception is pending
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    vmov    d0, r0, r1             @ store into fpr, for when it's a fpr return...
     bx      lr                     @ return on success
 1:
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END art_quick_proxy_invoke_handler
 
@@ -903,34 +839,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
@@ -996,44 +931,42 @@
     ldr r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
     cbnz r2, .Lexception_in_native
 
-    // Tear down the callee-save frame.
-    add  sp, #12                      @ rewind sp
-    // Do not pop r0 and r1, they contain the return value.
-    pop {r2-r3, r5-r8, r10-r11, lr}  @ 9 words of callee saves
-    .cfi_restore r2
-    .cfi_restore r3
-    .cfi_restore r5
-    .cfi_restore r6
-    .cfi_restore r7
-    .cfi_restore r8
-    .cfi_restore r10
-    .cfi_restore r11
-    .cfi_adjust_cfa_offset -48
+    // Tear down the callee-save frame. Skip arg registers.
+    add     sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
 
+    // store into fpr, for when it's a fpr return...
+    vmov d0, r0, r1
     bx lr      // ret
+    // Undo the unwinding information from above since it doesn't apply below.
+    .cfi_def_cfa_register r10
+    .cfi_adjust_cfa_offset FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
 
 .Lentry_error:
     mov sp, r10
     .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
+    // Tear down the callee-save frame. Skip arg registers.
+    add     sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     cbnz    r2, 1f                 @ success if no exception is pending
-    bx    lr                       @ return on success
+    vmov    d0, r0, r1             @ store into fpr, for when it's a fpr return...
+    bx      lr                     @ return on success
 1:
     DELIVER_PENDING_EXCEPTION
 END art_quick_to_interpreter_bridge
@@ -1044,38 +977,29 @@
     .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}
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset r1, 4
     sub   sp, #8         @ space for return value argument
-    .pad #8
     .cfi_adjust_cfa_offset 8
     strd r0, [sp]        @ r0/r1 -> [sp] for fpr_res
     mov   r2, r0         @ pass return value as gpr_res
@@ -1089,12 +1013,13 @@
     mov   r2, r0         @ link register saved by instrumentation
     mov   lr, r1         @ r1 is holding link register if we're to bounce to deoptimize
     pop   {r0, r1}       @ restore return value
+    .cfi_adjust_cfa_offset -8
     .cfi_restore r0
     .cfi_restore r1
     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
@@ -1102,10 +1027,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
 
     /*
@@ -1129,7 +1053,6 @@
     /* mul-long vAA, vBB, vCC */
 ENTRY art_quick_mul_long
     push    {r9 - r10}
-    .save {r9 - r10}
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r9, 0
     .cfi_rel_offset r10, 4
@@ -1222,15 +1145,14 @@
      */
 ENTRY art_quick_indexof
     push {r4, r10-r11, lr} @ 4 words of callee saves
-    .save {r4, r10-r11, lr}
     .cfi_adjust_cfa_offset 16
     .cfi_rel_offset r4, 0
     .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
@@ -1241,7 +1163,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 */
@@ -1339,7 +1261,6 @@
 1:                        @ Same strings, return.
 
     push {r4, r7-r12, lr} @ 8 words - keep alignment
-    .save {r4, r7-r12, lr}
     .cfi_adjust_cfa_offset 32
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r7, 4
@@ -1350,12 +1271,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:
@@ -1377,8 +1298,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:
@@ -1462,3 +1383,52 @@
 .Ldone:
     pop   {r4, r7-r12, pc}
 END art_quick_string_compareto
+
+    /* Assembly routines used to handle ABI differences. */
+
+    /* double fmod(double a, double b) */
+    .extern fmod
+ENTRY art_quick_fmod
+    push  {lr}
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset lr, 0
+    sub   sp, #4
+    .cfi_adjust_cfa_offset 4
+    vmov  r0, r1, d0
+    vmov  r2, r3, d1
+    bl    fmod
+    vmov  d0, r0, r1
+    add   sp, #4
+    .cfi_adjust_cfa_offset -4
+    pop   {pc}
+END art_quick_fmod
+
+    /* float fmodf(float a, float b) */
+     .extern fmodf
+ENTRY art_quick_fmodf
+    push  {lr}
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset lr, 0
+    sub   sp, #4
+    .cfi_adjust_cfa_offset 4
+    vmov  r0, r1, d0
+    bl    fmodf
+    vmov  s0, r0
+    add   sp, #4
+    .cfi_adjust_cfa_offset -4
+    pop   {pc}
+END art_quick_fmod
+
+    /* int64_t art_d2l(double d) */
+    .extern art_d2l
+ENTRY art_quick_d2l
+    vmov  r0, r1, d0
+    b     art_d2l
+END art_quick_d2l
+
+    /* int64_t art_f2l(float f) */
+    .extern art_f2l
+ENTRY art_quick_f2l
+    vmov  r0, s0
+    b     art_f2l
+END art_quick_f2l
diff --git a/runtime/arch/arm/quick_entrypoints_cc_arm.cc b/runtime/arch/arm/quick_entrypoints_cc_arm.cc
new file mode 100644
index 0000000..a3acd7e
--- /dev/null
+++ b/runtime/arch/arm/quick_entrypoints_cc_arm.cc
@@ -0,0 +1,117 @@
+/*
+ * 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 "mirror/art_method.h"
+#include "utils.h"  // For RoundUp().
+
+namespace art {
+
+// Assembly stub that does the final part of the up-call into Java.
+extern "C" void art_quick_invoke_stub_internal(mirror::ArtMethod*, uint32_t*, uint32_t,
+                                               Thread* self, JValue* result, uint32_t, uint32_t*,
+                                               uint32_t*);
+
+template <bool kIsStatic>
+static void quick_invoke_reg_setup(mirror::ArtMethod* method, uint32_t* args, uint32_t args_size,
+                                   Thread* self, JValue* result, const char* shorty) {
+  // Note: We do not follow aapcs ABI in quick code for both softfp and hardfp.
+  uint32_t core_reg_args[4];  // r0 ~ r3
+  uint32_t fp_reg_args[16];  // s0 ~ s15 (d0 ~ d7)
+  uint32_t gpr_index = 1;  // Index into core registers. Reserve r0 for mirror::ArtMethod*.
+  uint32_t fpr_index = 0;  // Index into float registers.
+  uint32_t fpr_double_index = 0;  // Index into float registers for doubles.
+  uint32_t arg_index = 0;  // Index into argument array.
+  const uint32_t result_in_float = kArm32QuickCodeUseSoftFloat ? 0 :
+      (shorty[0] == 'F' || shorty[0] == 'D') ? 1 : 0;
+
+  if (!kIsStatic) {
+    // Copy receiver for non-static methods.
+    core_reg_args[gpr_index++] = args[arg_index++];
+  }
+
+  for (uint32_t shorty_index = 1; shorty[shorty_index] != '\0'; ++shorty_index, ++arg_index) {
+    char arg_type = shorty[shorty_index];
+    if (kArm32QuickCodeUseSoftFloat) {
+      arg_type = (arg_type == 'D') ? 'J' : arg_type;  // Regard double as long.
+      arg_type = (arg_type == 'F') ? 'I' : arg_type;  // Regard float as int.
+    }
+    switch (arg_type) {
+      case 'D': {
+        // Copy double argument into fp_reg_args if there are still floating point reg arguments.
+        // Double should not overlap with float.
+        fpr_double_index = std::max(fpr_double_index, RoundUp(fpr_index, 2));
+        if (fpr_double_index < arraysize(fp_reg_args)) {
+          fp_reg_args[fpr_double_index++] = args[arg_index];
+          fp_reg_args[fpr_double_index++] = args[arg_index + 1];
+        }
+        ++arg_index;
+        break;
+      }
+      case 'F':
+        // Copy float argument into fp_reg_args if there are still floating point reg arguments.
+        // If fpr_index is odd then its pointing at a hole next to an existing float argument. If we
+        // encounter a float argument then pick it up from that hole. In the case fpr_index is even,
+        // ensure that we don't pick up an argument that overlaps with with a double from
+        // fpr_double_index. In either case, take care not to go beyond the maximum number of
+        // floating point arguments.
+        if (fpr_index % 2 == 0) {
+          fpr_index = std::max(fpr_double_index, fpr_index);
+        }
+        if (fpr_index < arraysize(fp_reg_args)) {
+          fp_reg_args[fpr_index++] = args[arg_index];
+        }
+        break;
+      case 'J':
+        if (gpr_index == 1 && !kArm32QuickCodeUseSoftFloat) {
+          // Don't use r1-r2 as a register pair, move to r2-r3 instead.
+          gpr_index++;
+        }
+        if (gpr_index < arraysize(core_reg_args)) {
+          // Note that we don't need to do this if two registers are not available
+          // when !kArm32QuickCodeUseSoftFloat. We do it anyway to leave this
+          // code simple.
+          core_reg_args[gpr_index++] = args[arg_index];
+        }
+        ++arg_index;
+        FALLTHROUGH_INTENDED;  // Fall-through to take of the high part.
+      default:
+        if (gpr_index < arraysize(core_reg_args)) {
+          core_reg_args[gpr_index++] = args[arg_index];
+        }
+        break;
+    }
+  }
+
+  art_quick_invoke_stub_internal(method, args, args_size, self, result, result_in_float,
+      core_reg_args, fp_reg_args);
+}
+
+// Called by art::mirror::ArtMethod::Invoke to do entry into a non-static method.
+// TODO: migrate into an assembly implementation as with ARM64.
+extern "C" void art_quick_invoke_stub(mirror::ArtMethod* method, uint32_t* args, uint32_t args_size,
+                                      Thread* self, JValue* result, const char* shorty) {
+  quick_invoke_reg_setup<false>(method, args, args_size, self, result, shorty);
+}
+
+// Called by art::mirror::ArtMethod::Invoke to do entry into a static method.
+// TODO: migrate into an assembly implementation as with ARM64.
+extern "C" void art_quick_invoke_static_stub(mirror::ArtMethod* method, uint32_t* args,
+                                             uint32_t args_size, Thread* self, JValue* result,
+                                             const char* shorty) {
+  quick_invoke_reg_setup<true>(method, args, args_size, self, result, shorty);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm/quick_method_frame_info_arm.h b/runtime/arch/arm/quick_method_frame_info_arm.h
index 7595e94..c1f3fc2 100644
--- a/runtime/arch/arm/quick_method_frame_info_arm.h
+++ b/runtime/arch/arm/quick_method_frame_info_arm.h
@@ -25,6 +25,8 @@
 namespace art {
 namespace arm {
 
+static constexpr uint32_t kArmCalleeSaveAlwaysSpills =
+    (1 << art::arm::LR);
 static constexpr uint32_t kArmCalleeSaveRefSpills =
     (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) | (1 << art::arm::R8) |
     (1 << art::arm::R10) | (1 << art::arm::R11);
@@ -32,23 +34,30 @@
     (1 << art::arm::R1) | (1 << art::arm::R2) | (1 << art::arm::R3);
 static constexpr uint32_t kArmCalleeSaveAllSpills =
     (1 << art::arm::R4) | (1 << art::arm::R9);
-static constexpr uint32_t kArmCalleeSaveFpAllSpills =
+
+static constexpr uint32_t kArmCalleeSaveFpAlwaysSpills = 0;
+static constexpr uint32_t kArmCalleeSaveFpRefSpills = 0;
+static constexpr uint32_t kArmCalleeSaveFpArgSpills =
     (1 << art::arm::S0)  | (1 << art::arm::S1)  | (1 << art::arm::S2)  | (1 << art::arm::S3)  |
     (1 << art::arm::S4)  | (1 << art::arm::S5)  | (1 << art::arm::S6)  | (1 << art::arm::S7)  |
     (1 << art::arm::S8)  | (1 << art::arm::S9)  | (1 << art::arm::S10) | (1 << art::arm::S11) |
-    (1 << art::arm::S12) | (1 << art::arm::S13) | (1 << art::arm::S14) | (1 << art::arm::S15) |
+    (1 << art::arm::S12) | (1 << art::arm::S13) | (1 << art::arm::S14) | (1 << art::arm::S15);
+static constexpr uint32_t kArmCalleeSaveFpAllSpills =
     (1 << art::arm::S16) | (1 << art::arm::S17) | (1 << art::arm::S18) | (1 << art::arm::S19) |
     (1 << art::arm::S20) | (1 << art::arm::S21) | (1 << art::arm::S22) | (1 << art::arm::S23) |
     (1 << art::arm::S24) | (1 << art::arm::S25) | (1 << art::arm::S26) | (1 << art::arm::S27) |
     (1 << art::arm::S28) | (1 << art::arm::S29) | (1 << art::arm::S30) | (1 << art::arm::S31);
 
 constexpr uint32_t ArmCalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
-  return kArmCalleeSaveRefSpills | (type == Runtime::kRefsAndArgs ? kArmCalleeSaveArgSpills : 0) |
-      (type == Runtime::kSaveAll ? kArmCalleeSaveAllSpills : 0) | (1 << art::arm::LR);
+  return kArmCalleeSaveAlwaysSpills | kArmCalleeSaveRefSpills |
+      (type == Runtime::kRefsAndArgs ? kArmCalleeSaveArgSpills : 0) |
+      (type == Runtime::kSaveAll ? kArmCalleeSaveAllSpills : 0);
 }
 
 constexpr uint32_t ArmCalleeSaveFpSpills(Runtime::CalleeSaveType type) {
-  return type == Runtime::kSaveAll ? kArmCalleeSaveFpAllSpills : 0;
+  return kArmCalleeSaveFpAlwaysSpills | kArmCalleeSaveFpRefSpills |
+      (type == Runtime::kRefsAndArgs ? kArmCalleeSaveFpArgSpills: 0) |
+      (type == Runtime::kSaveAll ? kArmCalleeSaveFpAllSpills : 0);
 }
 
 constexpr uint32_t ArmCalleeSaveFrameSize(Runtime::CalleeSaveType type) {
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..0a31480 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -19,11 +19,8 @@
 #include "context_arm64.h"
 
 #include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
 #include "quick/quick_method_frame_info.h"
-#include "stack.h"
-#include "thread.h"
-
+#include "utils.h"
 
 namespace art {
 namespace arm64 {
@@ -31,7 +28,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 +49,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 +71,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 +144,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..e68d41d 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -16,113 +16,29 @@
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/jni/jni_entrypoints.h"
-#include "entrypoints/portable/portable_entrypoints.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/quick/quick_default_externs.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*);
-
 // Cast entrypoints.
 extern "C" uint32_t art_quick_assignable_from_code(const mirror::Class* klass,
                                             const mirror::Class* ref_class);
-extern "C" void art_quick_check_cast(void*, void*);
-
-// DexCache entrypoints.
-extern "C" void* art_quick_initialize_static_storage(uint32_t, void*);
-extern "C" void* art_quick_initialize_type(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, void*);
-extern "C" void* art_quick_resolve_string(void*, uint32_t);
-
-// Field entrypoints.
-extern "C" int art_quick_set8_instance(uint32_t, void*, int8_t);
-extern "C" int art_quick_set8_static(uint32_t, int8_t);
-extern "C" int art_quick_set16_instance(uint32_t, void*, int16_t);
-extern "C" int art_quick_set16_static(uint32_t, int16_t);
-extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t);
-extern "C" int art_quick_set32_static(uint32_t, int32_t);
-extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t);
-extern "C" int art_quick_set64_static(uint32_t, int64_t);
-extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*);
-extern "C" int art_quick_set_obj_static(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_instance(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_instance(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_static(uint32_t);
-extern "C" int8_t art_quick_get_byte_static(uint32_t);
-extern "C" uint16_t art_quick_get_char_instance(uint32_t, void*);
-extern "C" int16_t art_quick_get_short_instance(uint32_t, void*);
-extern "C" uint16_t art_quick_get_char_static(uint32_t);
-extern "C" int16_t art_quick_get_short_static(uint32_t);
-extern "C" int32_t art_quick_get32_instance(uint32_t, void*);
-extern "C" int32_t art_quick_get32_static(uint32_t);
-extern "C" int64_t art_quick_get64_instance(uint32_t, void*);
-extern "C" int64_t art_quick_get64_static(uint32_t);
-extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
-extern "C" void* art_quick_get_obj_static(uint32_t);
-
-// Array entrypoints.
-extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
-extern "C" void art_quick_handle_fill_data(void*, void*);
-
-// Lock entrypoints.
-extern "C" void art_quick_lock_object(void*);
-extern "C" void art_quick_unlock_object(void*);
 
 // Single-precision FP arithmetics.
 extern "C" float art_quick_fmodf(float a, float b);          // REM_FLOAT[_2ADDR]
 
 // Double-precision FP arithmetics.
-extern "C" double art_quick_fmod(double a, double b);         // REM_DOUBLE[_2ADDR]
+extern "C" double art_quick_fmod(double a, double b);        // REM_DOUBLE[_2ADDR]
 
-// Memcpy
-extern "C" void* art_quick_memcpy(void* __restrict, const void* __restrict, size_t);
-
-// Intrinsic entrypoints.
-extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
-extern "C" int32_t art_quick_string_compareto(void*, void*);
-
-// Invoke entrypoints.
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-
-// Thread entrypoints.
-extern "C" void art_quick_test_suspend();
-
-// Throw entrypoints.
-extern "C" void art_quick_deliver_exception(void*);
-extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
-extern "C" void art_quick_throw_div_zero();
-extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
-extern "C" void art_quick_throw_null_pointer_exception();
-extern "C" void art_quick_throw_stack_overflow(void*);
-
-extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
-
-// Generic JNI downcall
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
-                     PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
+                     QuickEntryPoints* qpoints) {
   // Interpreter
   ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge;
   ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge;
@@ -130,10 +46,6 @@
   // JNI
   jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
 
-  // Portable
-  ppoints->pPortableResolutionTrampoline = art_portable_resolution_trampoline;
-  ppoints->pPortableToInterpreterBridge = art_portable_to_interpreter_bridge;
-
   // Alloc
   ResetQuickAllocEntryPoints(qpoints);
 
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index 687d232..c914d85 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -37,7 +37,8 @@
 
 namespace art {
 
-void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                      void* context) {
   // To match the case used in ARM we return directly to the longjmp function
   // rather than through a trivial assembly language stub.
 
@@ -51,7 +52,7 @@
   sc->pc = reinterpret_cast<uintptr_t>(longjmp);
 }
 
-void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
   struct ucontext *uc = reinterpret_cast<struct ucontext *>(context);
@@ -82,7 +83,8 @@
   *out_return_pc = sc->pc + 4;
 }
 
-bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
+bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                void* context) {
   // The code that looks for the catch location needs to know the value of the
   // PC at the point of call.  For Null checks we insert a GC map that is immediately after
   // the load/store instruction that might cause the fault.
@@ -105,7 +107,8 @@
 // The offset from r18 is Thread::ThreadSuspendTriggerOffset().
 // To check for a suspend check, we examine the instructions that caused
 // the fault (at PC-4 and PC).
-bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
+bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                               void* context) {
   // These are the instructions to check for.  The first one is the ldr x0,[r18,#xxx]
   // where xxx is the offset of the suspend trigger.
   uint32_t checkinst1 = 0xf9400240 | (Thread::ThreadSuspendTriggerOffset<8>().Int32Value() << 7);
@@ -155,7 +158,8 @@
   return false;
 }
 
-bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
+bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                  void* context) {
   struct ucontext *uc = reinterpret_cast<struct ucontext *>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
new file mode 100644
index 0000000..a1270dc
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -0,0 +1,146 @@
+/*
+ * 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 "instruction_set_features_arm64.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromVariant(
+    const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED) {
+  const bool smp = true;  // Conservative default.
+
+  // Look for variants that need a fix for a53 erratum 835769.
+  static const char* arm64_variants_with_a53_835769_bug[] = {
+      "default", "generic"  // Pessimistically assume all generic ARM64s are A53s.
+  };
+  bool needs_a53_835769_fix = FindVariantInArray(arm64_variants_with_a53_835769_bug,
+                                                 arraysize(arm64_variants_with_a53_835769_bug),
+                                                 variant);
+
+  if (!needs_a53_835769_fix) {
+    // Check to see if this is an expected variant.
+    static const char* arm64_known_variants[] = {
+        "denver64"
+    };
+    if (!FindVariantInArray(arm64_known_variants, arraysize(arm64_known_variants), variant)) {
+      std::ostringstream os;
+      os << "Unexpected CPU variant for Arm64: " << variant;
+      *error_msg = os.str();
+      return nullptr;
+    }
+  }
+  return new Arm64InstructionSetFeatures(smp, needs_a53_835769_fix);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool is_a53 = (bitmap & kA53Bitfield) != 0;
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCppDefines() {
+  const bool smp = true;
+  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::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 smp = false;
+  const bool is_a53 = true;  // Conservative default.
+
+  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("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromHwcap() {
+  bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
+  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromAssembly() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+bool Arm64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kArm64 != other->GetInstructionSet()) {
+    return false;
+  }
+  const Arm64InstructionSetFeatures* other_as_arm = other->AsArm64InstructionSetFeatures();
+  return fix_cortex_a53_835769_ == other_as_arm->fix_cortex_a53_835769_;
+}
+
+uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) | (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
+}
+
+std::string Arm64InstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (fix_cortex_a53_835769_) {
+    result += ",a53";
+  } else {
+    result += ",-a53";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  bool is_a53 = fix_cortex_a53_835769_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "a53") {
+      is_a53 = true;
+    } else if (feature == "-a53") {
+      is_a53 = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.h b/runtime/arch/arm64/instruction_set_features_arm64.h
new file mode 100644
index 0000000..b0c66b3
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64.h
@@ -0,0 +1,90 @@
+/*
+ * 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_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
+#define ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the ARM64 architecture.
+class Arm64InstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const Arm64InstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* 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 Arm64InstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kArm64;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  // Return a string of the form "a53" or "none".
+  std::string GetFeatureString() const OVERRIDE;
+
+  // Generate code addressing Cortex-A53 erratum 835769?
+  bool NeedFixCortexA53_835769() const {
+      return fix_cortex_a53_835769_;
+  }
+
+  virtual ~Arm64InstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "a53" adding these to a new ArmInstructionSetFeatures.
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  explicit Arm64InstructionSetFeatures(bool smp, bool needs_a53_835769_fix)
+      : InstructionSetFeatures(smp), fix_cortex_a53_835769_(needs_a53_835769_fix) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kA53Bitfield = 2,
+  };
+
+  const bool fix_cortex_a53_835769_;
+
+  DISALLOW_COPY_AND_ASSIGN(Arm64InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
new file mode 100644
index 0000000..027e59c
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -0,0 +1,35 @@
+/*
+ * 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 "instruction_set_features_arm64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(Arm64InstructionSetFeaturesTest, Arm64Features) {
+  // Build features for an ARM64 processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> arm64_features(
+      InstructionSetFeatures::FromVariant(kArm64, "default", &error_msg));
+  ASSERT_TRUE(arm64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(arm64_features->GetInstructionSet(), kArm64);
+  EXPECT_TRUE(arm64_features->Equals(arm64_features.get()));
+  EXPECT_STREQ("smp,a53", arm64_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm64_features->AsBitmap(), 3U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm64/portable_entrypoints_arm64.S b/runtime/arch/arm64/portable_entrypoints_arm64.S
deleted file mode 100644
index 41711b5..0000000
--- a/runtime/arch/arm64/portable_entrypoints_arm64.S
+++ /dev/null
@@ -1,28 +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.
- */
-
-#include "asm_support_arm64.S"
-
-    /*
-     * Portable invocation stub.
-     */
-UNIMPLEMENTED art_portable_invoke_stub
-
-UNIMPLEMENTED art_portable_proxy_invoke_handler
-
-UNIMPLEMENTED art_portable_resolution_trampoline
-
-UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 606816a..770073b5 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:
@@ -486,7 +499,7 @@
 
 .macro INVOKE_STUB_CREATE_FRAME
 
-SAVE_SIZE=6*8   // x4, x5, xSUSPEND, SP, LR & FP saved.
+SAVE_SIZE=15*8   // x4, x5, x20, x21, x22, x23, x24, x25, x26, x27, x28, xSUSPEND, SP, LR, FP saved.
 SAVE_SIZE_AND_METHOD=SAVE_SIZE+STACK_REFERENCE_SIZE
 
 
@@ -502,6 +515,25 @@
     .cfi_def_cfa_register x10              // before this.
     .cfi_adjust_cfa_offset SAVE_SIZE
 
+    str x28, [x10, #112]
+    .cfi_rel_offset x28, 112
+
+    stp x26, x27, [x10, #96]
+    .cfi_rel_offset x26, 96
+    .cfi_rel_offset x27, 104
+
+    stp x24, x25, [x10, #80]
+    .cfi_rel_offset x24, 80
+    .cfi_rel_offset x25, 88
+
+    stp x22, x23, [x10, #64]
+    .cfi_rel_offset x22, 64
+    .cfi_rel_offset x23, 72
+
+    stp x20, x21, [x10, #48]
+    .cfi_rel_offset x20, 48
+    .cfi_rel_offset x21, 56
+
     stp x9, xSUSPEND, [x10, #32]           // Save old stack pointer and xSUSPEND
     .cfi_rel_offset sp, 32
     .cfi_rel_offset x19, 40
@@ -551,7 +583,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_64]
     // Branch to method.
     blr x9
 
@@ -560,6 +592,25 @@
     .cfi_restore x4
     .cfi_restore x5
 
+    ldr x28, [xFP, #112]
+    .cfi_restore x28
+
+    ldp x26, x27, [xFP, #96]
+    .cfi_restore x26
+    .cfi_restore x27
+
+    ldp x24, x25, [xFP, #80]
+    .cfi_restore x24
+    .cfi_restore x25
+
+    ldp x22, x23, [xFP, #64]
+    .cfi_restore x22
+    .cfi_restore x23
+
+    ldp x20, x21, [xFP, #48]
+    .cfi_restore x20
+    .cfi_restore x21
+
     // Store result (w0/x0/s0/d0) appropriately, depending on resultType.
     ldrb w10, [x5]
 
@@ -937,21 +988,6 @@
 END art_quick_do_long_jump
 
     /*
-     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
-     * failure.
-     */
-    .extern artHandleFillArrayDataFromCode
-ENTRY art_quick_handle_fill_data
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // Save callee saves in case exception allocation triggers GC.
-    mov    x2, xSELF                       // Pass Thread::Current.
-    mov    x3, sp                          // Pass SP.
-    bl     artHandleFillArrayDataFromCode  // (Array*, const DexFile::Payload*, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    RETURN_IF_RESULT_IS_ZERO
-    DELIVER_PENDING_EXCEPTION
-END art_quick_handle_fill_data
-
-    /*
      * Entry from managed code that calls artLockObjectFromCode, may block for GC. x0 holds the
      * possibly null object to lock.
      *
@@ -960,7 +996,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]
@@ -981,14 +1017,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
 
@@ -1001,7 +1036,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]
@@ -1012,18 +1047,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
 
@@ -1073,8 +1107,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
 
@@ -1097,7 +1130,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
@@ -1107,16 +1140,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]
@@ -1124,7 +1157,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
@@ -1161,7 +1194,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]
@@ -1183,8 +1216,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
 
@@ -1192,13 +1224,11 @@
 .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
 .endm
 
@@ -1206,13 +1236,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  // 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
 .endm
 
@@ -1220,12 +1248,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
@@ -1233,12 +1260,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
@@ -1246,25 +1272,37 @@
 .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
 
+.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+    cbz w0, 1f                 // result zero branch over
+    ret                        // return
+1:
+    DELIVER_PENDING_EXCEPTION
+.endm
+
+    /*
+     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
+     * failure.
+     */
+TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
+
     /*
      * Entry from managed code when uninitialized static storage, this stub will run the class
      * initializer and deliver the exception on error. On success the static storage base is
      * returned.
      */
-TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 
-TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO
-TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 
 ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
 ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
@@ -1290,20 +1328,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
 
@@ -1313,7 +1350,7 @@
      * w1 holds the string index. The fast path check for hit in strings cache has already been
      * performed.
      */
-TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 
 // Generate the allocation entrypoints for each allocator.
 GENERATE_ALL_ALLOC_ENTRYPOINTS
@@ -1329,18 +1366,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
 
      /*
@@ -1350,19 +1385,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
 
@@ -1372,24 +1406,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
 
@@ -1447,9 +1481,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
@@ -1522,7 +1555,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
@@ -1532,7 +1565,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
@@ -1543,8 +1576,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() ???
@@ -1554,7 +1587,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
 
@@ -1567,19 +1600,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
@@ -1588,7 +1620,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
@@ -1611,7 +1643,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
@@ -1624,8 +1656,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
 
@@ -1640,9 +1671,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
@@ -1651,7 +1682,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 */
@@ -1745,12 +1776,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
@@ -1770,8 +1801,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/quick_method_frame_info_arm64.h b/runtime/arch/arm64/quick_method_frame_info_arm64.h
index 15c6c07..0e1e32b 100644
--- a/runtime/arch/arm64/quick_method_frame_info_arm64.h
+++ b/runtime/arch/arm64/quick_method_frame_info_arm64.h
@@ -54,7 +54,7 @@
     (1 << art::arm64::D0) | (1 << art::arm64::D1) | (1 << art::arm64::D2) |
     (1 << art::arm64::D3) | (1 << art::arm64::D4) | (1 << art::arm64::D5) |
     (1 << art::arm64::D6) | (1 << art::arm64::D7);
-static constexpr uint32_t kArm64FpAllSpills =
+static constexpr uint32_t kArm64CalleeSaveFpAllSpills =
     (1 << art::arm64::D8)  | (1 << art::arm64::D9)  | (1 << art::arm64::D10) |
     (1 << art::arm64::D11)  | (1 << art::arm64::D12)  | (1 << art::arm64::D13) |
     (1 << art::arm64::D14)  | (1 << art::arm64::D15);
@@ -68,7 +68,7 @@
 constexpr uint32_t Arm64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
   return kArm64CalleeSaveFpAlwaysSpills | kArm64CalleeSaveFpRefSpills |
       (type == Runtime::kRefsAndArgs ? kArm64CalleeSaveFpArgSpills: 0) |
-      (type == Runtime::kSaveAll ? kArm64FpAllSpills : 0);
+      (type == Runtime::kSaveAll ? kArm64CalleeSaveFpAllSpills : 0);
 }
 
 constexpr uint32_t Arm64CalleeSaveFrameSize(Runtime::CalleeSaveType type) {
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/context.cc b/runtime/arch/context.cc
index b1700bb..bf40a3f 100644
--- a/runtime/arch/context.cc
+++ b/runtime/arch/context.cc
@@ -20,8 +20,10 @@
 #include "arm/context_arm.h"
 #elif defined(__aarch64__)
 #include "arm64/context_arm64.h"
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 #include "mips/context_mips.h"
+#elif defined(__mips__) && defined(__LP64__)
+#include "mips64/context_mips64.h"
 #elif defined(__i386__)
 #include "x86/context_x86.h"
 #elif defined(__x86_64__)
@@ -37,8 +39,10 @@
   return new arm::ArmContext();
 #elif defined(__aarch64__)
   return new arm64::Arm64Context();
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
   return new mips::MipsContext();
+#elif defined(__mips__) && defined(__LP64__)
+  return new mips64::Mips64Context();
 #elif defined(__i386__)
   return new x86::X86Context();
 #elif defined(__x86_64__)
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
new file mode 100644
index 0000000..5ab461b
--- /dev/null
+++ b/runtime/arch/instruction_set.cc
@@ -0,0 +1,131 @@
+/*
+ * 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 "instruction_set.h"
+
+#include "globals.h"
+
+namespace art {
+
+const char* GetInstructionSetString(const InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return "arm";
+    case kArm64:
+      return "arm64";
+    case kX86:
+      return "x86";
+    case kX86_64:
+      return "x86_64";
+    case kMips:
+      return "mips";
+    case kMips64:
+      return "mips64";
+    case kNone:
+      return "none";
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+InstructionSet GetInstructionSetFromString(const char* isa_str) {
+  CHECK(isa_str != nullptr);
+
+  if (strcmp("arm", isa_str) == 0) {
+    return kArm;
+  } else if (strcmp("arm64", isa_str) == 0) {
+    return kArm64;
+  } else if (strcmp("x86", isa_str) == 0) {
+    return kX86;
+  } else if (strcmp("x86_64", isa_str) == 0) {
+    return kX86_64;
+  } else if (strcmp("mips", isa_str) == 0) {
+    return kMips;
+  } else if (strcmp("mips64", isa_str) == 0) {
+    return kMips64;
+  }
+
+  return kNone;
+}
+
+size_t GetInstructionSetAlignment(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return kArmAlignment;
+    case kArm64:
+      return kArm64Alignment;
+    case kX86:
+      // Fall-through.
+    case kX86_64:
+      return kX86Alignment;
+    case kMips:
+      // Fall-through.
+    case kMips64:
+      return kMipsAlignment;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have alignment.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
+static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+static constexpr size_t kMips64StackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+
+static constexpr size_t kArmStackOverflowReservedBytes =    8 * KB;
+static constexpr size_t kArm64StackOverflowReservedBytes =  8 * KB;
+static constexpr size_t kX86StackOverflowReservedBytes =    8 * KB;
+static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB;
+
+size_t GetStackOverflowReservedBytes(InstructionSet isa) {
+  switch (isa) {
+    case kArm:      // Intentional fall-through.
+    case kThumb2:
+      return kArmStackOverflowReservedBytes;
+
+    case kArm64:
+      return kArm64StackOverflowReservedBytes;
+
+    case kMips:
+      return kMipsStackOverflowReservedBytes;
+
+    case kMips64:
+      return kMips64StackOverflowReservedBytes;
+
+    case kX86:
+      return kX86StackOverflowReservedBytes;
+
+    case kX86_64:
+      return kX86_64StackOverflowReservedBytes;
+
+    case kNone:
+      LOG(FATAL) << "kNone has no stack overflow size";
+      UNREACHABLE();
+
+    default:
+      LOG(FATAL) << "Unknown instruction set" << isa;
+      UNREACHABLE();
+  }
+}
+
+}  // namespace art
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
new file mode 100644
index 0000000..9135e58
--- /dev/null
+++ b/runtime/arch/instruction_set.h
@@ -0,0 +1,253 @@
+/*
+ * 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_ARCH_INSTRUCTION_SET_H_
+#define ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/logging.h"  // Logging is required for FATAL in the helper functions.
+
+namespace art {
+
+enum InstructionSet {
+  kNone,
+  kArm,
+  kArm64,
+  kThumb2,
+  kX86,
+  kX86_64,
+  kMips,
+  kMips64
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
+
+#if defined(__arm__)
+static constexpr InstructionSet kRuntimeISA = kArm;
+#elif defined(__aarch64__)
+static constexpr InstructionSet kRuntimeISA = kArm64;
+#elif defined(__mips__) && !defined(__LP64__)
+static constexpr InstructionSet kRuntimeISA = kMips;
+#elif defined(__mips__) && defined(__LP64__)
+static constexpr InstructionSet kRuntimeISA = kMips64;
+#elif defined(__i386__)
+static constexpr InstructionSet kRuntimeISA = kX86;
+#elif defined(__x86_64__)
+static constexpr InstructionSet kRuntimeISA = kX86_64;
+#else
+static constexpr InstructionSet kRuntimeISA = kNone;
+#endif
+
+// Architecture-specific pointer sizes
+static constexpr size_t kArmPointerSize = 4;
+static constexpr size_t kArm64PointerSize = 8;
+static constexpr size_t kMipsPointerSize = 4;
+static constexpr size_t kMips64PointerSize = 8;
+static constexpr size_t kX86PointerSize = 4;
+static constexpr size_t kX86_64PointerSize = 8;
+
+// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
+// but ARM ELF requires 8..
+static constexpr size_t kArmAlignment = 8;
+
+// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
+static constexpr size_t kArm64Alignment = 16;
+
+// MIPS instruction alignment.  MIPS processors require code to be 4-byte aligned.
+// TODO: Can this be 4?
+static constexpr size_t kMipsAlignment = 8;
+
+// X86 instruction alignment. This is the recommended alignment for maximum performance.
+static constexpr size_t kX86Alignment = 16;
+
+
+const char* GetInstructionSetString(InstructionSet isa);
+
+// Note: Returns kNone when the string cannot be parsed to a known value.
+InstructionSet GetInstructionSetFromString(const char* instruction_set);
+
+static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return kArmPointerSize;
+    case kArm64:
+      return kArm64PointerSize;
+    case kX86:
+      return kX86PointerSize;
+    case kX86_64:
+      return kX86_64PointerSize;
+    case kMips:
+      return kMipsPointerSize;
+    case kMips64:
+      return kMips64PointerSize;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have pointer size.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+size_t GetInstructionSetAlignment(InstructionSet isa);
+
+static inline bool Is64BitInstructionSet(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+    case kX86:
+    case kMips:
+      return false;
+
+    case kArm64:
+    case kX86_64:
+    case kMips64:
+      return true;
+
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have bit width.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+static inline size_t InstructionSetPointerSize(InstructionSet isa) {
+  return Is64BitInstructionSet(isa) ? 8U : 4U;
+}
+
+static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return 4;
+    case kArm64:
+      return 8;
+    case kX86:
+      return 4;
+    case kX86_64:
+      return 8;
+    case kMips:
+      return 4;
+    case kMips64:
+      return 8;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have spills.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return 4;
+    case kArm64:
+      return 8;
+    case kX86:
+      return 8;
+    case kX86_64:
+      return 8;
+    case kMips:
+      return 4;
+    case kMips64:
+      return 8;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have spills.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+size_t GetStackOverflowReservedBytes(InstructionSet isa);
+
+// The following definitions create return types for two word-sized entities that will be passed
+// in registers so that memory operations for the interface trampolines can be avoided. The entities
+// are the resolved method and the pointer to the code to be invoked.
+//
+// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
+// uint64_t or long long int.
+//
+// On x86_64, ARM64 and MIPS64, structs are decomposed for allocation, so we can create a structs of
+// two size_t-sized values.
+//
+// We need two operations:
+//
+// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
+//    GetTwoWordFailureValue() will return a value that has lower part == 0.
+//
+// 2) A value that combines two word-sized values.
+//    GetTwoWordSuccessValue() constructs this.
+//
+// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
+//            that the object does not move or the value is updated. Simple use of this is NOT SAFE
+//            when the garbage collector can move objects concurrently. Ensure that required locks
+//            are held when using!
+
+#if defined(__i386__) || defined(__arm__) || (defined(__mips__) && !defined(__LP64__))
+typedef uint64_t TwoWordReturn;
+
+// Encodes method_ptr==nullptr and code_ptr==nullptr
+static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
+  return 0;
+}
+
+// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
+static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
+  static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
+  uint32_t lo32 = lo;
+  uint64_t hi64 = static_cast<uint64_t>(hi);
+  return ((hi64 << 32) | lo32);
+}
+
+#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__mips__) && defined(__LP64__))
+struct TwoWordReturn {
+  uintptr_t lo;
+  uintptr_t hi;
+};
+
+// Encodes method_ptr==nullptr. Leaves random value in code pointer.
+static inline TwoWordReturn GetTwoWordFailureValue() {
+  TwoWordReturn ret;
+  ret.lo = 0;
+  return ret;
+}
+
+// Write values into their respective members.
+static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
+  TwoWordReturn ret;
+  ret.lo = lo;
+  ret.hi = hi;
+  return ret;
+}
+#else
+#error "Unsupported architecture"
+#endif
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
new file mode 100644
index 0000000..1fd1dea
--- /dev/null
+++ b/runtime/arch/instruction_set_features.cc
@@ -0,0 +1,299 @@
+/*
+ * 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 "instruction_set_features.h"
+
+#include "base/casts.h"
+#include "utils.h"
+
+
+#include "arm/instruction_set_features_arm.h"
+#include "arm64/instruction_set_features_arm64.h"
+#include "mips/instruction_set_features_mips.h"
+#include "mips64/instruction_set_features_mips64.h"
+#include "x86/instruction_set_features_x86.h"
+#include "x86_64/instruction_set_features_x86_64.h"
+
+namespace art {
+
+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;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << isa;
+      UNREACHABLE();
+  }
+  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;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << isa;
+      UNREACHABLE();
+  }
+  CHECK_EQ(bitmap, result->AsBitmap());
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromCppDefines();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromCppDefines();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromCppDefines();
+      break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromCppDefines();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromCppDefines();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromCppDefines();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromCpuInfo();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromCpuInfo();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromCpuInfo();
+      break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromCpuInfo();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromCpuInfo();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromCpuInfo();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromHwcap();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromHwcap();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromHwcap();
+      break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromHwcap();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromHwcap();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromHwcap();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromAssembly();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromAssembly();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromAssembly();
+      break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromAssembly();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromAssembly();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromAssembly();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::AddFeaturesFromString(
+    const std::string& feature_list, std::string* error_msg) const {
+  if (feature_list.empty()) {
+    *error_msg = "No instruction set features specified";
+    return nullptr;
+  }
+  std::vector<std::string> features;
+  Split(feature_list, ',', &features);
+  bool smp = smp_;
+  bool use_default = false;  // Have we seen the 'default' feature?
+  bool first = false;  // Is this first feature?
+  for (auto it = features.begin(); it != features.end();) {
+    if (use_default) {
+      *error_msg = "Unexpected instruction set features after 'default'";
+      return nullptr;
+    }
+    std::string feature = Trim(*it);
+    bool erase = false;
+    if (feature == "default") {
+      if (!first) {
+        use_default = true;
+        erase = true;
+      } else {
+        *error_msg = "Unexpected instruction set features before 'default'";
+        return nullptr;
+      }
+    } else if (feature == "smp") {
+      smp = true;
+      erase = true;
+    } else if (feature == "-smp") {
+      smp = false;
+      erase = true;
+    }
+    // Erase the smp feature once processed.
+    if (!erase) {
+      ++it;
+    } else {
+      it = features.erase(it);
+    }
+    first = true;
+  }
+  DCHECK_EQ(use_default, features.empty());
+  return AddFeaturesFromSplitString(smp, features, error_msg);
+}
+
+const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
+  DCHECK_EQ(kArm, GetInstructionSet());
+  return down_cast<const ArmInstructionSetFeatures*>(this);
+}
+
+const Arm64InstructionSetFeatures* InstructionSetFeatures::AsArm64InstructionSetFeatures() const {
+  DCHECK_EQ(kArm64, GetInstructionSet());
+  return down_cast<const Arm64InstructionSetFeatures*>(this);
+}
+
+const MipsInstructionSetFeatures* InstructionSetFeatures::AsMipsInstructionSetFeatures() const {
+  DCHECK_EQ(kMips, GetInstructionSet());
+  return down_cast<const MipsInstructionSetFeatures*>(this);
+}
+
+const Mips64InstructionSetFeatures* InstructionSetFeatures::AsMips64InstructionSetFeatures() const {
+  DCHECK_EQ(kMips64, GetInstructionSet());
+  return down_cast<const Mips64InstructionSetFeatures*>(this);
+}
+
+const X86InstructionSetFeatures* InstructionSetFeatures::AsX86InstructionSetFeatures() const {
+  DCHECK(kX86 == GetInstructionSet() || kX86_64 == GetInstructionSet());
+  return down_cast<const X86InstructionSetFeatures*>(this);
+}
+
+const X86_64InstructionSetFeatures* InstructionSetFeatures::AsX86_64InstructionSetFeatures() const {
+  DCHECK_EQ(kX86_64, GetInstructionSet());
+  return down_cast<const X86_64InstructionSetFeatures*>(this);
+}
+
+bool InstructionSetFeatures::FindVariantInArray(const char* variants[], size_t num_variants,
+                                                const std::string& variant) {
+  const char** begin = variants;
+  const char** end = begin + num_variants;
+  return std::find(begin, end, variant) != end;
+}
+
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
+  os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
+  return os;
+}
+
+}  // namespace art
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
new file mode 100644
index 0000000..e4513ef
--- /dev/null
+++ b/runtime/arch/instruction_set_features.h
@@ -0,0 +1,123 @@
+/*
+ * 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_ARCH_INSTRUCTION_SET_FEATURES_H_
+#define ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
+
+#include <ostream>
+#include <vector>
+
+#include "base/macros.h"
+#include "instruction_set.h"
+
+namespace art {
+
+class ArmInstructionSetFeatures;
+class Arm64InstructionSetFeatures;
+class MipsInstructionSetFeatures;
+class Mips64InstructionSetFeatures;
+class X86InstructionSetFeatures;
+class X86_64InstructionSetFeatures;
+
+// Abstraction used to describe features of a different instruction sets.
+class InstructionSetFeatures {
+ public:
+  // 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);
+
+  // Parse a bitmap for the given isa and create an InstructionSetFeatures.
+  static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
+  static const InstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const InstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const InstructionSetFeatures* 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 InstructionSetFeatures* FromAssembly();
+
+  // Parse a string of the form "div,-atomic_ldrd_strd" adding and removing these features to
+  // create a new InstructionSetFeatures.
+  const InstructionSetFeatures* AddFeaturesFromString(const std::string& feature_list,
+                                                      std::string* error_msg) const WARN_UNUSED;
+
+  // Are these features the same as the other given features?
+  virtual bool Equals(const InstructionSetFeatures* other) const = 0;
+
+  // Return the ISA these features relate to.
+  virtual InstructionSet GetInstructionSet() const = 0;
+
+  // Return a bitmap that represents the features. ISA specific.
+  virtual uint32_t AsBitmap() const = 0;
+
+  // Return a string of the form "div,lpae" or "none".
+  virtual std::string GetFeatureString() const = 0;
+
+  // Does the instruction set variant require instructions for correctness with SMP?
+  bool IsSmp() const {
+    return smp_;
+  }
+
+  // Down cast this ArmInstructionFeatures.
+  const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
+
+  // Down cast this Arm64InstructionFeatures.
+  const Arm64InstructionSetFeatures* AsArm64InstructionSetFeatures() const;
+
+  // Down cast this MipsInstructionFeatures.
+  const MipsInstructionSetFeatures* AsMipsInstructionSetFeatures() const;
+
+  // Down cast this Mips64InstructionFeatures.
+  const Mips64InstructionSetFeatures* AsMips64InstructionSetFeatures() const;
+
+  // Down cast this X86InstructionFeatures.
+  const X86InstructionSetFeatures* AsX86InstructionSetFeatures() const;
+
+  // Down cast this X86_64InstructionFeatures.
+  const X86_64InstructionSetFeatures* AsX86_64InstructionSetFeatures() const;
+
+  virtual ~InstructionSetFeatures() {}
+
+ protected:
+  explicit InstructionSetFeatures(bool smp) : smp_(smp) {}
+
+  // Returns true if variant appears in the array variants.
+  static bool FindVariantInArray(const char* variants[], size_t num_variants,
+                                 const std::string& variant);
+
+  // Add architecture specific features in sub-classes.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const = 0;
+
+ private:
+  const bool smp_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
new file mode 100644
index 0000000..e6f4e7a
--- /dev/null
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -0,0 +1,160 @@
+/*
+ * 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 "instruction_set_features.h"
+
+#include <gtest/gtest.h>
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+#endif
+
+#include "base/stringprintf.h"
+
+namespace art {
+
+#ifdef HAVE_ANDROID_OS
+#if defined(__aarch64__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyVariant) {
+  LOG(WARNING) << "Test disabled due to no CPP define for A53 erratum 835769";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyVariant) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Read the variant 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();
+  }
+}
+
+#if defined(__aarch64__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyString) {
+  LOG(WARNING) << "Test disabled due to no CPP define for A53 erratum 835769";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyString) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Read the variant property.
+  std::string variant_key = StringPrintf("dalvik.vm.isa.%s.variant",
+                                         GetInstructionSetString(kRuntimeISA));
+  char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
+  if (property_get(variant_key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+    // Read the features property.
+    std::string features_key = StringPrintf("dalvik.vm.isa.%s.features",
+                                            GetInstructionSetString(kRuntimeISA));
+    char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+    if (property_get(features_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> base_features(
+          InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
+      ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+      std::unique_ptr<const InstructionSetFeatures> property_features(
+          base_features->AddFeaturesFromString(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();
+    }
+  }
+}
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromCpuInfo) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, 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();
+}
+#endif
+
+#ifndef HAVE_ANDROID_OS
+TEST(InstructionSetFeaturesTest, HostFeaturesFromCppDefines) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> default_features(
+      InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
+  ASSERT_TRUE(error_msg.empty());
+
+  std::unique_ptr<const InstructionSetFeatures> cpp_features(
+      InstructionSetFeatures::FromCppDefines());
+  EXPECT_TRUE(default_features->Equals(cpp_features.get()))
+      << "Default variant features: " << *default_features.get()
+      << "\nFeatures from build: " << *cpp_features.get();
+}
+#endif
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromHwcap) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, 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();
+}
+
+TEST(InstructionSetFeaturesTest, FeaturesFromAssembly) {
+  // 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/arch/instruction_set_test.cc b/runtime/arch/instruction_set_test.cc
new file mode 100644
index 0000000..2f3cf18
--- /dev/null
+++ b/runtime/arch/instruction_set_test.cc
@@ -0,0 +1,55 @@
+/*
+ * 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 "instruction_set.h"
+
+#include <gtest/gtest.h>
+
+#include "base/stringprintf.h"
+
+namespace art {
+
+TEST(InstructionSetTest, GetInstructionSetFromString) {
+  EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
+  EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
+  EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
+  EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
+  EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
+  EXPECT_EQ(kMips64, GetInstructionSetFromString("mips64"));
+  EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
+  EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
+}
+
+TEST(InstructionSetTest, GetInstructionSetString) {
+  EXPECT_STREQ("arm", GetInstructionSetString(kArm));
+  EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
+  EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
+  EXPECT_STREQ("x86", GetInstructionSetString(kX86));
+  EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
+  EXPECT_STREQ("mips", GetInstructionSetString(kMips));
+  EXPECT_STREQ("mips64", GetInstructionSetString(kMips64));
+  EXPECT_STREQ("none", GetInstructionSetString(kNone));
+}
+
+TEST(InstructionSetTest, TestRoundTrip) {
+  EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
+}
+
+TEST(InstructionSetTest, PointerSize) {
+  EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
+}
+
+}  // namespace art
diff --git a/runtime/arch/memcmp16.cc b/runtime/arch/memcmp16.cc
index 5a3e73e..813df2f 100644
--- a/runtime/arch/memcmp16.cc
+++ b/runtime/arch/memcmp16.cc
@@ -19,6 +19,7 @@
 // This linked against by assembly stubs, only.
 #pragma GCC diagnostic ignored "-Wunused-function"
 
+int32_t memcmp16_generic_static(const uint16_t* s0, const uint16_t* s1, size_t count);
 int32_t memcmp16_generic_static(const uint16_t* s0, const uint16_t* s1, size_t count) {
   for (size_t i = 0; i < count; i++) {
     if (s0[i] != s1[i]) {
diff --git a/runtime/arch/memcmp16.h b/runtime/arch/memcmp16.h
index 4b9fb8e..c449a14 100644
--- a/runtime/arch/memcmp16.h
+++ b/runtime/arch/memcmp16.h
@@ -30,7 +30,7 @@
 //
 // In both cases, MemCmp16 is declared.
 
-#if defined(__aarch64__) || defined(__arm__) || defined(__mips) || defined(__i386__) || defined(__x86_64__)
+#if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || defined(__i386__) || defined(__x86_64__)
 
 extern "C" uint32_t __memcmp16(const uint16_t* s0, const uint16_t* s1, size_t count);
 #define MemCmp16 __memcmp16
diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S
index d8ec9cd..eea6537 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
@@ -55,5 +66,54 @@
     END \name
 .endm
 
+#if defined(__mips_isa_rev) && __mips_isa_rev > 2
+  /* mips32r5 & mips32r6 have mthc1 op, and have 64-bit fp regs,
+     and in FPXX abi we avoid referring to odd-numbered fp regs */
+
+/* LDu: Load 64-bit floating-point value to float reg feven,
+   from unaligned (mod-4-aligned) mem location disp(base) */
+.macro LDu feven,fodd,disp,base,temp
+  l.s   \feven, \disp(\base)
+  lw    \temp, \disp+4(\base)
+  mthc1 \temp, \feven
+.endm
+
+/* SDu: Store 64-bit floating-point value from float reg feven,
+   to unaligned (mod-4-aligned) mem location disp(base) */
+.macro SDu feven,fodd,disp,base,temp
+  mfhc1 \temp, \feven
+  s.s   \feven, \disp(\base)
+  sw    \temp, \disp+4(\base)
+.endm
+
+/* MTD: Move double, from general regpair (reven,rodd)
+        to float regpair (feven,fodd) */
+.macro MTD reven,rodd,feven,fodd
+  mtc1  \reven, \feven
+  mthc1 \rodd, \feven
+.endm
+
+#else
+  /* mips32r1 has no mthc1 op;
+     mips32r1 and mips32r2 use 32-bit floating point register mode (FR=0),
+     and always hold doubles as (feven, fodd) fp reg pair */
+
+.macro LDu feven,fodd,disp,base,temp
+  l.s   \feven, \disp(\base)
+  l.s   \fodd,  \disp+4(\base)
+.endm
+
+.macro SDu feven,fodd,disp,base,temp
+  s.s   \feven, \disp(\base)
+  s.s   \fodd,  \disp+4(\base)
+.endm
+
+.macro MTD reven,rodd,feven,fodd
+  mtc1  \reven, \feven
+  mtc1  \rodd, \fodd
+.endm
+
+#endif  /* mips_isa_rev */
+
 
 #endif  // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 6add93b..02c0982 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_SAVE_ALL_CALLEE_SAVE 48
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 48
 #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/context_mips.cc b/runtime/arch/mips/context_mips.cc
index 789dbbb..e1f6c06 100644
--- a/runtime/arch/mips/context_mips.cc
+++ b/runtime/arch/mips/context_mips.cc
@@ -17,9 +17,8 @@
 #include "context_mips.h"
 
 #include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
 #include "quick/quick_method_frame_info.h"
-#include "stack.h"
+#include "utils.h"
 
 namespace art {
 namespace mips {
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 25e911d..1a661c4 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -14,75 +14,22 @@
  * 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"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/quick/quick_default_externs.h"
 #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*);
-
 // Cast entrypoints.
 extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
                                             const mirror::Class* ref_class);
-extern "C" void art_quick_check_cast(void*, void*);
-
-// DexCache entrypoints.
-extern "C" void* art_quick_initialize_static_storage(uint32_t, void*);
-extern "C" void* art_quick_initialize_type(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, void*);
-extern "C" void* art_quick_resolve_string(void*, uint32_t);
-
-// Field entrypoints.
-extern "C" int art_quick_set8_instance(uint32_t, void*, int8_t);
-extern "C" int art_quick_set8_static(uint32_t, int8_t);
-extern "C" int art_quick_set16_instance(uint32_t, void*, int16_t);
-extern "C" int art_quick_set16_static(uint32_t, int16_t);
-extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t);
-extern "C" int art_quick_set32_static(uint32_t, int32_t);
-extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t);
-extern "C" int art_quick_set64_static(uint32_t, int64_t);
-extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*);
-extern "C" int art_quick_set_obj_static(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_instance(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_instance(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_static(uint32_t);
-extern "C" int8_t art_quick_get_byte_static(uint32_t);
-extern "C" uint16_t art_quick_get_char_instance(uint32_t, void*);
-extern "C" int16_t art_quick_get_short_instance(uint32_t, void*);
-extern "C" uint16_t art_quick_get_char_static(uint32_t);
-extern "C" int16_t art_quick_get_short_static(uint32_t);
-extern "C" int32_t art_quick_get32_instance(uint32_t, void*);
-extern "C" int32_t art_quick_get32_static(uint32_t);
-extern "C" int64_t art_quick_get64_instance(uint32_t, void*);
-extern "C" int64_t art_quick_get64_static(uint32_t);
-extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
-extern "C" void* art_quick_get_obj_static(uint32_t);
-
-// Array entrypoints.
-extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
-extern "C" void art_quick_handle_fill_data(void*, void*);
-
-// Lock entrypoints.
-extern "C" void art_quick_lock_object(void*);
-extern "C" void art_quick_unlock_object(void*);
 
 // Math entrypoints.
 extern int32_t CmpgDouble(double a, double b);
@@ -110,42 +57,9 @@
 // Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR]
 extern "C" int64_t __divdi3(int64_t, int64_t);
 extern "C" int64_t __moddi3(int64_t, int64_t);
-extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
-
-// Intrinsic entrypoints.
-extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
-extern "C" int32_t art_quick_string_compareto(void*, void*);
-
-// Invoke entrypoints.
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-
-// Thread entrypoints.
-extern "C" void art_quick_test_suspend();
-
-// Throw entrypoints.
-extern "C" void art_quick_deliver_exception(void*);
-extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
-extern "C" void art_quick_throw_div_zero();
-extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
-extern "C" void art_quick_throw_null_pointer_exception();
-extern "C" void art_quick_throw_stack_overflow(void*);
-
-// Generic JNI downcall
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-
-extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
-                     PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
+                     QuickEntryPoints* qpoints) {
   // Interpreter
   ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge;
   ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge;
@@ -153,10 +67,6 @@
   // JNI
   jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
 
-  // Portable
-  ppoints->pPortableResolutionTrampoline = art_portable_resolution_trampoline;
-  ppoints->pPortableToInterpreterBridge = art_portable_to_interpreter_bridge;
-
   // Alloc
   ResetQuickAllocEntryPoints(qpoints);
 
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index aa6d68a..c9949d4 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -29,23 +29,29 @@
 
 namespace art {
 
-void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                      void* context ATTRIBUTE_UNUSED) {
 }
 
-void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
-                                             mirror::ArtMethod** out_method,
-                                             uintptr_t* out_return_pc, uintptr_t* out_sp) {
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED,
+                                             void* context ATTRIBUTE_UNUSED,
+                                             mirror::ArtMethod** out_method ATTRIBUTE_UNUSED,
+                                             uintptr_t* out_return_pc ATTRIBUTE_UNUSED,
+                                             uintptr_t* out_sp ATTRIBUTE_UNUSED) {
 }
 
-bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
+bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                void* context ATTRIBUTE_UNUSED) {
   return false;
 }
 
-bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
+bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                               void* context ATTRIBUTE_UNUSED) {
   return false;
 }
 
-bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
+bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                  void* context ATTRIBUTE_UNUSED) {
   return false;
 }
 }       // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
new file mode 100644
index 0000000..00ab613
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -0,0 +1,203 @@
+/*
+ * 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 "instruction_set_features_mips.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromVariant(
+    const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
+
+  bool smp = true;  // Conservative default.
+  bool fpu_32bit = true;
+  bool mips_isa_gte2 = false;
+  bool r6 = false;
+
+  // Override defaults based on variant string.
+  // Only care if it is R1, R2 or R6 and we assume all CPUs will have a FP unit.
+  constexpr const char* kMips32Prefix = "mips32r";
+  const size_t kPrefixLength = strlen(kMips32Prefix);
+  if (variant.compare(0, kPrefixLength, kMips32Prefix, kPrefixLength) == 0 &&
+      variant.size() > kPrefixLength) {
+    if (variant[kPrefixLength] >= '6') {
+      fpu_32bit = false;
+      r6 = true;
+    }
+    if (variant[kPrefixLength] >= '2') {
+      mips_isa_gte2 = true;
+    }
+  } else if (variant == "default") {
+    // Default variant is: smp = true, has fpu, is gte2, is not r6. This is the traditional
+    // setting.
+    mips_isa_gte2 = true;
+  } else {
+    LOG(WARNING) << "Unexpected CPU variant for Mips32 using defaults: " << variant;
+  }
+
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0;
+  bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0;
+  bool r6 = (bitmap & kR6) != 0;
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCppDefines() {
+  // Assume conservative defaults.
+  const bool smp = true;
+  bool fpu_32bit = true;
+  bool mips_isa_gte2 = false;
+  bool r6 = false;
+
+  // Override defaults based on compiler flags.
+#if (_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS32R5) || defined(_MIPS_ARCH_MIPS32R6)
+  mips_isa_gte2 = true;
+#endif
+
+#if defined(_MIPS_ARCH_MIPS32R6)
+  r6 = true;
+  fpu_32bit = false;
+#endif
+
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::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.
+  // Assume conservative defaults.
+  bool smp = false;
+  bool fpu_32bit = true;
+  bool mips_isa_gte2 = false;
+  bool r6 = false;
+
+  // Override defaults based on compiler flags.
+#if (_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_MIPS32R5) || defined(_MIPS_ARCH_MIPS32R6)
+  mips_isa_gte2 = true;
+#endif
+
+#if defined(_MIPS_ARCH_MIPS32R6)
+  r6 = true;
+  fpu_32bit = false;
+#endif
+
+  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("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromHwcap() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromAssembly() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+bool MipsInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kMips != other->GetInstructionSet()) {
+    return false;
+  }
+  const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures();
+  return (IsSmp() == other->IsSmp()) &&
+      (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
+      (mips_isa_gte2_ == other_as_mips->mips_isa_gte2_) &&
+      (r6_ == other_as_mips->r6_);
+}
+
+uint32_t MipsInstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) |
+      (fpu_32bit_ ? kFpu32Bitfield : 0) |
+      (mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0) |
+      (r6_ ? kR6 : 0);
+}
+
+std::string MipsInstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (fpu_32bit_) {
+    result += ",fpu32";
+  } else {
+    result += ",-fpu32";
+  }
+  if (mips_isa_gte2_) {
+    result += ",mips2";
+  } else {
+    result += ",-mips2";
+  }
+  if (r6_) {
+    result += ",r6";
+  }  // Suppress non-r6.
+  return result;
+}
+
+const InstructionSetFeatures* MipsInstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  bool fpu_32bit = fpu_32bit_;
+  bool mips_isa_gte2 = mips_isa_gte2_;
+  bool r6 = r6_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "fpu32") {
+      fpu_32bit = true;
+    } else if (feature == "-fpu32") {
+      fpu_32bit = false;
+    } else if (feature == "mips2") {
+      mips_isa_gte2 = true;
+    } else if (feature == "-mips2") {
+      mips_isa_gte2 = false;
+    } else if (feature == "r6") {
+      r6 = true;
+    } else if (feature == "-r6") {
+      r6 = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2, r6);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
new file mode 100644
index 0000000..aac436e
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -0,0 +1,104 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+#define ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the MIPS architecture.
+class MipsInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "r4000" and create InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const MipsInstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* 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 MipsInstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kMips;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  std::string GetFeatureString() const OVERRIDE;
+
+  // Is this an ISA revision greater than 2 opening up new opcodes.
+  bool IsMipsIsaRevGreaterThanEqual2() const {
+    return mips_isa_gte2_;
+  }
+
+  // Floating point double registers are encoded differently based on whether the Status.FR bit is
+  // set. When the FR bit is 0 then the FPU is 32-bit, 1 its 64-bit. Return true if the code should
+  // be generated assuming Status.FR is 0.
+  bool Is32BitFloatingPoint() const {
+    return fpu_32bit_;
+  }
+
+  bool IsR6() const {
+    return r6_;
+  }
+
+  virtual ~MipsInstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "fpu32", "mips2" adding these to a new MipsInstructionSetFeatures.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  MipsInstructionSetFeatures(bool smp, bool fpu_32bit, bool mips_isa_gte2, bool r6)
+      : InstructionSetFeatures(smp), fpu_32bit_(fpu_32bit),  mips_isa_gte2_(mips_isa_gte2), r6_(r6)
+  {}
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kFpu32Bitfield = 2,
+    kIsaRevGte2Bitfield = 4,
+    kR6 = 8,
+  };
+
+  const bool fpu_32bit_;
+  const bool mips_isa_gte2_;
+  const bool r6_;
+
+  DISALLOW_COPY_AND_ASSIGN(MipsInstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
diff --git a/runtime/arch/mips/instruction_set_features_mips_test.cc b/runtime/arch/mips/instruction_set_features_mips_test.cc
new file mode 100644
index 0000000..9b81ce2
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips_test.cc
@@ -0,0 +1,34 @@
+/*
+ * 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 "instruction_set_features_mips.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(MipsInstructionSetFeaturesTest, MipsFeatures) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> mips_features(
+      InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+  ASSERT_TRUE(mips_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(mips_features->GetInstructionSet(), kMips);
+  EXPECT_TRUE(mips_features->Equals(mips_features.get()));
+  EXPECT_STREQ("smp,fpu32,mips2", mips_features->GetFeatureString().c_str());
+  EXPECT_EQ(mips_features->AsBitmap(), 7U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips/jni_entrypoints_mips.S b/runtime/arch/mips/jni_entrypoints_mips.S
index e5f4a79..fbc81d5 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)
@@ -48,9 +47,9 @@
     addiu $sp, $sp, 32          # restore the stack
     .cfi_adjust_cfa_offset -32
     move  $t9, $v0              # put method code result in $t9
-    jr    $t9                   # leaf call to method's code
+    jalr  $zero, $t9            # leaf call to method's code
     nop
 .Lno_native_code_found:
-    jr    $ra
+    jalr  $zero, $ra
     nop
 END art_jni_dlsym_lookup_stub
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
deleted file mode 100644
index 7545ce0..0000000
--- a/runtime/arch/mips/portable_entrypoints_mips.S
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "asm_support_mips.S"
-
-    .set noreorder
-    .balign 4
-
-    .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
-    .cfi_adjust_cfa_offset 64
-    sw     $ra, 60($sp)
-    .cfi_rel_offset 31, 60
-    sw     $s8, 56($sp)
-    .cfi_rel_offset 30, 56
-    sw     $gp, 52($sp)
-    .cfi_rel_offset 28, 52
-    sw     $s7, 48($sp)
-    .cfi_rel_offset 23, 48
-    sw     $s6, 44($sp)
-    .cfi_rel_offset 22, 44
-    sw     $s5, 40($sp)
-    .cfi_rel_offset 21, 40
-    sw     $s4, 36($sp)
-    .cfi_rel_offset 20, 36
-    sw     $s3, 32($sp)
-    .cfi_rel_offset 19, 32
-    sw     $s2, 28($sp)
-    .cfi_rel_offset 18, 28
-    sw     $a3, 12($sp)
-    .cfi_rel_offset 7, 12
-    sw     $a2, 8($sp)
-    .cfi_rel_offset 6, 8
-    sw     $a1, 4($sp)
-    .cfi_rel_offset 5, 4
-    # Begin argument set up.
-    sw      $a0, 0($sp)            # place proxy method at bottom of frame
-    move    $a2, rSELF             # pass Thread::Current
-    jal     artPortableProxyInvokeHandler  # (Method* proxy method, receiver, Thread*, SP)
-    move    $a3, $sp               # pass $sp
-    lw      $ra, 60($sp)           # restore $ra
-    jr      $ra
-    addiu   $sp, $sp, 64           # pop frame
-    .cfi_adjust_cfa_offset -64
-END art_portable_proxy_invoke_handler
-
-    /*
-     * Invocation stub for portable code.
-     * On entry:
-     *   a0 = method pointer
-     *   a1 = argument array or NULL for no argument methods
-     *   a2 = size of argument array in bytes
-     *   a3 = (managed) thread pointer
-     *   [sp + 16] = JValue* result
-     *   [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
-    sw    $ra, 12($sp)
-    .cfi_rel_offset 31, 12
-    sw    $fp, 8($sp)
-    .cfi_rel_offset 30, 8
-    sw    $s1, 4($sp)
-    .cfi_rel_offset 17, 4
-    sw    $s0, 0($sp)
-    .cfi_rel_offset 16, 0
-    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 $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
-    subu  $sp, $sp, $t0         # reserve stack space for argument array
-    addiu $a0, $sp, 4           # pass stack pointer + method ptr as dest for memcpy
-    jal   memcpy                # (dest, src, bytes)
-    addiu $sp, $sp, -16         # make space for argument slots for memcpy
-    addiu $sp, $sp, 16          # restore stack after memcpy
-    lw    $a0, 16($fp)          # restore method*
-    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
-    jalr  $t9                   # call the method
-    sw    $zero, 0($sp)         # store NULL for method* at bottom of frame
-    move  $sp, $fp              # restore the stack
-    lw    $s0, 0($sp)
-    .cfi_restore 16
-    lw    $s1, 4($sp)
-    .cfi_restore 17
-    lw    $fp, 8($sp)
-    .cfi_restore 30
-    lw    $ra, 12($sp)
-    .cfi_restore 31
-    addiu $sp, $sp, 16
-    .cfi_adjust_cfa_offset -16
-    lw    $t0, 16($sp)          # get result pointer
-    lw    $t1, 20($sp)          # get result type char
-    li    $t2, 68               # put char 'D' into t2
-    beq   $t1, $t2, 1f          # branch if result type char == 'D'
-    li    $t3, 70               # put char 'F' into t3
-    beq   $t1, $t3, 1f          # branch if result type char == 'F'
-    sw    $v0, 0($t0)           # store the result
-    jr    $ra
-    sw    $v1, 4($t0)           # store the other half of the result
-1:
-    s.s   $f0, 0($t0)           # store floating point result
-    jr    $ra
-    s.s   $f1, 4($t0)           # store other half of floating point result
-END art_portable_invoke_stub
-
-UNIMPLEMENTED art_portable_resolution_trampoline
-UNIMPLEMENTED art_portable_to_interpreter_bridge
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 9e9e523..df2feb7 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -26,134 +26,144 @@
     /* Deliver an exception pending on a thread */
     .extern artDeliverPendingExceptionFromCode
 
+#define ARG_SLOT_SIZE   32    // space for a0-a3 plus 4 more words
+
     /*
      * 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 for Method*
+     * Clobbers $t0 and $sp
+     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
+     * Reserves FRAME_SIZE_SAVE_ALL_CALLEE_SAVE + ARG_SLOT_SIZE bytes on the stack
      */
 .macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    addiu  $sp, $sp, -64
-    .cfi_adjust_cfa_offset 64
+    addiu  $sp, $sp, -48
+    .cfi_adjust_cfa_offset 48
 
      // Ugly compile-time check, but we only have the preprocessor.
-#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 64)
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 48)
 #error "SAVE_ALL_CALLEE_SAVE_FRAME(MIPS) size not as expected."
 #endif
 
-    sw     $ra, 60($sp)
-    .cfi_rel_offset 31, 60
-    sw     $s8, 56($sp)
-    .cfi_rel_offset 30, 56
-    sw     $gp, 52($sp)
-    .cfi_rel_offset 28, 52
-    sw     $s7, 48($sp)
-    .cfi_rel_offset 23, 48
-    sw     $s6, 44($sp)
-    .cfi_rel_offset 22, 44
-    sw     $s5, 40($sp)
-    .cfi_rel_offset 21, 40
-    sw     $s4, 36($sp)
-    .cfi_rel_offset 20, 36
-    sw     $s3, 32($sp)
-    .cfi_rel_offset 19, 32
-    sw     $s2, 28($sp)
-    .cfi_rel_offset 18, 28
-    sw     $s1, 24($sp)
-    .cfi_rel_offset 17, 24
-    sw     $s0, 20($sp)
-    .cfi_rel_offset 16, 20
-    # 1 word for alignment, 4 open words for args $a0-$a3, bottom will hold Method*
+    sw     $ra, 44($sp)
+    .cfi_rel_offset 31, 44
+    sw     $s8, 40($sp)
+    .cfi_rel_offset 30, 40
+    sw     $gp, 36($sp)
+    .cfi_rel_offset 28, 36
+    sw     $s7, 32($sp)
+    .cfi_rel_offset 23, 32
+    sw     $s6, 28($sp)
+    .cfi_rel_offset 22, 28
+    sw     $s5, 24($sp)
+    .cfi_rel_offset 21, 24
+    sw     $s4, 20($sp)
+    .cfi_rel_offset 20, 20
+    sw     $s3, 16($sp)
+    .cfi_rel_offset 19, 16
+    sw     $s2, 12($sp)
+    .cfi_rel_offset 18, 12
+    sw     $s1, 8($sp)
+    .cfi_rel_offset 17, 8
+    sw     $s0, 4($sp)
+    .cfi_rel_offset 16, 4
+    # 1 word for holding Method*
+
+    lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
+    lw $t0, 0($t0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    lw $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.
+    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
+    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
 .endm
 
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes non-moving GC.
      * Does not include rSUSPEND or rSELF
-     * callee-save: $s2-$s8 + $gp + $ra, 9 total + 3 words padding + 4 open words for args
+     * callee-save: $s2-$s8 + $gp + $ra, 9 total + 2 words padding + 1 word to hold Method*
+     * Clobbers $t0 and $sp
+     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
+     * Reserves FRAME_SIZE_REFS_ONLY_CALLEE_SAVE + ARG_SLOT_SIZE bytes on the stack
      */
-.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-    addiu  $sp, $sp, -64
-    .cfi_adjust_cfa_offset 64
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+    addiu  $sp, $sp, -48
+    .cfi_adjust_cfa_offset 48
 
     // Ugly compile-time check, but we only have the preprocessor.
-#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 64)
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 48)
 #error "REFS_ONLY_CALLEE_SAVE_FRAME(MIPS) size not as expected."
 #endif
 
-    sw     $ra, 60($sp)
-    .cfi_rel_offset 31, 60
-    sw     $s8, 56($sp)
-    .cfi_rel_offset 30, 56
-    sw     $gp, 52($sp)
-    .cfi_rel_offset 28, 52
-    sw     $s7, 48($sp)
-    .cfi_rel_offset 23, 48
-    sw     $s6, 44($sp)
-    .cfi_rel_offset 22, 44
-    sw     $s5, 40($sp)
-    .cfi_rel_offset 21, 40
-    sw     $s4, 36($sp)
-    .cfi_rel_offset 20, 36
-    sw     $s3, 32($sp)
-    .cfi_rel_offset 19, 32
-    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*
+    sw     $ra, 44($sp)
+    .cfi_rel_offset 31, 44
+    sw     $s8, 40($sp)
+    .cfi_rel_offset 30, 40
+    sw     $gp, 36($sp)
+    .cfi_rel_offset 28, 36
+    sw     $s7, 32($sp)
+    .cfi_rel_offset 23, 32
+    sw     $s6, 28($sp)
+    .cfi_rel_offset 22, 28
+    sw     $s5, 24($sp)
+    .cfi_rel_offset 21, 24
+    sw     $s4, 20($sp)
+    .cfi_rel_offset 20, 20
+    sw     $s3, 16($sp)
+    .cfi_rel_offset 19, 16
+    sw     $s2, 12($sp)
+    .cfi_rel_offset 18, 12
+    # 2 words for alignment and bottom word will hold Method*
+
+    lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
+    lw $t0, 0($t0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    lw $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.
+    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
+    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    lw     $ra, 60($sp)
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
+    .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
+    lw     $ra, 44($sp)
     .cfi_restore 31
-    lw     $s8, 56($sp)
+    lw     $s8, 40($sp)
     .cfi_restore 30
-    lw     $gp, 52($sp)
+    lw     $gp, 36($sp)
     .cfi_restore 28
-    lw     $s7, 48($sp)
+    lw     $s7, 32($sp)
     .cfi_restore 23
-    lw     $s6, 44($sp)
+    lw     $s6, 28($sp)
     .cfi_restore 22
-    lw     $s5, 40($sp)
+    lw     $s5, 24($sp)
     .cfi_restore 21
-    lw     $s4, 36($sp)
+    lw     $s4, 20($sp)
     .cfi_restore 20
-    lw     $s3, 32($sp)
+    lw     $s3, 16($sp)
     .cfi_restore 19
-    lw     $s2, 28($sp)
+    lw     $s2, 12($sp)
     .cfi_restore 18
-    addiu  $sp, $sp, 64
-    .cfi_adjust_cfa_offset -64
+    addiu  $sp, $sp, 48
+    .cfi_adjust_cfa_offset -48
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
-    lw     $ra, 60($sp)
-    .cfi_restore 31
-    lw     $s8, 56($sp)
-    .cfi_restore 30
-    lw     $gp, 52($sp)
-    .cfi_restore 28
-    lw     $s7, 48($sp)
-    .cfi_restore 23
-    lw     $s6, 44($sp)
-    .cfi_restore 22
-    lw     $s5, 40($sp)
-    .cfi_restore 21
-    lw     $s4, 36($sp)
-    .cfi_restore 20
-    lw     $s3, 32($sp)
-    .cfi_restore 19
-    lw     $s2, 28($sp)
-    .cfi_restore 18
-    jr     $ra
-    addiu  $sp, $sp, 64
-    .cfi_adjust_cfa_offset -64
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    jalr   $zero, $ra
+    nop
 .endm
 
     /*
      * Macro that sets up the callee save frame to conform with
-     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC.
+     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs).
      * 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_REGISTERS_ONLY
     addiu  $sp, $sp, -64
     .cfi_adjust_cfa_offset 64
 
@@ -180,16 +190,55 @@
     .cfi_rel_offset 19, 32
     sw     $s2, 28($sp)
     .cfi_rel_offset 18, 28
-    sw     $a3, 12($sp)
-    .cfi_rel_offset 7, 12
-    sw     $a2, 8($sp)
-    .cfi_rel_offset 6, 8
-    sw     $a1, 4($sp)
-    .cfi_rel_offset 5, 4
+    sw     $a3, 24($sp)
+    .cfi_rel_offset 7, 24
+    sw     $a2, 20($sp)
+    .cfi_rel_offset 6, 20
+    sw     $a1, 16($sp)
+    .cfi_rel_offset 5, 16
     # bottom will hold Method*
 .endm
 
-.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC.
+     * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method*
+     * Clobbers $t0 and $sp
+     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
+     * Reserves FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE + ARG_SLOT_SIZE bytes on the stack
+     */
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
+    lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
+    lw $t0, 0($t0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    lw $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.
+    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
+    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
+.endm
+
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC.
+     * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method*
+     * Clobbers $sp
+     * Use $a0 as the Method* and loads it into bottom of stack.
+     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
+     * Reserves FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE + ARG_SLOT_SIZE bytes on the stack
+     */
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_A0
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
+    sw $a0, 0($sp)                                # Place Method* at bottom of stack.
+    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
+    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
+    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
+.endm
+
+.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
+    .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
     lw     $ra, 60($sp)
     .cfi_restore 31
     lw     $s8, 56($sp)
@@ -208,11 +257,11 @@
     .cfi_restore 19
     lw     $s2, 28($sp)
     .cfi_restore 18
-    lw     $a3, 12($sp)
+    lw     $a3, 24($sp)
     .cfi_restore 7
-    lw     $a2, 8($sp)
+    lw     $a2, 20($sp)
     .cfi_restore 6
-    lw     $a1, 4($sp)
+    lw     $a1, 16($sp)
     .cfi_restore 5
     addiu  $sp, $sp, 64           # pop frame
     .cfi_adjust_cfa_offset -64
@@ -224,38 +273,37 @@
      */
 .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
+    jalr    $zero, $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
+    jalr   $zero, $ra
     nop
 1:
     DELIVER_PENDING_EXCEPTION
 .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
+    jalr   $zero, $ra                    # return on success
     nop
 1:
     DELIVER_PENDING_EXCEPTION
 .endm
 
-.macro RETURN_IF_RESULT_IS_NON_ZERO
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     beqz   $v0, 1f                       # success?
     nop
-    jr     $ra                           # return on success
+    jalr   $zero, $ra                    # return on success
     nop
 1:
     DELIVER_PENDING_EXCEPTION
@@ -266,38 +314,23 @@
      * FIXME: just guessing about the shape of the jmpbuf.  Where will pc be?
      */
 ENTRY art_quick_do_long_jump
-    l.s     $f0, 0($a1)
-    l.s     $f1, 4($a1)
-    l.s     $f2, 8($a1)
-    l.s     $f3, 12($a1)
-    l.s     $f4, 16($a1)
-    l.s     $f5, 20($a1)
-    l.s     $f6, 24($a1)
-    l.s     $f7, 28($a1)
-    l.s     $f8, 32($a1)
-    l.s     $f9, 36($a1)
-    l.s     $f10, 40($a1)
-    l.s     $f11, 44($a1)
-    l.s     $f12, 48($a1)
-    l.s     $f13, 52($a1)
-    l.s     $f14, 56($a1)
-    l.s     $f15, 60($a1)
-    l.s     $f16, 64($a1)
-    l.s     $f17, 68($a1)
-    l.s     $f18, 72($a1)
-    l.s     $f19, 76($a1)
-    l.s     $f20, 80($a1)
-    l.s     $f21, 84($a1)
-    l.s     $f22, 88($a1)
-    l.s     $f23, 92($a1)
-    l.s     $f24, 96($a1)
-    l.s     $f25, 100($a1)
-    l.s     $f26, 104($a1)
-    l.s     $f27, 108($a1)
-    l.s     $f28, 112($a1)
-    l.s     $f29, 116($a1)
-    l.s     $f30, 120($a1)
-    l.s     $f31, 124($a1)
+    LDu  $f0,  $f1,   0*8, $a1, $t1
+    LDu  $f2,  $f3,   1*8, $a1, $t1
+    LDu  $f4,  $f5,   2*8, $a1, $t1
+    LDu  $f6,  $f7,   3*8, $a1, $t1
+    LDu  $f8,  $f9,   4*8, $a1, $t1
+    LDu  $f10, $f11,  5*8, $a1, $t1
+    LDu  $f12, $f13,  6*8, $a1, $t1
+    LDu  $f14, $f15,  7*8, $a1, $t1
+    LDu  $f16, $f17,  8*8, $a1, $t1
+    LDu  $f18, $f19,  9*8, $a1, $t1
+    LDu  $f20, $f21, 10*8, $a1, $t1
+    LDu  $f22, $f23, 11*8, $a1, $t1
+    LDu  $f24, $f25, 12*8, $a1, $t1
+    LDu  $f26, $f27, 13*8, $a1, $t1
+    LDu  $f28, $f29, 14*8, $a1, $t1
+    LDu  $f30, $f31, 15*8, $a1, $t1
+
     .set push
     .set nomacro
     .set noat
@@ -332,7 +365,7 @@
     lw      $ra, 124($a0)
     lw      $a0, 16($a0)
     move    $v0, $zero          # clear result registers r0 and r1
-    jr      $ra                 # do long jump
+    jalr    $zero, $ra          # do long jump
     move    $v1, $zero
 END art_quick_do_long_jump
 
@@ -342,12 +375,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
+    jalr $zero, $t9                 # artDeliverExceptionFromCode(Throwable*, Thread*)
+    move $a1, rSELF                 # pass Thread::Current
 END art_quick_deliver_exception
 
     /*
@@ -355,13 +386,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
+    jalr $zero, $t9                 # artThrowNullPointerExceptionFromCode(Thread*)
+    move $a0, rSELF                 # pass Thread::Current
 END art_quick_throw_null_pointer_exception
 
     /*
@@ -369,12 +397,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
+    jalr $zero, $t9                 # artThrowDivZeroFromCode(Thread*)
+    move $a0, rSELF                 # pass Thread::Current
 END art_quick_throw_div_zero
 
     /*
@@ -382,13 +408,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
+    jalr $zero, $t9                 # artThrowArrayBoundsFromCode(index, limit, Thread*)
+    move $a2, rSELF                 # pass Thread::Current
 END art_quick_throw_array_bounds
 
     /*
@@ -396,12 +419,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
+    jalr $zero, $t9                 # artThrowStackOverflowFromCode(Thread*)
+    move $a0, rSELF                 # pass Thread::Current
 END art_quick_throw_stack_overflow
 
     /*
@@ -409,12 +430,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
+    jalr $zero, $t9                 # artThrowNoSuchMethodFromCode(method_idx, Thread*)
+    move $a1, rSELF                 # pass Thread::Current
 END art_quick_throw_no_such_method
 
     /*
@@ -436,24 +455,17 @@
 .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*
-    move  $t0, $sp                        # save $sp
-    addiu $sp, $sp, -32                   # make space for extra args
-    .cfi_adjust_cfa_offset 32
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
+    lw    $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE+ARG_SLOT_SIZE($sp)    # pass caller Method*
+    addiu $t0, $sp, ARG_SLOT_SIZE         # save $sp (remove arg slots)
     move  $a3, rSELF                      # pass Thread::Current
-    .cfi_rel_offset 28, 12
     jal   \cxx_name                       # (method_idx, this, caller, Thread*, $sp)
     sw    $t0, 16($sp)                    # pass $sp
-    addiu $sp, $sp, 32                    # release out args
-    .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
+    move  $t9, $v1                        # save $v0->code_
+    jalr  $zero, $t9
     nop
 1:
     DELIVER_PENDING_EXCEPTION
@@ -479,7 +491,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
@@ -495,10 +506,10 @@
     .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 $t0, $a2, 16          # create space for method pointer in frame
-    srl   $t0, $t0, 4           # shift the frame size right 4
-    sll   $t0, $t0, 4           # shift the frame size left 4 to align to 16 bytes
-    subu  $sp, $sp, $t0         # reserve stack space for argument array
+    addiu $t0, $a2, 4           # create space for method pointer in frame.
+    subu  $t0, $sp, $t0         # reserve & align *stack* to 16 bytes:
+    srl   $t0, $t0, 4           # native calling convention only aligns to 8B,
+    sll   $sp, $t0, 4           # so we have to ensure ART 16B alignment ourselves.
     addiu $a0, $sp, 4           # pass stack pointer + method ptr as dest for memcpy
     jal   memcpy                # (dest, src, bytes)
     addiu $sp, $sp, -16         # make space for argument slots for memcpy
@@ -507,7 +518,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_32($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
@@ -529,12 +540,12 @@
     li    $t3, 70               # put char 'F' into t3
     beq   $t1, $t3, 1f          # branch if result type char == 'F'
     sw    $v0, 0($t0)           # store the result
-    jr    $ra
+    jalr  $zero, $ra
     sw    $v1, 4($t0)           # store the other half of the result
 1:
-    s.s   $f0, 0($t0)           # store floating point result
-    jr    $ra
-    s.s   $f1, 4($t0)           # store other half of floating point result
+    SDu   $f0, $f1, 0, $t0, $t1 # store floating point result
+    jalr  $zero, $ra
+    nop
 END art_quick_invoke_stub
 
     /*
@@ -543,11 +554,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
-    move    $a2, rSELF                         # pass Thread::Current
-    jal     artHandleFillArrayDataFromCode     # (Array*, const DexFile::Payload*, Thread*, $sp)
-    move    $a3, $sp                           # pass $sp
+    lw     $a2, 0($sp)                    # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case exception allocation triggers GC
+    jal    artHandleFillArrayDataFromCode # (payload offset, Array*, method, Thread*)
+    move   $a3, rSELF                     # pass Thread::Current
     RETURN_IF_ZERO
 END art_quick_handle_fill_data
 
@@ -556,13 +566,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
 
@@ -571,13 +579,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
 
@@ -586,7 +592,6 @@
      */
     .extern artThrowClassCastException
 ENTRY art_quick_check_cast
-    GENERATE_GLOBAL_POINTER
     addiu  $sp, $sp, -16
     .cfi_adjust_cfa_offset 16
     sw     $ra, 12($sp)
@@ -595,10 +600,11 @@
     sw     $a1, 4($sp)
     sw     $a0, 0($sp)
     jal    artIsAssignableFromCode
-    nop
+    addiu  $sp, $sp, -16             # reserve argument slots on the stack
+    addiu  $sp, $sp, 16
     beqz   $v0, .Lthrow_class_cast_exception
     lw     $ra, 12($sp)
-    jr     $ra
+    jalr   $zero, $ra
     addiu  $sp, $sp, 16
     .cfi_adjust_cfa_offset -16
 .Lthrow_class_cast_exception:
@@ -608,10 +614,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
+    jalr $zero, $t9                 # artThrowClassCastException (Class*, Class*, Thread*)
+    move $a2, rSELF                 # pass Thread::Current
 END art_quick_check_cast
 
     /*
@@ -620,7 +625,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
@@ -628,9 +632,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
@@ -640,30 +642,28 @@
 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
     sb  $t0, ($t1)
-    jr  $ra
+    jalr $zero, $ra
     nop
 .Ldo_aput_null:
     sll $a1, $a1, 2
     add $t0, $a0, $a1
-    sw  $a2, OBJECT_ARRAY_DATA_OFFSET($t0)
-    jr  $ra
+    sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
+    jalr $zero, $ra
     nop
 .Lcheck_assignability:
     addiu  $sp, $sp, -32
@@ -677,79 +677,33 @@
     move   $a1, $t1
     move   $a0, $t0
     jal    artIsAssignableFromCode  # (Class*, Class*)
-    nop
+    addiu $sp, $sp, -16     # reserve argument slots on the stack
+    addiu $sp, $sp, 16
     lw     $ra, 28($sp)
     lw     $t9, 12($sp)
     lw     $a2, 8($sp)
     lw     $a1, 4($sp)
     lw     $a0, 0($sp)
-    add    $sp, 32
+    addiu  $sp, 32
     .cfi_adjust_cfa_offset -32
     bnez   $v0, .Ldo_aput
     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
+    jalr $zero, $t9                 # artThrowArrayStoreException(Class*, Class*, Thread*)
+    move $a2, rSELF                 # pass Thread::Current
 END art_quick_aput_obj
 
     /*
-     * Entry from managed code when uninitialized static storage, this stub will run the class
-     * initializer and deliver the exception on error. On success the static storage base is
-     * returned.
-     */
-    .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)
-    jal     artInitializeStaticStorageFromCode
-    move    $a3, $sp                            # pass $sp
-    RETURN_IF_RESULT_IS_NON_ZERO
-END art_quick_initialize_static_storage
-
-    /*
-     * Entry from managed code when dex cache misses for a type_idx.
-     */
-    .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)
-    jal     artInitializeTypeFromCode
-    move    $a3, $sp                           # pass $sp
-    RETURN_IF_RESULT_IS_NON_ZERO
-END art_quick_initialize_type
-
-    /*
-     * Entry from managed code when type_idx needs to be checked for access and dex cache may also
-     * miss.
-     */
-    .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)
-    jal     artInitializeTypeAndVerifyAccessFromCode
-    move    $a3, $sp                           # pass $sp
-    RETURN_IF_RESULT_IS_NON_ZERO
-END art_quick_initialize_type_and_verify_access
-    /*
      * Called by managed code to resolve a static field and load a boolean primitive value.
      */
     .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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
     /*
@@ -757,12 +711,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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -771,12 +723,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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
     /*
@@ -784,12 +734,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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -798,12 +746,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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -812,12 +758,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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -826,12 +770,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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -840,12 +782,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
     /*
@@ -853,12 +793,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -867,12 +805,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
     /*
@@ -880,12 +816,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -894,12 +828,10 @@
      */
     .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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    jal    artGet32InstanceFromCode      # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGet32InstanceFromCode      # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get32_instance
 
@@ -908,12 +840,10 @@
      */
     .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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    jal    artGet64InstanceFromCode      # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGet64InstanceFromCode      # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get64_instance
 
@@ -922,12 +852,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -936,12 +864,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -950,12 +876,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
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
     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
 
@@ -964,12 +888,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -978,12 +900,11 @@
      */
     .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*
+    lw     $a1, 0($sp)                   # pass referrer's Method*
+                                         # 64 bit new_val is in a2:a3 pair
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -992,12 +913,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*
+    lw     $a2, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artSetObjStaticFromCode       # (field_idx, new_val, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
+    jal    artSetObjStaticFromCode       # (field_idx, new_val, referrer, Thread*)
     RETURN_IF_ZERO
 END art_quick_set_obj_static
 
@@ -1006,12 +925,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*
+    lw     $a3, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -1020,12 +937,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*
+    lw     $a3, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -1034,12 +949,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*
+    lw     $a3, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
@@ -1048,11 +961,12 @@
      */
     .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
+    lw     $t1, 0($sp)                   # load referrer's Method*
+                                         # 64 bit new_val is in a2:a3 pair
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    sw     rSELF, 20($sp)                # pass Thread::Current
+    jal    artSet64InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
+    sw     $t1, 16($sp)                  # pass referrer's Method*
     RETURN_IF_ZERO
 END art_quick_set64_instance
 
@@ -1061,42 +975,20 @@
      */
     .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*
+    lw     $a3, 0($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
+    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
 
-    /*
-     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
-     * exception on error. On success the String is returned. R0 holds the referring method,
-     * R1 holds the string index. The fast path check for hit in strings cache has already been
-     * performed.
-     */
-    .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)
-    jal     artResolveStringFromCode
-    move    $a3, $sp                  # pass $sp
-    RETURN_IF_RESULT_IS_NON_ZERO
-END art_quick_resolve_string
-
-
 // Macro to facilitate adding new allocation entrypoints.
 .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
@@ -1104,11 +996,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
@@ -1117,22 +1007,46 @@
 GENERATE_ALL_ALLOC_ENTRYPOINTS
 
     /*
+     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
+     * exception on error. On success the String is returned. R0 holds the referring method,
+     * R1 holds the string index. The fast path check for hit in strings cache has already been
+     * performed.
+     */
+TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+    /*
+     * Entry from managed code when uninitialized static storage, this stub will run the class
+     * initializer and deliver the exception on error. On success the static storage base is
+     * returned.
+     */
+TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+    /*
+     * Entry from managed code when dex cache misses for a type_idx.
+     */
+TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+    /*
+     * Entry from managed code when type_idx needs to be checked for access and dex cache may also
+     * miss.
+     */
+TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+
+    /*
      * Called by managed code when the value in rSUSPEND has been decremented to 0.
      */
     .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
+    addiu  rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
+    jalr   $zero, $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
 
     /*
@@ -1141,18 +1055,17 @@
      */
     .extern artQuickProxyInvokeHandler
 ENTRY art_quick_proxy_invoke_handler
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    sw      $a0, 0($sp)            # place proxy method at bottom of frame
-    move    $a2, rSELF             # pass Thread::Current
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_A0
+    move    $a2, rSELF                  # pass Thread::Current
     jal     artQuickProxyInvokeHandler  # (Method* proxy method, receiver, Thread*, SP)
-    move    $a3, $sp               # pass $sp
+    addiu   $a3, $sp, ARG_SLOT_SIZE     # pass $sp (remove arg slots)
     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     bnez    $t0, 1f
-    mtc1    $v0, $f0               # place return value to FP return value
-    jr      $ra
-    mtc1    $v1, $f1               # place return value to FP return value
+    # don't care if $v0 and/or $v1 are modified, when exception branch taken
+    MTD     $v0, $v1, $f0, $f1          # move float value to return value
+    jalr    $zero, $ra
+    nop
 1:
     DELIVER_PENDING_EXCEPTION
 END art_quick_proxy_invoke_handler
@@ -1162,49 +1075,106 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    GENERATE_GLOBAL_POINTER
     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
+    jalr    $zero, $t9
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
 ENTRY art_quick_resolution_trampoline
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    move    $a2, rSELF             # pass Thread::Current
+    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
+    addiu   $a3, $sp, ARG_SLOT_SIZE       # pass $sp (remove arg slots)
     beqz    $v0, 1f
-    lw      $a0, 0($sp)            # load resolved method to $a0
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    lw      $a0, ARG_SLOT_SIZE($sp)       # load resolved method to $a0
+    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
+    jalr    $zero, $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
 
-UNIMPLEMENTED art_quick_generic_jni_trampoline
+    .extern artQuickGenericJniTrampoline
+    .extern artQuickGenericJniEndTrampoline
+ENTRY art_quick_generic_jni_trampoline
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_A0
+    move    $s8, $sp               # save $sp to $s8
+    move    $s3, $gp               # save $gp to $s3
+
+    # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
+    move    $a0, rSELF                     # pass Thread::Current
+    addiu   $a1, $sp, ARG_SLOT_SIZE        # save $sp (remove arg slots)
+    jal     artQuickGenericJniTrampoline   # (Thread*, SP)
+    addiu   $sp, $sp, -5120                # reserve space on the stack
+
+    # The C call will have registered the complete save-frame on success.
+    # The result of the call is:
+    # v0: ptr to native code, 0 on error.
+    # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
+    beq     $v0, $zero, 1f         # check entry error
+    move    $t9, $v0               # save the code ptr
+    move    $sp, $v1               # release part of the alloca
+
+    # Load parameters from stack into registers
+    lw      $a0,   0($sp)
+    lw      $a1,   4($sp)
+    lw      $a2,   8($sp)
+
+    # Load FPRs the same as GPRs. Look at BuildNativeCallFrameStateMachine.
+    jalr    $t9                    # native call
+    lw      $a3,  12($sp)
+    addiu   $sp, $sp, 16           # remove arg slots
+
+    move    $gp, $s3               # restore $gp from $s3
+
+    # result sign extension is handled in C code
+    # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
+    move    $a0, rSELF             # pass Thread::Current
+    move    $a2, $v0               # pass result
+    move    $a3, $v1
+    addiu   $sp, $sp, -24          # reserve arg slots
+    jal     artQuickGenericJniEndTrampoline
+    s.d     $f0, 16($sp)           # pass result_f
+    addiu   $sp, $sp, 24           # remove arg slots
+
+    lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
+    bne     $t0, $zero, 2f         # check for pending exceptions
+    move    $sp, $s8               # tear down the alloca
+
+    # tear dpown the callee-save frame
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+
+    MTD     $v0, $v1, $f0, $f1     # move float value to return value
+    jalr    $zero, $ra
+    nop
+
+1:
+    move    $sp, $s8               # tear down the alloca
+2:
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    DELIVER_PENDING_EXCEPTION
+END art_quick_generic_jni_trampoline
 
     .extern artQuickToInterpreterBridge
 ENTRY art_quick_to_interpreter_bridge
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    move    $a1, rSELF             # pass Thread::Current
-    jal     artQuickToInterpreterBridge    # (Method* method, Thread*, SP)
-    move    $a2, $sp               # pass $sp
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    move    $a1, rSELF                          # pass Thread::Current
+    jal     artQuickToInterpreterBridge         # (Method* method, Thread*, SP)
+    addiu   $a2, $sp, ARG_SLOT_SIZE             # pass $sp (remove arg slots)
     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     bnez    $t0, 1f
-    mtc1    $v0, $f0               # place return value to FP return value
-    jr      $ra
-    mtc1    $v1, $f1               # place return value to FP return value
+    # don't care if $v0 and/or $v1 are modified, when exception branch taken
+    MTD     $v0, $v1, $f0, $f1                  # move float value to return value
+    jalr    $zero, $ra
+    nop
 1:
     DELIVER_PENDING_EXCEPTION
 END art_quick_to_interpreter_bridge
@@ -1215,21 +1185,14 @@
     .extern artInstrumentationMethodEntryFromCode
     .extern artInstrumentationMethodExitFromCode
 ENTRY art_quick_instrumentation_entry
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_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)
-    .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)
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    sw       $a0, 28($sp)   # save arg0 in free arg slot
+    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
+    lw       $a0, 28($sp)   # restore arg0 from free arg slot
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     jalr     $t9            # call method
     nop
 END art_quick_instrumentation_entry
@@ -1238,34 +1201,32 @@
 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
-    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
-    sw       $v0, 32($sp)
+
+    addiu    $sp, $sp, -16  # allocate temp storage on the stack
+    .cfi_adjust_cfa_offset 16
+    sw       $v0, 12($sp)
     .cfi_rel_offset 2, 32
-    sw       $v1, 36($sp)
-    .cfi_rel_offset 3, 36 
-    s.s      $f0, 40($sp)
-    s.s      $f1, 44($sp)
-    s.s      $f0, 16($sp)   # pass fpr result
-    s.s      $f1, 20($sp)
+    sw       $v1, 8($sp)
+    .cfi_rel_offset 3, 36
+    s.d      $f0, 0($sp)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+    s.d      $f0, 16($sp)   # pass fpr result
     move     $a2, $v0       # pass gpr result
     move     $a3, $v1
-    move     $a1, $t0       # pass $sp
+    addiu    $a1, $sp, ARG_SLOT_SIZE   # pass $sp (remove arg slots)
     jal      artInstrumentationMethodExitFromCode  # (Thread*, SP, gpr_res, fpr_res)
     move     $a0, rSELF     # pass Thread::Current
     move     $t0, $v0       # set aside returned link register
     move     $ra, $v1       # set link register for deoptimization
-    lw       $v0, 32($sp)   # restore return values
-    lw       $v1, 36($sp)
-    l.s      $f0, 40($sp)
-    l.s      $f1, 44($sp)
-    jr       $t0            # return
-    addiu    $sp, $sp, 112  # 48 bytes of args + 64 bytes of callee save frame
-    .cfi_adjust_cfa_offset -112
+    addiu    $sp, $sp, ARG_SLOT_SIZE+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE  # args slot + refs_only callee save frame
+    lw       $v0, 12($sp)   # restore return values
+    lw       $v1, 8($sp)
+    l.d      $f0, 0($sp)
+    jalr     $zero, $t0     # return
+    addiu    $sp, $sp, 16   # remove temp storage from stack
+    .cfi_adjust_cfa_offset -16
 END art_quick_instrumentation_exit
 
     /*
@@ -1273,14 +1234,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
 
     /*
@@ -1293,18 +1251,22 @@
      *   $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)
     srl     $a0, 1
     srl     $a0, $v1                         #  alo<- alo >> (32-(shift&31))
     sll     $v1, $a1, $a2                    #  rhi<- ahi << (shift&31)
-    or      $v1, $a0                         #  rhi<- rhi | alo
     andi    $a2, 0x20                        #  shift< shift & 0x20
-    movn    $v1, $v0, $a2                    #  rhi<- rlo (if shift&0x20)
-    jr      $ra
-    movn    $v0, $zero, $a2                  #  rlo<- 0  (if shift&0x20)
+    beqz    $a2, 1f
+    or      $v1, $a0                         #  rhi<- rhi | alo
+
+    move    $v1, $v0                         #  rhi<- rlo (if shift&0x20)
+    move    $v0, $zero                       #  rlo<- 0 (if shift&0x20)
+
+1:  jalr    $zero, $ra
+    nop
 END art_quick_shl_long
 
     /*
@@ -1317,19 +1279,22 @@
      *   $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)
     not     $a0, $a2                         #  alo<- 31-shift (shift is 5b)
     sll     $a1, 1
     sll     $a1, $a0                         #  ahi<- ahi << (32-(shift&31))
-    or      $v0, $a1                         #  rlo<- rlo | ahi
     andi    $a2, 0x20                        #  shift & 0x20
-    movn    $v0, $v1, $a2                    #  rlo<- rhi (if shift&0x20)
-    jr      $ra
-    movn    $v1, $a3, $a2                    #  rhi<- sign(ahi) (if shift&0x20)
+    beqz    $a2, 1f
+    or      $v0, $a1                         #  rlo<- rlo | ahi
+
+    move    $v0, $v1                         #  rlo<- rhi (if shift&0x20)
+    move    $v1, $a3                         #  rhi<- sign(ahi) (if shift&0x20)
+
+1:  jalr    $zero, $ra
+    nop
 END art_quick_shr_long
 
     /*
@@ -1343,26 +1308,22 @@
      *   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)
     sll     $a1, 1
     sll     $a1, $a0                         #  ahi<- ahi << (32-(shift&31))
-    or      $v0, $a1                         #  rlo<- rlo | ahi
     andi    $a2, 0x20                        #  shift & 0x20
-    movn    $v0, $v1, $a2                    #  rlo<- rhi (if shift&0x20)
-    jr      $ra
-    movn    $v1, $zero, $a2                  #  rhi<- 0 (if shift&0x20)
+    beqz    $a2, 1f
+    or      $v0, $a1                         #  rlo<- rlo | ahi
+
+    move    $v0, $v1                         #  rlo<- rhi (if shift&0x20)
+    move    $v1, $zero                       #  rhi<- 0 (if shift&0x20)
+
+1:  jalr    $zero, $ra
+    nop
 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/mips/quick_method_frame_info_mips.h b/runtime/arch/mips/quick_method_frame_info_mips.h
index 2a8bcf0..5fbffbc 100644
--- a/runtime/arch/mips/quick_method_frame_info_mips.h
+++ b/runtime/arch/mips/quick_method_frame_info_mips.h
@@ -40,8 +40,7 @@
 
 constexpr uint32_t MipsCalleeSaveFrameSize(Runtime::CalleeSaveType type) {
   return RoundUp((POPCOUNT(MipsCalleeSaveCoreSpills(type)) /* gprs */ +
-                  (type == Runtime::kRefsAndArgs ? 0 : 3) + 1 /* Method* */) *
-                 kMipsPointerSize, kStackAlignment);
+                  1 /* Method* */) * kMipsPointerSize, kStackAlignment);
 }
 
 constexpr QuickMethodFrameInfo MipsCalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
diff --git a/runtime/arch/mips64/asm_support_mips64.S b/runtime/arch/mips64/asm_support_mips64.S
new file mode 100644
index 0000000..10976bb
--- /dev/null
+++ b/runtime/arch/mips64/asm_support_mips64.S
@@ -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_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_S_
+#define ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_S_
+
+#include "asm_support_mips64.h"
+
+// Define special registers.
+
+// Register holding suspend check count down.
+#define rSUSPEND $s0
+// Register holding Thread::Current().
+#define rSELF $s1
+
+
+    //  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.
+    .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
+
+.macro END name
+    .cfi_endproc
+    .size \name, .-\name
+.endm
+
+.macro UNIMPLEMENTED name
+    ENTRY \name
+    break
+    break
+    END \name
+.endm
+
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_S_
diff --git a/runtime/arch/mips64/asm_support_mips64.h b/runtime/arch/mips64/asm_support_mips64.h
new file mode 100644
index 0000000..995fcf3
--- /dev/null
+++ b/runtime/arch/mips64/asm_support_mips64.h
@@ -0,0 +1,29 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_H_
+
+#include "asm_support.h"
+
+// 64 ($f24-$f31) + 64 ($s0-$s7) + 8 ($gp) + 8 ($s8) + 8 ($ra) + 1x8 bytes padding
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 160
+// 48 ($s2-$s7) + 8 ($gp) + 8 ($s8) + 8 ($ra) + 1x8 bytes padding
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 80
+// $f12-$f19, $a1-$a7, $s2-$s7 + $gp + $s8 + $ra, 16 total + 1x8 bytes padding + method*
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 208
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_H_
diff --git a/runtime/arch/mips64/context_mips64.cc b/runtime/arch/mips64/context_mips64.cc
new file mode 100644
index 0000000..7523ade
--- /dev/null
+++ b/runtime/arch/mips64/context_mips64.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 "context_mips64.h"
+
+#include "mirror/art_method-inl.h"
+#include "quick/quick_method_frame_info.h"
+#include "util.h"
+
+namespace art {
+namespace mips64 {
+
+static constexpr uintptr_t gZero = 0;
+
+void Mips64Context::Reset() {
+  for (size_t i = 0; i < kNumberOfGpuRegisters; i++) {
+    gprs_[i] = nullptr;
+  }
+  for (size_t i = 0; i < kNumberOfFpuRegisters; i++) {
+    fprs_[i] = nullptr;
+  }
+  gprs_[SP] = &sp_;
+  gprs_[RA] = &ra_;
+  // Initialize registers with easy to spot debug values.
+  sp_ = Mips64Context::kBadGprBase + SP;
+  ra_ = Mips64Context::kBadGprBase + RA;
+}
+
+void Mips64Context::FillCalleeSaves(const StackVisitor& fr) {
+  mirror::ArtMethod* method = fr.GetMethod();
+  const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo();
+  size_t spill_count = POPCOUNT(frame_info.CoreSpillMask());
+  size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask());
+  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 < kNumberOfGpuRegisters; i++) {
+      if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
+        gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes());
+        j++;
+      }
+    }
+  }
+  if (fp_spill_count > 0) {
+    // Lowest number spill is farthest away, walk registers and fill into context.
+    int j = 1;
+    for (size_t i = 0; i < kNumberOfFpuRegisters; i++) {
+      if (((frame_info.FpSpillMask() >> i) & 1) != 0) {
+        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j,
+                                        frame_info.FrameSizeInBytes());
+        j++;
+      }
+    }
+  }
+}
+
+bool Mips64Context::SetGPR(uint32_t reg, uintptr_t value) {
+  CHECK_LT(reg, static_cast<uint32_t>(kNumberOfGpuRegisters));
+  CHECK_NE(gprs_[reg], &gZero);  // Can't overwrite this static value since they are never reset.
+  if (gprs_[reg] != nullptr) {
+    *gprs_[reg] = value;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool Mips64Context::SetFPR(uint32_t reg, uintptr_t value) {
+  CHECK_LT(reg, static_cast<uint32_t>(kNumberOfFpuRegisters));
+  CHECK_NE(fprs_[reg], &gZero);  // Can't overwrite this static value since they are never reset.
+  if (fprs_[reg] != nullptr) {
+    *fprs_[reg] = value;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void Mips64Context::SmashCallerSaves() {
+  // This needs to be 0 because we want a null/zero return value.
+  gprs_[V0] = const_cast<uintptr_t*>(&gZero);
+  gprs_[V1] = const_cast<uintptr_t*>(&gZero);
+  gprs_[A1] = nullptr;
+  gprs_[A0] = nullptr;
+  gprs_[A2] = nullptr;
+  gprs_[A3] = nullptr;
+  gprs_[A4] = nullptr;
+  gprs_[A5] = nullptr;
+  gprs_[A6] = nullptr;
+  gprs_[A7] = nullptr;
+
+  // f0-f23 are caller-saved; f24-f31 are callee-saved.
+  fprs_[F0] = nullptr;
+  fprs_[F1] = nullptr;
+  fprs_[F2] = nullptr;
+  fprs_[F3] = nullptr;
+  fprs_[F4] = nullptr;
+  fprs_[F5] = nullptr;
+  fprs_[F6] = nullptr;
+  fprs_[F7] = nullptr;
+  fprs_[F8] = nullptr;
+  fprs_[F9] = nullptr;
+  fprs_[F10] = nullptr;
+  fprs_[F11] = nullptr;
+  fprs_[F12] = nullptr;
+  fprs_[F13] = nullptr;
+  fprs_[F14] = nullptr;
+  fprs_[F15] = nullptr;
+  fprs_[F16] = nullptr;
+  fprs_[F17] = nullptr;
+  fprs_[F18] = nullptr;
+  fprs_[F19] = nullptr;
+  fprs_[F20] = nullptr;
+  fprs_[F21] = nullptr;
+  fprs_[F22] = nullptr;
+  fprs_[F23] = nullptr;
+}
+
+extern "C" void art_quick_do_long_jump(uintptr_t*, uintptr_t*);
+
+void Mips64Context::DoLongJump() {
+  uintptr_t gprs[kNumberOfGpuRegisters];
+  uintptr_t fprs[kNumberOfFpuRegisters];
+  for (size_t i = 0; i < kNumberOfGpuRegisters; ++i) {
+    gprs[i] = gprs_[i] != nullptr ? *gprs_[i] : Mips64Context::kBadGprBase + i;
+  }
+  for (size_t i = 0; i < kNumberOfFpuRegisters; ++i) {
+    fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : Mips64Context::kBadFprBase + i;
+  }
+  art_quick_do_long_jump(gprs, fprs);
+}
+
+}  // namespace mips64
+}  // namespace art
diff --git a/runtime/arch/mips64/context_mips64.h b/runtime/arch/mips64/context_mips64.h
new file mode 100644
index 0000000..4ba5f13
--- /dev/null
+++ b/runtime/arch/mips64/context_mips64.h
@@ -0,0 +1,92 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_
+
+#include "arch/context.h"
+#include "base/logging.h"
+#include "registers_mips64.h"
+
+namespace art {
+namespace mips64 {
+
+class Mips64Context : public Context {
+ public:
+  Mips64Context() {
+    Reset();
+  }
+  virtual ~Mips64Context() {}
+
+  void Reset() 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);
+    CHECK(success) << "Failed to set SP register";
+  }
+
+  void SetPC(uintptr_t new_pc) OVERRIDE {
+    bool success = SetGPR(RA, new_pc);
+    CHECK(success) << "Failed to set RA register";
+  }
+
+  uintptr_t* GetGPRAddress(uint32_t reg) OVERRIDE {
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfGpuRegisters));
+    return gprs_[reg];
+  }
+
+  bool GetGPR(uint32_t reg, uintptr_t* val) OVERRIDE {
+    CHECK_LT(reg, static_cast<uint32_t>(kNumberOfGpuRegisters));
+    if (gprs_[reg] == nullptr) {
+      return false;
+    } else {
+      DCHECK(val != nullptr);
+      *val = *gprs_[reg];
+      return true;
+    }
+  }
+
+  bool SetGPR(uint32_t reg, uintptr_t value) OVERRIDE;
+
+  bool GetFPR(uint32_t reg, uintptr_t* val) OVERRIDE {
+    CHECK_LT(reg, static_cast<uint32_t>(kNumberOfFpuRegisters));
+    if (fprs_[reg] == nullptr) {
+      return false;
+    } else {
+      DCHECK(val != nullptr);
+      *val = *fprs_[reg];
+      return true;
+    }
+  }
+
+  bool SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
+
+  void SmashCallerSaves() OVERRIDE;
+  void DoLongJump() OVERRIDE;
+
+ private:
+  // Pointers to registers in the stack, initialized to NULL except for the special cases below.
+  uintptr_t* gprs_[kNumberOfGpuRegisters];
+  uint64_t* fprs_[kNumberOfFpuRegisters];
+  // Hold values for sp and ra (return address) if they are not located within a stack frame.
+  uintptr_t sp_, ra_;
+};
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_
diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc
new file mode 100644
index 0000000..4a3bf02
--- /dev/null
+++ b/runtime/arch/mips64/entrypoints_init_mips64.cc
@@ -0,0 +1,180 @@
+/*
+ * 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 "atomic.h"
+#include "entrypoints/interpreter/interpreter_entrypoints.h"
+#include "entrypoints/jni/jni_entrypoints.h"
+#include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/quick/quick_default_externs.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 {
+
+// Cast entrypoints.
+extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
+                                            const mirror::Class* ref_class);
+// Math entrypoints.
+extern int32_t CmpgDouble(double a, double b);
+extern int32_t CmplDouble(double a, double b);
+extern int32_t CmpgFloat(float a, float b);
+extern int32_t CmplFloat(float a, float b);
+extern "C" int64_t artLmul(int64_t a, int64_t b);
+extern "C" int64_t artLdiv(int64_t a, int64_t b);
+extern "C" int64_t artLmod(int64_t a, int64_t b);
+
+// Math conversions.
+extern "C" int32_t __fixsfsi(float op1);      // FLOAT_TO_INT
+extern "C" int32_t __fixdfsi(double op1);     // DOUBLE_TO_INT
+extern "C" float __floatdisf(int64_t op1);    // LONG_TO_FLOAT
+extern "C" double __floatdidf(int64_t op1);   // LONG_TO_DOUBLE
+extern "C" int64_t __fixsfdi(float op1);      // FLOAT_TO_LONG
+extern "C" int64_t __fixdfdi(double op1);     // DOUBLE_TO_LONG
+
+// Single-precision FP arithmetics.
+extern "C" float fmodf(float a, float b);      // REM_FLOAT[_2ADDR]
+
+// Double-precision FP arithmetics.
+extern "C" double fmod(double a, double b);     // REM_DOUBLE[_2ADDR]
+
+// Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR]
+extern "C" int64_t __divdi3(int64_t, int64_t);
+extern "C" int64_t __moddi3(int64_t, int64_t);
+
+void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
+                     QuickEntryPoints* qpoints) {
+  // Interpreter
+  ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge;
+  ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge;
+
+  // JNI
+  jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
+
+  // Alloc
+  ResetQuickAllocEntryPoints(qpoints);
+
+  // Cast
+  qpoints->pInstanceofNonTrivial = artIsAssignableFromCode;
+  qpoints->pCheckCast = art_quick_check_cast;
+
+  // DexCache
+  qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage;
+  qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access;
+  qpoints->pInitializeType = art_quick_initialize_type;
+  qpoints->pResolveString = art_quick_resolve_string;
+
+  // Field
+  qpoints->pSet8Instance = art_quick_set8_instance;
+  qpoints->pSet8Static = art_quick_set8_static;
+  qpoints->pSet16Instance = art_quick_set16_instance;
+  qpoints->pSet16Static = art_quick_set16_static;
+  qpoints->pSet32Instance = art_quick_set32_instance;
+  qpoints->pSet32Static = art_quick_set32_static;
+  qpoints->pSet64Instance = art_quick_set64_instance;
+  qpoints->pSet64Static = art_quick_set64_static;
+  qpoints->pSetObjInstance = art_quick_set_obj_instance;
+  qpoints->pSetObjStatic = art_quick_set_obj_static;
+  qpoints->pGetBooleanInstance = art_quick_get_boolean_instance;
+  qpoints->pGetByteInstance = art_quick_get_byte_instance;
+  qpoints->pGetCharInstance = art_quick_get_char_instance;
+  qpoints->pGetShortInstance = art_quick_get_short_instance;
+  qpoints->pGet32Instance = art_quick_get32_instance;
+  qpoints->pGet64Instance = art_quick_get64_instance;
+  qpoints->pGetObjInstance = art_quick_get_obj_instance;
+  qpoints->pGetBooleanStatic = art_quick_get_boolean_static;
+  qpoints->pGetByteStatic = art_quick_get_byte_static;
+  qpoints->pGetCharStatic = art_quick_get_char_static;
+  qpoints->pGetShortStatic = art_quick_get_short_static;
+  qpoints->pGet32Static = art_quick_get32_static;
+  qpoints->pGet64Static = art_quick_get64_static;
+  qpoints->pGetObjStatic = art_quick_get_obj_static;
+
+  // Array
+  qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check;
+  qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check;
+  qpoints->pAputObject = art_quick_aput_obj;
+  qpoints->pHandleFillArrayData = art_quick_handle_fill_data;
+
+  // JNI
+  qpoints->pJniMethodStart = JniMethodStart;
+  qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized;
+  qpoints->pJniMethodEnd = JniMethodEnd;
+  qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
+  qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
+  qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
+  qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline;
+
+  // Locks
+  qpoints->pLockObject = art_quick_lock_object;
+  qpoints->pUnlockObject = art_quick_unlock_object;
+
+  // Math
+  qpoints->pCmpgDouble = CmpgDouble;
+  qpoints->pCmpgFloat = CmpgFloat;
+  qpoints->pCmplDouble = CmplDouble;
+  qpoints->pCmplFloat = CmplFloat;
+  qpoints->pFmod = fmod;
+  qpoints->pL2d = art_l2d;
+  qpoints->pFmodf = fmodf;
+  qpoints->pL2f = art_l2f;
+  qpoints->pD2iz = art_d2i;
+  qpoints->pF2iz = art_f2i;
+  qpoints->pIdivmod = NULL;
+  qpoints->pD2l = art_d2l;
+  qpoints->pF2l = art_f2l;
+  qpoints->pLdiv = artLdiv;
+  qpoints->pLmod = artLmod;
+  qpoints->pLmul = artLmul;
+  qpoints->pShlLong = NULL;
+  qpoints->pShrLong = NULL;
+  qpoints->pUshrLong = NULL;
+
+  // Intrinsics
+  qpoints->pIndexOf = art_quick_indexof;
+  qpoints->pStringCompareTo = art_quick_string_compareto;
+  qpoints->pMemcpy = memcpy;
+
+  // Invocation
+  qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline;
+  qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline;
+  qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge;
+  qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
+  qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
+  qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check;
+  qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check;
+  qpoints->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check;
+
+  // Thread
+  qpoints->pTestSuspend = art_quick_test_suspend;
+
+  // Throws
+  qpoints->pDeliverException = art_quick_deliver_exception;
+  qpoints->pThrowArrayBounds = art_quick_throw_array_bounds;
+  qpoints->pThrowDivZero = art_quick_throw_div_zero;
+  qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method;
+  qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception;
+  qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;
+
+  // TODO - use lld/scd instructions for Mips64
+  // Atomic 64-bit load/store
+  qpoints->pA64Load = QuasiAtomic::Read64;
+  qpoints->pA64Store = QuasiAtomic::Write64;
+};
+
+}  // namespace art
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
new file mode 100644
index 0000000..7b5cd49
--- /dev/null
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 "fault_handler.h"
+#include <sys/ucontext.h>
+#include "base/macros.h"
+#include "globals.h"
+#include "base/logging.h"
+#include "base/hex_dump.h"
+
+
+//
+// Mips64 specific fault handler functions.
+//
+
+namespace art {
+
+void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                      void* context ATTRIBUTE_UNUSED) {
+}
+
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED,
+                                             void* context ATTRIBUTE_UNUSED,
+                                             mirror::ArtMethod** out_method ATTRIBUTE_UNUSED,
+                                             uintptr_t* out_return_pc ATTRIBUTE_UNUSED,
+                                             uintptr_t* out_sp ATTRIBUTE_UNUSED) {
+}
+
+bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                void* context ATTRIBUTE_UNUSED) {
+  return false;
+}
+
+bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                               void* context ATTRIBUTE_UNUSED) {
+  return false;
+}
+
+bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                                  void* context ATTRIBUTE_UNUSED) {
+  return false;
+}
+}       // namespace art
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.cc b/runtime/arch/mips64/instruction_set_features_mips64.cc
new file mode 100644
index 0000000..26478cb
--- /dev/null
+++ b/runtime/arch/mips64/instruction_set_features_mips64.cc
@@ -0,0 +1,116 @@
+/*
+ * 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 "instruction_set_features_mips64.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromVariant(
+    const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
+  // TODO: r6 variant.
+  if (variant != "default") {
+    std::ostringstream os;
+    LOG(WARNING) << "Unexpected CPU variant for Mips64 using defaults: " << variant;
+  }
+  bool smp = true;  // Conservative default.
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromCppDefines() {
+  const bool smp = true;
+
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::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 smp = 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("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromHwcap() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromAssembly() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+bool Mips64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kMips64 != other->GetInstructionSet()) {
+    return false;
+  }
+  return (IsSmp() == other->IsSmp());
+}
+
+uint32_t Mips64InstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0);
+}
+
+std::string Mips64InstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* Mips64InstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  auto i = features.begin();
+  if (i != features.end()) {
+    // We don't have any features.
+    std::string feature = Trim(*i);
+    *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+    return nullptr;
+  }
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.h b/runtime/arch/mips64/instruction_set_features_mips64.h
new file mode 100644
index 0000000..d5d6012
--- /dev/null
+++ b/runtime/arch/mips64/instruction_set_features_mips64.h
@@ -0,0 +1,80 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS64_INSTRUCTION_SET_FEATURES_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_INSTRUCTION_SET_FEATURES_MIPS64_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the MIPS64 architecture.
+class Mips64InstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "r4000" and create InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const Mips64InstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* 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 Mips64InstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kMips64;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  std::string GetFeatureString() const OVERRIDE;
+
+  virtual ~Mips64InstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "fpu32", "mips2" adding these to a new Mips64InstructionSetFeatures.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  explicit Mips64InstructionSetFeatures(bool smp) : InstructionSetFeatures(smp) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(Mips64InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_INSTRUCTION_SET_FEATURES_MIPS64_H_
diff --git a/runtime/arch/mips64/instruction_set_features_mips64_test.cc b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
new file mode 100644
index 0000000..dc34506
--- /dev/null
+++ b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
@@ -0,0 +1,34 @@
+/*
+ * 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 "instruction_set_features_mips64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(Mips64InstructionSetFeaturesTest, Mips64Features) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> mips64_features(
+      InstructionSetFeatures::FromVariant(kMips64, "default", &error_msg));
+  ASSERT_TRUE(mips64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(mips64_features->GetInstructionSet(), kMips64);
+  EXPECT_TRUE(mips64_features->Equals(mips64_features.get()));
+  EXPECT_STREQ("smp", mips64_features->GetFeatureString().c_str());
+  EXPECT_EQ(mips64_features->AsBitmap(), 1U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips64/jni_entrypoints_mips64.S b/runtime/arch/mips64/jni_entrypoints_mips64.S
new file mode 100644
index 0000000..90fd3ee
--- /dev/null
+++ b/runtime/arch/mips64/jni_entrypoints_mips64.S
@@ -0,0 +1,76 @@
+/*
+ * 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_mips64.S"
+
+    .set noreorder
+    .balign 16
+
+    /*
+     * Jni dlsym lookup stub.
+     */
+    .extern artFindNativeMethod
+ENTRY art_jni_dlsym_lookup_stub
+    daddiu $sp, $sp, -80        # save a0-a7 and $ra
+    .cfi_adjust_cfa_offset 80
+    sd     $ra, 64($sp)
+    .cfi_rel_offset 31, 64
+    sw     $a7, 56($sp)
+    .cfi_rel_offset 11, 56
+    sw     $a6, 48($sp)
+    .cfi_rel_offset 10, 48
+    sw     $a5, 40($sp)
+    .cfi_rel_offset 9, 40
+    sw     $a4, 32($sp)
+    .cfi_rel_offset 8, 32
+    sw     $a3, 24($sp)
+    .cfi_rel_offset 7, 24
+    sw     $a2, 16($sp)
+    .cfi_rel_offset 6, 16
+    sw     $a1, 8($sp)
+    .cfi_rel_offset 5, 8
+    sw     $a0, 0($sp)
+    .cfi_rel_offset 4, 0
+    jal    artFindNativeMethod  # (Thread*)
+    move   $a0, $s1             # pass Thread::Current()
+    ld     $a0, 0($sp)          # restore registers from stack
+    .cfi_restore 4
+    ld     $a1, 8($sp)
+    .cfi_restore 5
+    ld     $a2, 16($sp)
+    .cfi_restore 6
+    ld     $a3, 24($sp)
+    .cfi_restore 7
+    ld     $a4, 32($sp)
+    .cfi_restore 8
+    ld     $a5, 40($sp)
+    .cfi_restore 9
+    ld     $a6, 48($sp)
+    .cfi_restore 10
+    ld     $a7, 56($sp)
+    .cfi_restore 11
+    ld     $ra, 64($sp)
+    .cfi_restore 31
+    beq    $v0, $zero, .Lno_native_code_found
+    daddiu $sp, $sp, 80         # restore the stack
+    .cfi_adjust_cfa_offset -80
+    move   $t9, $v0             # put method code result in $t9
+    jalr   $zero, $t9           # leaf call to method's code
+    nop
+.Lno_native_code_found:
+    jalr   $zero, $ra
+    nop
+END art_jni_dlsym_lookup_stub
diff --git a/runtime/arch/mips64/memcmp16_mips64.S b/runtime/arch/mips64/memcmp16_mips64.S
new file mode 100644
index 0000000..962977e
--- /dev/null
+++ b/runtime/arch/mips64/memcmp16_mips64.S
@@ -0,0 +1,50 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS64_MEMCMP16_MIPS64_S_
+#define ART_RUNTIME_ARCH_MIPS64_MEMCMP16_MIPS64_S_
+
+#include "asm_support_mips64.S"
+
+.set noreorder
+
+// u4 __memcmp16(const u2*, const u2*, size_t);
+ENTRY_NO_GP __memcmp16
+  move  $t0, $zero
+  move  $t1, $zero
+  beqz  $a2, done       /* 0 length string */
+  nop
+  beq   $a0, $a1, done  /* addresses are identical */
+  nop
+
+1:
+  lhu   $t0, 0($a0)
+  lhu   $t1, 0($a1)
+  bne   $t0, $t1, done
+  nop
+  daddu $a0, 2
+  daddu $a1, 2
+  dsubu $a2, 1
+  bnez  $a2, 1b
+  nop
+
+done:
+  dsubu $v0, $t0, $t1
+  j     $ra
+  nop
+END __memcmp16
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_MEMCMP16_MIPS64_S_
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
new file mode 100644
index 0000000..3430eb5
--- /dev/null
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -0,0 +1,897 @@
+/*
+ * 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_mips64.S"
+
+#include "arch/quick_alloc_entrypoints.S"
+
+    .set noreorder
+    .balign 16
+
+    /* Deliver the given exception */
+    .extern artDeliverExceptionFromCode
+    /* Deliver an exception pending on a thread */
+    .extern artDeliverPendingExceptionFromCode
+
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveAll)
+     * callee-save: padding + $f24-$f31 + $s0-$s7 + $gp + $ra + $s8 = 19 total + 1x8 bytes padding
+     */
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    daddiu $sp, $sp, -160
+    .cfi_adjust_cfa_offset 160
+
+     // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 160)
+#error "SAVE_ALL_CALLEE_SAVE_FRAME(MIPS64) size not as expected."
+#endif
+
+    sd     $ra, 152($sp)
+    .cfi_rel_offset 31, 152
+    sd     $s8, 144($sp)
+    .cfi_rel_offset 30, 144
+    sd     $gp, 136($sp)
+    .cfi_rel_offset 28, 136
+    sd     $s7, 128($sp)
+    .cfi_rel_offset 23, 128
+    sd     $s6, 120($sp)
+    .cfi_rel_offset 22, 120
+    sd     $s5, 112($sp)
+    .cfi_rel_offset 21, 112
+    sd     $s4, 104($sp)
+    .cfi_rel_offset 20, 104
+    sd     $s3,  96($sp)
+    .cfi_rel_offset 19, 96
+    sd     $s2,  88($sp)
+    .cfi_rel_offset 18, 88
+    sd     $s1,  80($sp)
+    .cfi_rel_offset 17, 80
+    sd     $s0,  72($sp)
+    .cfi_rel_offset 16, 72
+
+    // FP callee-saves
+    s.d    $f31, 64($sp)
+    s.d    $f30, 56($sp)
+    s.d    $f29, 48($sp)
+    s.d    $f28, 40($sp)
+    s.d    $f27, 32($sp)
+    s.d    $f26, 24($sp)
+    s.d    $f25, 16($sp)
+    s.d    $f24,  8($sp)
+
+    # load appropriate callee-save-method
+    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
+    ld      $v0, 0($v0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld      $v0, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET($v0)
+    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
+    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
+.endm
+
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes
+     * non-moving GC.
+     * Does not include rSUSPEND or rSELF
+     * callee-save: padding + $s2-$s7 + $gp + $ra + $s8 = 9 total + 1x8 bytes padding
+     */
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+    daddiu $sp, $sp, -80
+    .cfi_adjust_cfa_offset 80
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 80)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(MIPS64) size not as expected."
+#endif
+
+    sd     $ra, 72($sp)
+    .cfi_rel_offset 31, 72
+    sd     $s8, 64($sp)
+    .cfi_rel_offset 30, 64
+    sd     $gp, 56($sp)
+    .cfi_rel_offset 28, 56
+    sd     $s7, 48($sp)
+    .cfi_rel_offset 23, 48
+    sd     $s6, 40($sp)
+    .cfi_rel_offset 22, 40
+    sd     $s5, 32($sp)
+    .cfi_rel_offset 21, 32
+    sd     $s4, 24($sp)
+    .cfi_rel_offset 20, 24
+    sd     $s3, 16($sp)
+    .cfi_rel_offset 19, 16
+    sd     $s2, 8($sp)
+    .cfi_rel_offset 18, 8
+    # load appropriate callee-save-method
+    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
+    ld      $v0, 0($v0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld      $v0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET($v0)
+    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
+    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
+.endm
+
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    ld     $ra, 72($sp)
+    .cfi_restore 31
+    ld     $s8, 64($sp)
+    .cfi_restore 30
+    ld     $gp, 56($sp)
+    .cfi_restore 28
+    ld     $s7, 48($sp)
+    .cfi_restore 23
+    ld     $s6, 40($sp)
+    .cfi_restore 22
+    ld     $s5, 32($sp)
+    .cfi_restore 21
+    ld     $s4, 24($sp)
+    .cfi_restore 20
+    ld     $s3, 16($sp)
+    .cfi_restore 19
+    ld     $s2, 8($sp)
+    .cfi_restore 18
+    daddiu $sp, $sp, 80
+    .cfi_adjust_cfa_offset -80
+.endm
+
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    ld     $ra, 72($sp)
+    .cfi_restore 31
+    ld     $s8, 64($sp)
+    .cfi_restore 30
+    ld     $gp, 56($sp)
+    .cfi_restore 28
+    ld     $s7, 48($sp)
+    .cfi_restore 23
+    ld     $s6, 40($sp)
+    .cfi_restore 22
+    ld     $s5, 32($sp)
+    .cfi_restore 21
+    ld     $s4, 24($sp)
+    .cfi_restore 20
+    ld     $s3, 16($sp)
+    .cfi_restore 19
+    ld     $s2, 8($sp)
+    .cfi_restore 18
+    jalr   $zero, $ra
+    daddiu $sp, $sp, 80
+    .cfi_adjust_cfa_offset -80
+.endm
+
+// This assumes the top part of these stack frame types are identical.
+#define REFS_AND_ARGS_MINUS_REFS_SIZE (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes
+     * non-moving GC.
+     * callee-save: padding + $f12-$f19 + $a1-$a7 + $s2-$s7 + $gp + $ra + $s8 = 24 total + 1 words padding + Method*
+     */
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+    daddiu  $sp, $sp, -208
+    .cfi_adjust_cfa_offset 208
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 208)
+#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(MIPS64) size not as expected."
+#endif
+
+    sd     $ra, 200($sp)           # = kQuickCalleeSaveFrame_RefAndArgs_LrOffset
+    .cfi_rel_offset 31, 200
+    sd     $s8, 192($sp)
+    .cfi_rel_offset 30, 192
+    sd     $gp, 184($sp)
+    .cfi_rel_offset 28, 184
+    sd     $s7, 176($sp)
+    .cfi_rel_offset 23, 176
+    sd     $s6, 168($sp)
+    .cfi_rel_offset 22, 168
+    sd     $s5, 160($sp)
+    .cfi_rel_offset 21, 160
+    sd     $s4, 152($sp)
+    .cfi_rel_offset 20, 152
+    sd     $s3, 144($sp)
+    .cfi_rel_offset 19, 144
+    sd     $s2, 136($sp)
+    .cfi_rel_offset 18, 136
+
+    sd     $a7, 128($sp)
+    .cfi_rel_offset 11, 128
+    sd     $a6, 120($sp)
+    .cfi_rel_offset 10, 120
+    sd     $a5, 112($sp)
+    .cfi_rel_offset 9, 112
+    sd     $a4, 104($sp)
+    .cfi_rel_offset 8, 104
+    sd     $a3,  96($sp)
+    .cfi_rel_offset 7, 96
+    sd     $a2,  88($sp)
+    .cfi_rel_offset 6, 88
+    sd     $a1,  80($sp)           # = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset
+    .cfi_rel_offset 5, 80
+
+    s.d    $f19, 72($sp)
+    s.d    $f18, 64($sp)
+    s.d    $f17, 56($sp)
+    s.d    $f16, 48($sp)
+    s.d    $f15, 40($sp)
+    s.d    $f14, 32($sp)
+    s.d    $f13, 24($sp)           # = kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset
+    s.d    $f12, 16($sp)           # This isn't necessary to store.
+
+    # 1x8 bytes paddig + Method*
+    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
+    ld      $v0, 0($v0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld      $v0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET($v0)
+    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
+    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
+.endm
+
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+    # load appropriate callee-save-method
+    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
+    ld      $v0, 0($v0)
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld      $v0, RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET($v0)
+    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
+    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
+.endm
+
+.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    ld     $ra, 200($sp)
+    .cfi_restore 31
+    ld     $s8, 192($sp)
+    .cfi_restore 30
+    ld     $gp, 184($sp)
+    .cfi_restore 28
+    ld     $s7, 176($sp)
+    .cfi_restore 23
+    ld     $s6, 168($sp)
+    .cfi_restore 22
+    ld     $s5, 160($sp)
+    .cfi_restore 21
+    ld     $s4, 152($sp)
+    .cfi_restore 20
+    ld     $s3, 144($sp)
+    .cfi_restore 19
+    ld     $s2, 136($sp)
+    .cfi_restore 18
+
+    ld     $a7, 128($sp)
+    .cfi_restore 11
+    ld     $a6, 120($sp)
+    .cfi_restore 10
+    ld     $a5, 112($sp)
+    .cfi_restore 9
+    ld     $a4, 104($sp)
+    .cfi_restore 8
+    ld     $a3,  96($sp)
+    .cfi_restore 7
+    ld     $a2,  88($sp)
+    .cfi_restore 6
+    ld     $a1,  80($sp)
+    .cfi_restore 5
+
+    l.d    $f19, 72($sp)
+    l.d    $f18, 64($sp)
+    l.d    $f17, 56($sp)
+    l.d    $f16, 48($sp)
+    l.d    $f15, 40($sp)
+    l.d    $f14, 32($sp)
+    l.d    $f13, 24($sp)
+    l.d    $f12, 16($sp)
+
+    daddiu $sp, $sp, 208
+    .cfi_adjust_cfa_offset -208
+.endm
+
+    /*
+     * Macro that set calls through to artDeliverPendingExceptionFromCode,
+     * where the pending
+     * exception is Thread::Current()->exception_
+     */
+.macro DELIVER_PENDING_EXCEPTION
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME     # save callee saves for throw
+    dla     $t9, artDeliverPendingExceptionFromCode
+    jalr    $zero, $t9                   # artDeliverPendingExceptionFromCode(Thread*)
+    move    $a0, rSELF                   # pass Thread::Current
+.endm
+
+.macro RETURN_IF_NO_EXCEPTION
+    ld     $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    bne    $t0, $zero, 1f                      # success if no exception is pending
+    nop
+    jalr   $zero, $ra
+    nop
+1:
+    DELIVER_PENDING_EXCEPTION
+.endm
+
+.macro RETURN_IF_ZERO
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    bne    $v0, $zero, 1f                # success?
+    nop
+    jalr   $zero, $ra                    # return on success
+    nop
+1:
+    DELIVER_PENDING_EXCEPTION
+.endm
+
+.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    beq    $v0, $zero, 1f                # success?
+    nop
+    jalr   $zero, $ra                    # return on success
+    nop
+1:
+    DELIVER_PENDING_EXCEPTION
+.endm
+
+    /*
+     * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_
+     * FIXME: just guessing about the shape of the jmpbuf.  Where will pc be?
+     */
+ENTRY art_quick_do_long_jump
+    l.d     $f0, 0($a1)
+    l.d     $f1, 8($a1)
+    l.d     $f2, 16($a1)
+    l.d     $f3, 24($a1)
+    l.d     $f4, 32($a1)
+    l.d     $f5, 40($a1)
+    l.d     $f6, 48($a1)
+    l.d     $f7, 56($a1)
+    l.d     $f8, 64($a1)
+    l.d     $f9, 72($a1)
+    l.d     $f10, 80($a1)
+    l.d     $f11, 88($a1)
+    l.d     $f12, 96($a1)
+    l.d     $f13, 104($a1)
+    l.d     $f14, 112($a1)
+    l.d     $f15, 120($a1)
+    l.d     $f16, 128($a1)
+    l.d     $f17, 136($a1)
+    l.d     $f18, 144($a1)
+    l.d     $f19, 152($a1)
+    l.d     $f20, 160($a1)
+    l.d     $f21, 168($a1)
+    l.d     $f22, 176($a1)
+    l.d     $f23, 184($a1)
+    l.d     $f24, 192($a1)
+    l.d     $f25, 200($a1)
+    l.d     $f26, 208($a1)
+    l.d     $f27, 216($a1)
+    l.d     $f28, 224($a1)
+    l.d     $f29, 232($a1)
+    l.d     $f30, 240($a1)
+    l.d     $f31, 248($a1)
+    .set push
+    .set nomacro
+    .set noat
+# no need to load zero
+    ld      $at, 8($a0)
+    .set pop
+    ld      $v0, 16($a0)
+    ld      $v1, 24($a0)
+# a0 has to be loaded last
+    ld      $a1, 40($a0)
+    ld      $a2, 48($a0)
+    ld      $a3, 56($a0)
+    ld      $a4, 64($a0)
+    ld      $a5, 72($a0)
+    ld      $a6, 80($a0)
+    ld      $a7, 88($a0)
+    ld      $t0, 96($a0)
+    ld      $t1, 104($a0)
+    ld      $t2, 112($a0)
+    ld      $t3, 120($a0)
+    ld      $s0, 128($a0)
+    ld      $s1, 136($a0)
+    ld      $s2, 144($a0)
+    ld      $s3, 152($a0)
+    ld      $s4, 160($a0)
+    ld      $s5, 168($a0)
+    ld      $s6, 176($a0)
+    ld      $s7, 184($a0)
+    ld      $t8, 192($a0)
+    ld      $t9, 200($a0)
+# no need to load k0, k1
+    ld      $gp, 224($a0)
+    ld      $sp, 232($a0)
+    ld      $s8, 240($a0)
+    ld      $ra, 248($a0)
+    ld      $a0, 32($a0)
+    move    $v0, $zero          # clear result registers v0 and v1
+    jalr    $zero, $ra          # do long jump
+    move    $v1, $zero
+END art_quick_do_long_jump
+
+UNIMPLEMENTED art_quick_deliver_exception
+UNIMPLEMENTED art_quick_throw_null_pointer_exception
+UNIMPLEMENTED art_quick_throw_div_zero
+UNIMPLEMENTED art_quick_throw_array_bounds
+UNIMPLEMENTED art_quick_throw_stack_overflow
+UNIMPLEMENTED art_quick_throw_no_such_method
+
+UNIMPLEMENTED art_quick_invoke_interface_trampoline
+UNIMPLEMENTED art_quick_invoke_interface_trampoline_with_access_check
+
+UNIMPLEMENTED art_quick_invoke_static_trampoline_with_access_check
+UNIMPLEMENTED art_quick_invoke_direct_trampoline_with_access_check
+UNIMPLEMENTED art_quick_invoke_super_trampoline_with_access_check
+UNIMPLEMENTED art_quick_invoke_virtual_trampoline_with_access_check
+
+    # On entry:
+    #   t0 = shorty
+    #   t1 = ptr to arg_array
+    #   t2 = number of argument bytes remain
+    #   v0 = ptr to stack frame where to copy arg_array
+    # This macro modifies t3, t9 and v0
+.macro LOOP_OVER_SHORTY_LOADING_REG gpu, fpu, label
+    lbu    $t3, 0($t0)           # get argument type from shorty
+    beqz   $t3, \label
+    daddiu $t0, 1
+    li     $t9, 68               # put char 'D' into t9
+    beq    $t9, $t3, 1f          # branch if result type char == 'D'
+    li     $t9, 70               # put char 'F' into t9
+    beq    $t9, $t3, 2f          # branch if result type char == 'F'
+    li     $t9, 74               # put char 'J' into t9
+    beq    $t9, $t3, 3f          # branch if result type char == 'J'
+    nop
+    lwu    $\gpu, 0($t1)
+    sw     $\gpu, 0($v0)
+    daddiu $v0, 4
+    daddiu $t1, 4
+    b      4f
+    daddiu $t2, -4               # delay slot
+
+1:  # found double
+    lwu    $t3, 0($t1)
+    mtc1   $t3, $\fpu
+    sw     $t3, 0($v0)
+    lwu    $t3, 4($t1)
+    mthc1  $t3, $\fpu
+    sw     $t3, 4($v0)
+    daddiu $v0, 8
+    daddiu $t1, 8
+    b      4f
+    daddiu $t2, -8               # delay slot
+
+2:  # found float
+    lwu    $t3, 0($t1)
+    mtc1   $t3, $\fpu
+    sw     $t3, 0($v0)
+    daddiu $v0, 4
+    daddiu $t1, 4
+    b      4f
+    daddiu $t2, -4               # delay slot
+
+3:  # found long (8 bytes)
+    lwu    $t3, 0($t1)
+    sw     $t3, 0($v0)
+    lwu    $t9, 4($t1)
+    sw     $t9, 4($v0)
+    dsll   $t9, $t9, 32
+    or     $\gpu, $t9, $t3
+    daddiu $v0, 8
+    daddiu $t1, 8
+    daddiu $t2, -8
+4:
+.endm
+
+    /*
+     * Invocation stub for quick code.
+     * On entry:
+     *   a0 = method pointer
+     *   a1 = argument array that must at least contain the this ptr.
+     *   a2 = size of argument array in bytes
+     *   a3 = (managed) thread pointer
+     *   a4 = JValue* result
+     *   a5 = shorty
+     */
+ENTRY art_quick_invoke_stub
+    # push a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra onto the stack
+    daddiu $sp, $sp, -48
+    .cfi_adjust_cfa_offset 48
+    sd     $ra, 40($sp)
+    .cfi_rel_offset 31, 40
+    sd     $s8, 32($sp)
+    .cfi_rel_offset 30, 32
+    sd     $s1, 24($sp)
+    .cfi_rel_offset 17, 24
+    sd     $s0, 16($sp)
+    .cfi_rel_offset 16, 16
+    sd     $a5, 8($sp)
+    .cfi_rel_offset 9, 8
+    sd     $a4, 0($sp)
+    .cfi_rel_offset 8, 0
+
+    daddiu $s0, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
+    move   $s1, $a3              # move managed thread pointer into s1 (rSELF)
+    move   $s8, $sp              # save sp in s8 (fp)
+
+    daddiu $t3, $a2, 20          # add 4 for method* and 16 for stack alignment
+    dsrl   $t3, $t3, 4           # shift the frame size right 4
+    dsll   $t3, $t3, 4           # shift the frame size left 4 to align to 16 bytes
+    dsubu  $sp, $sp, $t3         # reserve stack space for argument array
+
+    daddiu $t0, $a5, 1           # t0 = shorty[1] (skip 1 for return type)
+    daddiu $t1, $a1, 4           # t1 = ptr to arg_array[4] (skip this ptr)
+    daddiu $t2, $a2, -4          # t2 = number of argument bytes remain (skip this ptr)
+    daddiu $v0, $sp, 8           # v0 points to where to copy arg_array
+    LOOP_OVER_SHORTY_LOADING_REG a2, f14, call_fn
+    LOOP_OVER_SHORTY_LOADING_REG a3, f15, call_fn
+    LOOP_OVER_SHORTY_LOADING_REG a4, f16, call_fn
+    LOOP_OVER_SHORTY_LOADING_REG a5, f17, call_fn
+    LOOP_OVER_SHORTY_LOADING_REG a6, f18, call_fn
+    LOOP_OVER_SHORTY_LOADING_REG a7, f19, call_fn
+
+    # copy arguments onto stack (t2 should be multiples of 4)
+    ble    $t2, $zero, call_fn   # t2 = number of argument bytes remain
+1:
+    lw     $t3, 0($t1)           # load from argument array
+    daddiu $t1, $t1, 4
+    sw     $t3, 0($v0)           # save to stack
+    daddiu $t2, -4
+    bgt    $t2, $zero, 1b        # t2 = number of argument bytes remain
+    daddiu $v0, $v0, 4
+
+call_fn:
+    # call method (a0 and a1 have been untouched)
+    lwu    $a1, 0($a1)           # make a1 = this ptr
+    sw     $a1, 4($sp)           # copy this ptr (skip 4 bytes for method*)
+    sw     $zero, 0($sp)         # store NULL for method* at bottom of frame
+    ld     $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64($a0)  # get pointer to the code
+    jalr   $t9                   # call the method
+    nop
+    move   $sp, $s8              # restore sp
+
+    # pop a4, a5, s1(rSELF), s8, ra off of the stack
+    ld     $a4, 0($sp)
+    .cfi_restore 8
+    ld     $a5, 8($sp)
+    .cfi_restore 9
+    ld     $s0, 16($sp)
+    .cfi_restore 16
+    ld     $s1, 24($sp)
+    .cfi_restore 17
+    ld     $s8, 32($sp)
+    .cfi_restore 30
+    ld     $ra, 40($sp)
+    .cfi_restore 31
+    daddiu $sp, $sp, 48
+    .cfi_adjust_cfa_offset -48
+
+    # a4 = JValue* result
+    # a5 = shorty string
+    lbu   $t1, 0($a5)           # get result type from shorty
+    li    $t2, 68               # put char 'D' into t2
+    beq   $t1, $t2, 1f          # branch if result type char == 'D'
+    li    $t3, 70               # put char 'F' into t3
+    beq   $t1, $t3, 1f          # branch if result type char == 'F'
+    sw    $v0, 0($a4)           # store the result
+    dsrl  $v1, $v0, 32
+    jalr  $zero, $ra
+    sw    $v1, 4($a4)           # store the other half of the result
+1:
+    mfc1  $v0, $f0
+    mfhc1 $v1, $f0
+    sw    $v0, 0($a4)           # store the result
+    jalr  $zero, $ra
+    sw    $v1, 4($a4)           # store the other half of the result
+END art_quick_invoke_stub
+
+    /*
+     * Invocation static stub for quick code.
+     * On entry:
+     *   a0 = method pointer
+     *   a1 = argument array that must at least contain the this ptr.
+     *   a2 = size of argument array in bytes
+     *   a3 = (managed) thread pointer
+     *   a4 = JValue* result
+     *   a5 = shorty
+     */
+ENTRY art_quick_invoke_static_stub
+
+    # push a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra, onto the stack
+    daddiu $sp, $sp, -48
+    .cfi_adjust_cfa_offset 48
+    sd     $ra, 40($sp)
+    .cfi_rel_offset 31, 40
+    sd     $s8, 32($sp)
+    .cfi_rel_offset 30, 32
+    sd     $s1, 24($sp)
+    .cfi_rel_offset 17, 24
+    sd     $s0, 16($sp)
+    .cfi_rel_offset 16, 16
+    sd     $a5, 8($sp)
+    .cfi_rel_offset 9, 8
+    sd     $a4, 0($sp)
+    .cfi_rel_offset 8, 0
+
+    daddiu $s0, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
+    move   $s1, $a3              # move managed thread pointer into s1 (rSELF)
+    move   $s8, $sp              # save sp in s8 (fp)
+
+    daddiu $t3, $a2, 20          # add 4 for method* and 16 for stack alignment
+    dsrl   $t3, $t3, 4           # shift the frame size right 4
+    dsll   $t3, $t3, 4           # shift the frame size left 4 to align to 16 bytes
+    dsubu  $sp, $sp, $t3         # reserve stack space for argument array
+
+    daddiu $t0, $a5, 1           # t0 = shorty[1] (skip 1 for return type)
+    move   $t1, $a1              # t1 = arg_array
+    move   $t2, $a2              # t2 = number of argument bytes remain
+    daddiu $v0, $sp, 4           # v0 points to where to copy arg_array
+    LOOP_OVER_SHORTY_LOADING_REG a1, f13, call_sfn
+    LOOP_OVER_SHORTY_LOADING_REG a2, f14, call_sfn
+    LOOP_OVER_SHORTY_LOADING_REG a3, f15, call_sfn
+    LOOP_OVER_SHORTY_LOADING_REG a4, f16, call_sfn
+    LOOP_OVER_SHORTY_LOADING_REG a5, f17, call_sfn
+    LOOP_OVER_SHORTY_LOADING_REG a6, f18, call_sfn
+    LOOP_OVER_SHORTY_LOADING_REG a7, f19, call_sfn
+
+    # copy arguments onto stack (t2 should be multiples of 4)
+    ble    $t2, $zero, call_sfn  # t2 = number of argument bytes remain
+1:
+    lw     $t3, 0($t1)           # load from argument array
+    daddiu $t1, $t1, 4
+    sw     $t3, 0($v0)           # save to stack
+    daddiu $t2, -4
+    bgt    $t2, $zero, 1b        # t2 = number of argument bytes remain
+    daddiu $v0, $v0, 4
+
+call_sfn:
+    # call method (a0 has been untouched)
+    sw     $zero, 0($sp)         # store NULL for method* at bottom of frame
+    ld     $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64($a0)  # get pointer to the code
+    jalr   $t9                   # call the method
+    nop
+    move   $sp, $s8              # restore sp
+
+    # pop a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra off of the stack
+    ld     $a4, 0($sp)
+    .cfi_restore 8
+    ld     $a5, 8($sp)
+    .cfi_restore 9
+    ld     $s0, 16($sp)
+    .cfi_restore 16
+    ld     $s1, 24($sp)
+    .cfi_restore 17
+    ld     $s8, 32($sp)
+    .cfi_restore 30
+    ld     $ra, 40($sp)
+    .cfi_restore 31
+    daddiu $sp, $sp, 48
+    .cfi_adjust_cfa_offset -48
+
+    # a4 = JValue* result
+    # a5 = shorty string
+    lbu   $t1, 0($a5)           # get result type from shorty
+    li    $t2, 68               # put char 'D' into t2
+    beq   $t1, $t2, 1f          # branch if result type char == 'D'
+    li    $t3, 70               # put char 'F' into t3
+    beq   $t1, $t3, 1f          # branch if result type char == 'F'
+    sw    $v0, 0($a4)           # store the result
+    dsrl  $v1, $v0, 32
+    jalr  $zero, $ra
+    sw    $v1, 4($a4)           # store the other half of the result
+1:
+    mfc1  $v0, $f0
+    mfhc1 $v1, $f0
+    sw    $v0, 0($a4)           # store the result
+    jalr  $zero, $ra
+    sw    $v1, 4($a4)           # store the other half of the result
+END art_quick_invoke_static_stub
+
+
+
+UNIMPLEMENTED art_quick_handle_fill_data
+UNIMPLEMENTED art_quick_lock_object
+UNIMPLEMENTED art_quick_unlock_object
+UNIMPLEMENTED art_quick_check_cast
+UNIMPLEMENTED art_quick_aput_obj_with_null_and_bound_check
+UNIMPLEMENTED art_quick_aput_obj_with_bound_check
+UNIMPLEMENTED art_quick_aput_obj
+UNIMPLEMENTED art_quick_initialize_static_storage
+UNIMPLEMENTED art_quick_initialize_type
+UNIMPLEMENTED art_quick_initialize_type_and_verify_access
+UNIMPLEMENTED art_quick_get_boolean_static
+UNIMPLEMENTED art_quick_get_byte_static
+UNIMPLEMENTED art_quick_get_char_static
+UNIMPLEMENTED art_quick_get_short_static
+UNIMPLEMENTED art_quick_get32_static
+UNIMPLEMENTED art_quick_get64_static
+UNIMPLEMENTED art_quick_get_obj_static
+UNIMPLEMENTED art_quick_get_boolean_instance
+UNIMPLEMENTED art_quick_get_byte_instance
+UNIMPLEMENTED art_quick_get_char_instance
+UNIMPLEMENTED art_quick_get_short_instance
+UNIMPLEMENTED art_quick_get32_instance
+UNIMPLEMENTED art_quick_get64_instance
+UNIMPLEMENTED art_quick_get_obj_instance
+UNIMPLEMENTED art_quick_set8_static
+UNIMPLEMENTED art_quick_set16_static
+UNIMPLEMENTED art_quick_set32_static
+UNIMPLEMENTED art_quick_set64_static
+UNIMPLEMENTED art_quick_set_obj_static
+UNIMPLEMENTED art_quick_set8_instance
+UNIMPLEMENTED art_quick_set16_instance
+UNIMPLEMENTED art_quick_set32_instance
+UNIMPLEMENTED art_quick_set64_instance
+UNIMPLEMENTED art_quick_set_obj_instance
+UNIMPLEMENTED art_quick_resolve_string
+
+// Macro to facilitate adding new allocation entrypoints.
+.macro TWO_ARG_DOWNCALL name, entrypoint, return
+ENTRY \name
+    break
+    break
+END \name
+.endm
+
+.macro THREE_ARG_DOWNCALL name, entrypoint, return
+ENTRY \name
+    break
+    break
+END \name
+.endm
+
+// Generate the allocation entrypoints for each allocator.
+GENERATE_ALL_ALLOC_ENTRYPOINTS
+
+UNIMPLEMENTED art_quick_test_suspend
+UNIMPLEMENTED art_quick_proxy_invoke_handler
+UNIMPLEMENTED art_quick_imt_conflict_trampoline
+UNIMPLEMENTED art_quick_resolution_trampoline
+
+    .extern artQuickGenericJniTrampoline
+    .extern artQuickGenericJniEndTrampoline
+ENTRY art_quick_generic_jni_trampoline
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+    sd      $a0, 0($sp)            # store native ArtMethod* to bottom of stack
+    move    $s8, $sp               # save $sp
+
+    # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
+    move    $a0, rSELF             # pass Thread::Current
+    move    $a1, $sp               # pass $sp
+    jal     artQuickGenericJniTrampoline   # (Thread*, SP)
+    daddiu  $sp, $sp, -5120        # reserve space on the stack
+
+    # The C call will have registered the complete save-frame on success.
+    # The result of the call is:
+    # v0: ptr to native code, 0 on error.
+    # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
+    beq     $v0, $zero, 1f         # check entry error
+    move    $t9, $v0               # save the code ptr
+    move    $sp, $v1               # release part of the alloca
+
+    # Load parameters from stack into registers
+    ld      $a0,   0($sp)
+    ld      $a1,   8($sp)
+    ld      $a2,  16($sp)
+    ld      $a3,  24($sp)
+    ld      $a4,  32($sp)
+    ld      $a5,  40($sp)
+    ld      $a6,  48($sp)
+    ld      $a7,  56($sp)
+    # Load FPRs the same as GPRs. Look at BuildNativeCallFrameStateMachine.
+    l.d     $f12,  0($sp)
+    l.d     $f13,  8($sp)
+    l.d     $f14, 16($sp)
+    l.d     $f15, 24($sp)
+    l.d     $f16, 32($sp)
+    l.d     $f17, 40($sp)
+    l.d     $f18, 48($sp)
+    l.d     $f19, 56($sp)
+    jalr    $t9                    # native call
+    daddiu  $sp, $sp, 64
+
+    # result sign extension is handled in C code
+    # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
+    move    $a0, rSELF             # pass Thread::Current
+    move    $a1, $v0
+    jal     artQuickGenericJniEndTrampoline
+    dmfc1   $a2, $f0
+
+    ld      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
+    bne     $t0, $zero, 2f         # check for pending exceptions
+    move    $sp, $s8               # tear down the alloca
+
+    # tear dpown the callee-save frame
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+
+    jalr    $zero, $ra
+    dmtc1   $v0, $f0               # place return value to FP return value
+
+1:
+    move    $sp, $s8               # tear down the alloca
+2:
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    DELIVER_PENDING_EXCEPTION
+END art_quick_generic_jni_trampoline
+
+    .extern artQuickToInterpreterBridge
+ENTRY art_quick_to_interpreter_bridge
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    move    $a1, rSELF             # pass Thread::Current
+    jal     artQuickToInterpreterBridge    # (Method* method, Thread*, SP)
+    move    $a2, $sp               # pass $sp
+    ld      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
+    daddiu  $sp, $sp, REFS_AND_ARGS_MINUS_REFS_SIZE  # skip a0-a7 and f12-f19
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    bne     $t0, $zero, 1f
+    dmtc1   $v0, $f0               # place return value to FP return value
+    jalr    $zero, $ra
+    dmtc1   $v1, $f1               # place return value to FP return value
+1:
+    DELIVER_PENDING_EXCEPTION
+END art_quick_to_interpreter_bridge
+
+    /*
+     * Routine that intercepts method calls and returns.
+     */
+    .extern artInstrumentationMethodEntryFromCode
+    .extern artInstrumentationMethodExitFromCode
+ENTRY art_quick_instrumentation_entry
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    daddiu   $sp, $sp, -16     # space for saving arg0
+    .cfi_adjust_cfa_offset 16
+    sd       $a0, 0($sp)       # save arg0
+    move     $a3, $ra          # pass $ra
+    jal      artInstrumentationMethodEntryFromCode  # (Method*, Object*, Thread*, RA)
+    move     $a2, rSELF        # pass Thread::Current
+    move     $t9, $v0          # $t9 holds reference to code
+    ld       $a0, 0($sp)       # restore arg0
+    daddiu   $sp, $sp, 16      # remove args
+    .cfi_adjust_cfa_offset -16
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
+    jalr     $t9               # call method
+    nop
+END art_quick_instrumentation_entry
+    /* intentional fallthrough */
+    .global art_quick_instrumentation_exit
+art_quick_instrumentation_exit:
+    .cfi_startproc
+    daddiu   $t9, $ra, 4       # put current address into $t9 to rebuild $gp
+    .cpload  $t9
+    move     $ra, $zero        # link register is to here, so clobber with 0 for later checks
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+    move     $t0, $sp          # remember bottom of caller's frame
+    daddiu   $sp, $sp, -16     # save return values and set up args
+    .cfi_adjust_cfa_offset 16
+    sd       $v0, 0($sp)
+    .cfi_rel_offset 2, 0
+    s.d      $f0, 8($sp)
+    mov.d    $f15, $f0         # pass fpr result
+    move     $a2, $v0          # pass gpr result
+    move     $a1, $t0          # pass $sp
+    jal      artInstrumentationMethodExitFromCode  # (Thread*, SP, gpr_res, fpr_res)
+    move     $a0, rSELF        # pass Thread::Current
+    move     $t0, $v0          # set aside returned link register
+    move     $ra, $v1          # set link register for deoptimization
+    ld       $v0, 0($sp)       # restore return values
+    l.d      $f0, 8($sp)
+    jalr     $zero, $t0        # return
+    daddiu   $sp, $sp, 16+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE  # 16 bytes of saved values + ref_only callee save frame
+    .cfi_adjust_cfa_offset -(16+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
+END art_quick_instrumentation_exit
+
+UNIMPLEMENTED art_quick_deoptimize
+UNIMPLEMENTED art_quick_indexof
+UNIMPLEMENTED art_quick_string_compareto
diff --git a/runtime/arch/mips64/quick_method_frame_info_mips64.h b/runtime/arch/mips64/quick_method_frame_info_mips64.h
new file mode 100644
index 0000000..de55e81
--- /dev/null
+++ b/runtime/arch/mips64/quick_method_frame_info_mips64.h
@@ -0,0 +1,76 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_mips64.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace mips64 {
+
+static constexpr uint32_t kMips64CalleeSaveRefSpills =
+    (1 << art::mips64::S2) | (1 << art::mips64::S3) | (1 << art::mips64::S4) |
+    (1 << art::mips64::S5) | (1 << art::mips64::S6) | (1 << art::mips64::S7) |
+    (1 << art::mips64::GP) | (1 << art::mips64::S8);
+static constexpr uint32_t kMips64CalleeSaveArgSpills =
+    (1 << art::mips64::A1) | (1 << art::mips64::A2) | (1 << art::mips64::A3) |
+    (1 << art::mips64::A4) | (1 << art::mips64::A5) | (1 << art::mips64::A6) |
+    (1 << art::mips64::A7);
+static constexpr uint32_t kMips64CalleeSaveAllSpills =
+    (1 << art::mips64::S0) | (1 << art::mips64::S1);
+
+static constexpr uint32_t kMips64CalleeSaveFpRefSpills = 0;
+static constexpr uint32_t kMips64CalleeSaveFpArgSpills =
+    (1 << art::mips64::F12) | (1 << art::mips64::F13) | (1 << art::mips64::F14) |
+    (1 << art::mips64::F15) | (1 << art::mips64::F16) | (1 << art::mips64::F17) |
+    (1 << art::mips64::F18) | (1 << art::mips64::F19);
+// F12 should not be necessary to spill, as A0 is always in use.
+static constexpr uint32_t kMips64CalleeSaveFpAllSpills =
+    (1 << art::mips64::F24) | (1 << art::mips64::F25) | (1 << art::mips64::F26) |
+    (1 << art::mips64::F27) | (1 << art::mips64::F28) | (1 << art::mips64::F29) |
+    (1 << art::mips64::F30) | (1 << art::mips64::F31);
+
+constexpr uint32_t Mips64CalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kMips64CalleeSaveRefSpills |
+      (type == Runtime::kRefsAndArgs ? kMips64CalleeSaveArgSpills : 0) |
+      (type == Runtime::kSaveAll ? kMips64CalleeSaveAllSpills : 0) | (1 << art::mips64::RA);
+}
+
+constexpr uint32_t Mips64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
+  return kMips64CalleeSaveFpRefSpills |
+      (type == Runtime::kRefsAndArgs ? kMips64CalleeSaveFpArgSpills: 0) |
+      (type == Runtime::kSaveAll ? kMips64CalleeSaveFpAllSpills : 0);
+}
+
+constexpr uint32_t Mips64CalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(Mips64CalleeSaveCoreSpills(type)) /* gprs */ +
+                  POPCOUNT(Mips64CalleeSaveFpSpills(type))   /* fprs */ +
+                  + 1 /* Method* */) * kMips64PointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo Mips64CalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(Mips64CalleeSaveFrameSize(type),
+                              Mips64CalleeSaveCoreSpills(type),
+                              Mips64CalleeSaveFpSpills(type));
+}
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_
diff --git a/runtime/arch/mips64/registers_mips64.cc b/runtime/arch/mips64/registers_mips64.cc
new file mode 100644
index 0000000..4959208
--- /dev/null
+++ b/runtime/arch/mips64/registers_mips64.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "registers_mips64.h"
+
+#include <ostream>
+
+namespace art {
+namespace mips64 {
+
+static const char* kRegisterNames[] = {
+  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+  "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+  "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+  "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
+};
+
+std::ostream& operator<<(std::ostream& os, const GpuRegister& rhs) {
+  if (rhs >= ZERO && rhs < kNumberOfGpuRegisters) {
+    os << kRegisterNames[rhs];
+  } else {
+    os << "GpuRegister[" << static_cast<int>(rhs) << "]";
+  }
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const FpuRegister& rhs) {
+  if (rhs >= F0 && rhs < kNumberOfFpuRegisters) {
+    os << "f" << static_cast<int>(rhs);
+  } else {
+    os << "FpuRegister[" << static_cast<int>(rhs) << "]";
+  }
+  return os;
+}
+
+}  // namespace mips64
+}  // namespace art
diff --git a/runtime/arch/mips64/registers_mips64.h b/runtime/arch/mips64/registers_mips64.h
new file mode 100644
index 0000000..38bc8f2
--- /dev/null
+++ b/runtime/arch/mips64/registers_mips64.h
@@ -0,0 +1,109 @@
+/*
+ * 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_RUNTIME_ARCH_MIPS64_REGISTERS_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_REGISTERS_MIPS64_H_
+
+#include <iosfwd>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "globals.h"
+
+namespace art {
+namespace mips64 {
+
+enum GpuRegister {
+  ZERO =  0,
+  AT   =  1,  // Assembler temporary.
+  V0   =  2,  // Values.
+  V1   =  3,
+  A0   =  4,  // Arguments.
+  A1   =  5,
+  A2   =  6,
+  A3   =  7,
+  A4   =  8,
+  A5   =  9,
+  A6   = 10,
+  A7   = 11,
+  T0   = 12,  // Temporaries.
+  T1   = 13,
+  T2   = 14,
+  T3   = 15,
+  S0   = 16,  // Saved values.
+  S1   = 17,
+  S2   = 18,
+  S3   = 19,
+  S4   = 20,
+  S5   = 21,
+  S6   = 22,
+  S7   = 23,
+  T8   = 24,  // More temporaries.
+  T9   = 25,
+  K0   = 26,  // Reserved for trap handler.
+  K1   = 27,
+  GP   = 28,  // Global pointer.
+  SP   = 29,  // Stack pointer.
+  S8   = 30,  // Saved value/frame pointer.
+  RA   = 31,  // Return address.
+  kNumberOfGpuRegisters = 32,
+  kNoGpuRegister = -1  // Signals an illegal register.
+};
+std::ostream& operator<<(std::ostream& os, const GpuRegister& rhs);
+
+// Values for floating point registers.
+enum FpuRegister {
+  F0  =  0,
+  F1  =  1,
+  F2  =  2,
+  F3  =  3,
+  F4  =  4,
+  F5  =  5,
+  F6  =  6,
+  F7  =  7,
+  F8  =  8,
+  F9  =  9,
+  F10 = 10,
+  F11 = 11,
+  F12 = 12,
+  F13 = 13,
+  F14 = 14,
+  F15 = 15,
+  F16 = 16,
+  F17 = 17,
+  F18 = 18,
+  F19 = 19,
+  F20 = 20,
+  F21 = 21,
+  F22 = 22,
+  F23 = 23,
+  F24 = 24,
+  F25 = 25,
+  F26 = 26,
+  F27 = 27,
+  F28 = 28,
+  F29 = 29,
+  F30 = 30,
+  F31 = 31,
+  kNumberOfFpuRegisters = 32,
+  kNoFpuRegister = -1,
+};
+std::ostream& operator<<(std::ostream& os, const FpuRegister& rhs);
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_REGISTERS_MIPS64_H_
diff --git a/runtime/arch/mips64/thread_mips64.cc b/runtime/arch/mips64/thread_mips64.cc
new file mode 100644
index 0000000..c55537c
--- /dev/null
+++ b/runtime/arch/mips64/thread_mips64.cc
@@ -0,0 +1,34 @@
+/*
+ * 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 "thread.h"
+
+#include "asm_support_mips64.h"
+#include "base/logging.h"
+
+namespace art {
+
+void Thread::InitCpu() {
+  CHECK_EQ(THREAD_FLAGS_OFFSET, ThreadFlagsOffset<8>().Int32Value());
+  CHECK_EQ(THREAD_CARD_TABLE_OFFSET, CardTableOffset<8>().Int32Value());
+  CHECK_EQ(THREAD_EXCEPTION_OFFSET, ExceptionOffset<8>().Int32Value());
+}
+
+void Thread::CleanupCpu() {
+  // Do nothing.
+}
+
+}  // namespace art
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index 632c5f3..53b9f4e 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -16,25 +16,25 @@
 
 .macro GENERATE_ALLOC_ENTRYPOINTS c_suffix, cxx_suffix
 // Called by managed code to allocate an object.
-TWO_ARG_DOWNCALL art_quick_alloc_object\c_suffix, artAllocObjectFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_alloc_object\c_suffix, artAllocObjectFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an object of a resolved class.
-TWO_ARG_DOWNCALL art_quick_alloc_object_resolved\c_suffix, artAllocObjectFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_alloc_object_resolved\c_suffix, artAllocObjectFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an object of an initialized class.
-TWO_ARG_DOWNCALL art_quick_alloc_object_initialized\c_suffix, artAllocObjectFromCodeInitialized\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_alloc_object_initialized\c_suffix, artAllocObjectFromCodeInitialized\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an object when the caller doesn't know whether it has access
 // to the created type.
-TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check\c_suffix, artAllocObjectFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check\c_suffix, artAllocObjectFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an array.
-THREE_ARG_DOWNCALL art_quick_alloc_array\c_suffix, artAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+THREE_ARG_DOWNCALL art_quick_alloc_array\c_suffix, artAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an array of a resolve class.
-THREE_ARG_DOWNCALL art_quick_alloc_array_resolved\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+THREE_ARG_DOWNCALL art_quick_alloc_array_resolved\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an array when the caller doesn't know whether it has access
 // to the created type.
-THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check\c_suffix, artAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check\c_suffix, artAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
-THREE_ARG_DOWNCALL art_quick_check_and_alloc_array\c_suffix, artCheckAndAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+THREE_ARG_DOWNCALL art_quick_check_and_alloc_array\c_suffix, artCheckAndAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 // Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
-THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_with_access_check\c_suffix, artCheckAndAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_with_access_check\c_suffix, artCheckAndAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 .endm
 
 .macro GENERATE_ALL_ALLOC_ENTRYPOINTS
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 6b74a1b..986b7ec 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -41,7 +41,7 @@
       for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
         Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
         if (!runtime_->HasCalleeSaveMethod(type)) {
-          runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(type), type);
+          runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(), type);
         }
       }
     }
@@ -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__(
@@ -530,18 +530,6 @@
 #endif
   }
 
-  // Method with 32b arg0, 32b arg1, 64b arg2
-  size_t Invoke3UUWithReferrer(uint32_t arg0, uint32_t arg1, uint64_t arg2, uintptr_t code,
-                               Thread* self, mirror::ArtMethod* referrer) {
-#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
-    // Just pass through.
-    return Invoke3WithReferrer(arg0, arg1, arg2, code, self, referrer);
-#else
-    // TODO: Needs 4-param invoke.
-    return 0;
-#endif
-  }
-
   static uintptr_t GetEntrypoint(Thread* self, QuickEntrypointEnum entrypoint) {
     int32_t offset;
 #ifdef __LP64__
@@ -744,17 +732,17 @@
         EXPECT_EQ(LockWord::LockState::kFatLocked, iter_state);
       }
     } else {
-      bool lock;  // Whether to lock or unlock in this step.
+      bool take_lock;  // Whether to lock or unlock in this step.
       if (counts[index] == 0) {
-        lock = true;
+        take_lock = true;
       } else if (counts[index] == kThinLockLoops) {
-        lock = false;
+        take_lock = false;
       } else {
         // Randomly.
-        lock = r.next() % 2 == 0;
+        take_lock = r.next() % 2 == 0;
       }
 
-      if (lock) {
+      if (take_lock) {
         test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U, art_quick_lock_object,
                       self);
         counts[index]++;
@@ -811,6 +799,9 @@
 }
 
 TEST_F(StubTest, UnlockObject) {
+  // This will lead to monitor error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   TestUnlockObject(this);
 }
 
@@ -1004,6 +995,9 @@
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
+  // This will lead to OOM  error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();
@@ -1128,6 +1122,9 @@
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   // TODO: Check the "Unresolved" allocation stubs
 
+  // This will lead to OOM  error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   Thread* self = Thread::Current();
   // Create an object
   ScopedObjectAccess soa(self);
@@ -1148,11 +1145,11 @@
   // 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
                             10U,
+                            reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0)),  // arbitrary
                             StubTest::GetEntrypoint(self, kQuickAllocArray),
                             self);
 
@@ -1167,7 +1164,8 @@
   {
     // We can use nullptr in the second argument as we do not need a method here (not used in
     // resolved/initialized cases)
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr), 10U,
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 10U,
+                            reinterpret_cast<size_t>(nullptr),
                             StubTest::GetEntrypoint(self, kQuickAllocArrayResolved),
                             self);
     EXPECT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException(nullptr));
@@ -1185,8 +1183,9 @@
 
   // Out-of-memory.
   {
-    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), reinterpret_cast<size_t>(nullptr),
+    size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()),
                             GB,  // that should fail...
+                            reinterpret_cast<size_t>(nullptr),
                             StubTest::GetEntrypoint(self, kQuickAllocArrayResolved),
                             self);
 
@@ -1221,13 +1220,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);
@@ -1304,8 +1302,8 @@
 }
 
 
-static void GetSetBooleanStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                           mirror::ArtMethod* referrer, StubTest* test)
+static void GetSetBooleanStatic(Handle<mirror::ArtField>* f, 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;
@@ -1333,14 +1331,13 @@
   std::cout << "Skipping set_boolean_static as I don't know how to do that on " << kRuntimeISA << std::endl;
 #endif
 }
-static void GetSetByteStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                           mirror::ArtMethod* referrer, StubTest* test)
+static void GetSetByteStatic(Handle<mirror::ArtField>* f, 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()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1364,13 +1361,12 @@
 
 
 static void GetSetBooleanInstance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
-                             Thread* self, mirror::ArtMethod* referrer, StubTest* test)
+                                  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 +1397,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]),
@@ -1431,14 +1426,13 @@
 #endif
 }
 
-static void GetSetCharStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                           mirror::ArtMethod* referrer, StubTest* test)
+static void GetSetCharStatic(Handle<mirror::ArtField>* f, 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()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1460,14 +1454,13 @@
   std::cout << "Skipping set_char_static as I don't know how to do that on " << kRuntimeISA << std::endl;
 #endif
 }
-static void GetSetShortStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                           mirror::ArtMethod* referrer, StubTest* test)
+static void GetSetShortStatic(Handle<mirror::ArtField>* f, 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()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1494,10 +1487,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 +1519,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]),
@@ -1557,14 +1548,13 @@
 #endif
 }
 
-static void GetSet32Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                           mirror::ArtMethod* referrer, StubTest* test)
+static void GetSet32Static(Handle<mirror::ArtField>* f, 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()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1592,10 +1582,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]),
@@ -1647,8 +1636,8 @@
 }
 #endif
 
-static void GetSetObjStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                            mirror::ArtMethod* referrer, StubTest* test)
+static void GetSetObjStatic(Handle<mirror::ArtField>* f, 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__))
   set_and_check_static((*f)->GetDexFieldIndex(), nullptr, self, referrer, test);
@@ -1712,14 +1701,13 @@
 
 // TODO: Complete these tests for 32b architectures.
 
-static void GetSet64Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
-                           mirror::ArtMethod* referrer, StubTest* test)
+static void GetSet64Static(Handle<mirror::ArtField>* f, 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->Invoke3UWithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                values[i],
                                StubTest::GetEntrypoint(self, kQuickSet64Static),
@@ -1735,6 +1723,7 @@
     EXPECT_EQ(res, values[i]) << "Iteration " << i;
   }
 #else
+  UNUSED(f, self, referrer, test);
   LOG(INFO) << "Skipping set64static as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set64static as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -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]),
@@ -1772,6 +1760,7 @@
     EXPECT_EQ(res, static_cast<int64_t>(res2));
   }
 #else
+  UNUSED(obj, f, self, referrer, test);
   LOG(INFO) << "Skipping set64instance as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
   std::cout << "Skipping set64instance as I don't know how to do that on " << kRuntimeISA << std::endl;
@@ -1801,47 +1790,47 @@
     Handle<mirror::ObjectArray<mirror::ArtField>> fields(hs.NewHandle(c.Get()->GetSFields()));
     int32_t num_fields = fields->GetLength();
     for (int32_t i = 0; i < num_fields; ++i) {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::ArtField> f(hs.NewHandle(fields->Get(i)));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::ArtField> f(hs2.NewHandle(fields->Get(i)));
 
       Primitive::Type type = f->GetTypeAsPrimitiveType();
       switch (type) {
         case Primitive::Type::kPrimBoolean:
           if (test_type == type) {
-            GetSetBooleanStatic(&obj, &f, self, m.Get(), test);
+            GetSetBooleanStatic(&f, self, m.Get(), test);
           }
           break;
         case Primitive::Type::kPrimByte:
           if (test_type == type) {
-            GetSetByteStatic(&obj, &f, self, m.Get(), test);
+            GetSetByteStatic(&f, self, m.Get(), test);
           }
           break;
         case Primitive::Type::kPrimChar:
           if (test_type == type) {
-            GetSetCharStatic(&obj, &f, self, m.Get(), test);
+            GetSetCharStatic(&f, self, m.Get(), test);
           }
           break;
         case Primitive::Type::kPrimShort:
           if (test_type == type) {
-            GetSetShortStatic(&obj, &f, self, m.Get(), test);
+            GetSetShortStatic(&f, self, m.Get(), test);
           }
           break;
         case Primitive::Type::kPrimInt:
           if (test_type == type) {
-            GetSet32Static(&obj, &f, self, m.Get(), test);
+            GetSet32Static(&f, self, m.Get(), test);
           }
           break;
 
         case Primitive::Type::kPrimLong:
           if (test_type == type) {
-            GetSet64Static(&obj, &f, self, m.Get(), test);
+            GetSet64Static(&f, self, m.Get(), test);
           }
           break;
 
         case Primitive::Type::kPrimNot:
           // Don't try array.
           if (test_type == type && f->GetTypeDescriptor()[0] != '[') {
-            GetSetObjStatic(&obj, &f, self, m.Get(), test);
+            GetSetObjStatic(&f, self, m.Get(), test);
           }
           break;
 
@@ -1856,8 +1845,8 @@
     Handle<mirror::ObjectArray<mirror::ArtField>> fields(hs.NewHandle(c.Get()->GetIFields()));
     int32_t num_fields = fields->GetLength();
     for (int32_t i = 0; i < num_fields; ++i) {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::ArtField> f(hs.NewHandle(fields->Get(i)));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::ArtField> f(hs2.NewHandle(fields->Get(i)));
 
       Primitive::Type type = f->GetTypeAsPrimitiveType();
       switch (type) {
@@ -2109,10 +2098,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/context_x86.cc b/runtime/arch/x86/context_x86.cc
index 37049cf..49aa326 100644
--- a/runtime/arch/x86/context_x86.cc
+++ b/runtime/arch/x86/context_x86.cc
@@ -17,9 +17,9 @@
 #include "context_x86.h"
 
 #include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
 #include "quick/quick_method_frame_info.h"
-#include "stack.h"
+#include "utils.h"
+
 
 namespace art {
 namespace x86 {
@@ -72,6 +72,16 @@
   }
 }
 
+bool X86Context::GetFPR(uint32_t reg ATTRIBUTE_UNUSED, uintptr_t* val ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "Floating-point registers are all caller save in X86";
+  UNREACHABLE();
+}
+
+bool X86Context::SetFPR(uint32_t reg ATTRIBUTE_UNUSED, uintptr_t value ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "Floating-point registers are all caller save in X86";
+  UNREACHABLE();
+}
+
 void X86Context::DoLongJump() {
 #if defined(__i386__)
   // Array of GPR values, filled from the context backward for the long jump pop. We add a slot at
@@ -81,7 +91,7 @@
     gprs[kNumberOfCpuRegisters - i - 1] = gprs_[i] != nullptr ? *gprs_[i] : X86Context::kBadGprBase + i;
   }
   // We want to load the stack pointer one slot below so that the ret will pop eip.
-  uintptr_t esp = gprs[kNumberOfCpuRegisters - ESP - 1] - kWordSize;
+  uintptr_t esp = gprs[kNumberOfCpuRegisters - ESP - 1] - sizeof(intptr_t);
   gprs[kNumberOfCpuRegisters] = esp;
   *(reinterpret_cast<uintptr_t*>(esp)) = eip_;
   __asm__ __volatile__(
diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h
index a350b25..01c8b82 100644
--- a/runtime/arch/x86/context_x86.h
+++ b/runtime/arch/x86/context_x86.h
@@ -62,15 +62,9 @@
 
   bool SetGPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
-  bool GetFPR(uint32_t reg, uintptr_t* val) OVERRIDE {
-    LOG(FATAL) << "Floating-point registers are all caller save in X86";
-    return false;
-  }
+  bool GetFPR(uint32_t reg, uintptr_t* val) OVERRIDE;
 
-  bool SetFPR(uint32_t reg, uintptr_t value) OVERRIDE {
-    LOG(FATAL) << "Floating-point registers are all caller save in X86";
-    return false;
-  }
+  bool SetFPR(uint32_t reg, uintptr_t value) OVERRIDE;
 
   void SmashCallerSaves() OVERRIDE;
   void DoLongJump() OVERRIDE;
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 682c502..7cdd2fc 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -16,114 +16,20 @@
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/jni/jni_entrypoints.h"
-#include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/quick/quick_default_externs.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*);
-
 // Cast entrypoints.
 extern "C" uint32_t art_quick_is_assignable(const mirror::Class* klass,
-                                                const mirror::Class* ref_class);
-extern "C" void art_quick_check_cast(void*, void*);
-
-// DexCache entrypoints.
-extern "C" void* art_quick_initialize_static_storage(uint32_t, void*);
-extern "C" void* art_quick_initialize_type(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, void*);
-extern "C" void* art_quick_resolve_string(void*, uint32_t);
-
-// Field entrypoints.
-extern "C" int art_quick_set8_instance(uint32_t, void*, int8_t);
-extern "C" int art_quick_set8_static(uint32_t, int8_t);
-extern "C" int art_quick_set16_instance(uint32_t, void*, int16_t);
-extern "C" int art_quick_set16_static(uint32_t, int16_t);
-extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t);
-extern "C" int art_quick_set32_static(uint32_t, int32_t);
-extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t);
-extern "C" int art_quick_set64_static(uint32_t, int64_t);
-extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*);
-extern "C" int art_quick_set_obj_static(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_instance(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_instance(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_static(uint32_t);
-extern "C" uint8_t art_quick_get_boolean_static(uint32_t);
-extern "C" int16_t art_quick_get_short_instance(uint32_t, void*);
-extern "C" uint16_t art_quick_get_char_instance(uint32_t, void*);
-extern "C" int16_t art_quick_get_short_static(uint32_t);
-extern "C" uint16_t art_quick_get_char_static(uint32_t);
-extern "C" int32_t art_quick_get32_instance(uint32_t, void*);
-extern "C" int32_t art_quick_get32_static(uint32_t);
-extern "C" int64_t art_quick_get64_instance(uint32_t, void*);
-extern "C" int64_t art_quick_get64_static(uint32_t);
-extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
-extern "C" void* art_quick_get_obj_static(uint32_t);
-
-// Array entrypoints.
-extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
-extern "C" void art_quick_handle_fill_data(void*, void*);
-
-// Lock entrypoints.
-extern "C" void art_quick_lock_object(void*);
-extern "C" void art_quick_unlock_object(void*);
-
-// Math entrypoints.
-extern "C" int64_t art_quick_d2l(double);
-extern "C" int64_t art_quick_f2l(float);
-extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
-extern "C" int64_t art_quick_lmod(int64_t, int64_t);
-extern "C" int64_t art_quick_lmul(int64_t, int64_t);
-extern "C" uint64_t art_quick_lshl(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_lshr(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_lushr(uint64_t, uint32_t);
-
-// Intrinsic entrypoints.
-extern "C" int32_t art_quick_string_compareto(void*, void*);
-extern "C" void* art_quick_memcpy(void*, const void*, size_t);
-
-// Invoke entrypoints.
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-
-// Thread entrypoints.
-extern "C" void art_quick_test_suspend();
-
-// Throw entrypoints.
-extern "C" void art_quick_deliver_exception(void*);
-extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
-extern "C" void art_quick_throw_div_zero();
-extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
-extern "C" void art_quick_throw_null_pointer_exception();
-extern "C" void art_quick_throw_stack_overflow(void*);
-
-// Generic JNI downcall
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-
-extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
+                                            const mirror::Class* ref_class);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
-                     PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
+                     QuickEntryPoints* qpoints) {
   // Interpreter
   ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge;
   ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge;
@@ -131,10 +37,6 @@
   // JNI
   jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
 
-  // Portable
-  ppoints->pPortableResolutionTrampoline = art_portable_resolution_trampoline;
-  ppoints->pPortableToInterpreterBridge = art_portable_to_interpreter_bridge;
-
   // Alloc
   ResetQuickAllocEntryPoints(qpoints);
 
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 17310b6..ad962e2 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -113,7 +113,7 @@
       // Group 3
       case 0x66:
         operand_size_prefix = true;
-        // fallthrough
+        FALLTHROUGH_INTENDED;
 
       // Group 1
       case 0xf0:
@@ -184,6 +184,7 @@
 
       case 0x80:        // group 1, byte immediate.
       case 0x83:
+      case 0xc6:
         modrm = *pc++;
         has_modrm = true;
         immediate_size = 1;
@@ -230,7 +231,7 @@
   return pc - startpc;
 }
 
-void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+void FaultManager::HandleNestedSignal(int, siginfo_t*, void* context) {
   // For the Intel architectures we need to go to an assembly language
   // stub.  This is because the 32 bit call to longjmp is much different
   // from the 64 bit ABI call and pushing things onto the stack inside this
@@ -283,7 +284,7 @@
   *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
 }
 
-bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
+bool NullPointerHandler::Action(int, siginfo_t*, void* context) {
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
   uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
@@ -323,7 +324,7 @@
 // The offset from fs is Thread::ThreadSuspendTriggerOffset().
 // To check for a suspend check, we examine the instructions that caused
 // the fault.
-bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
+bool SuspensionHandler::Action(int, siginfo_t*, void* context) {
   // These are the instructions to check for.  The first one is the mov eax, fs:[xxx]
   // where xxx is the offset of the suspend trigger.
 #if defined(__x86_64__)
@@ -397,7 +398,7 @@
 // This is done before any frame is established in the method.  The return
 // address for the previous method is on the stack at ESP.
 
-bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
+bool StackOverflowHandler::Action(int, siginfo_t* info, void* context) {
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   uintptr_t sp = static_cast<uintptr_t>(uc->CTX_ESP);
 
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
new file mode 100644
index 0000000..a12773d
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -0,0 +1,276 @@
+/*
+ * 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 "instruction_set_features_x86.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "arch/x86_64/instruction_set_features_x86_64.h"
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromVariant(
+    const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED,
+    bool x86_64) {
+  bool known_variant = false;
+  bool smp = true;  // Conservative default.
+  static const char* x86_variants_with_ssse3[] = {
+      "atom"
+  };
+  bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
+                                      variant);
+  bool has_SSE4_1 = false;
+  bool has_SSE4_2 = false;
+  bool has_AVX = false;
+  bool has_AVX2 = false;
+  if (!known_variant && variant != "default") {
+    std::ostringstream os;
+    LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
+  }
+
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromBitmap(uint32_t bitmap,
+                                                                       bool x86_64) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
+  bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
+  bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
+  bool has_AVX = (bitmap & kAvxBitfield) != 0;
+  bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
+  const bool smp = true;
+
+#ifndef __SSSE3__
+  const bool has_SSSE3 = false;
+#else
+  const bool has_SSSE3 = true;
+#endif
+
+#ifndef __SSE4_1__
+  const bool has_SSE4_1 = false;
+#else
+  const bool has_SSE4_1 = true;
+#endif
+
+#ifndef __SSE4_2__
+  const bool has_SSE4_2 = false;
+#else
+  const bool has_SSE4_2 = true;
+#endif
+
+#ifndef __AVX__
+  const bool has_AVX = false;
+#else
+  const bool has_AVX = true;
+#endif
+
+#ifndef __AVX2__
+  const bool has_AVX2 = false;
+#else
+  const bool has_AVX2 = true;
+#endif
+
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
+  // 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 smp = false;
+  bool has_SSSE3 = false;
+  bool has_SSE4_1 = false;
+  bool has_SSE4_2 = false;
+  bool has_AVX = false;
+  bool has_AVX2 = 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("flags") != std::string::npos) {
+          LOG(INFO) << "found flags";
+          if (line.find("ssse3") != std::string::npos) {
+            has_SSSE3 = true;
+          }
+          if (line.find("sse4_1") != std::string::npos) {
+            has_SSE4_1 = true;
+          }
+          if (line.find("sse4_2") != std::string::npos) {
+            has_SSE4_2 = true;
+          }
+          if (line.find("avx") != std::string::npos) {
+            has_AVX = true;
+          }
+          if (line.find("avx2") != std::string::npos) {
+            has_AVX2 = true;
+          }
+        } else if (line.find("processor") != std::string::npos &&
+            line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromHwcap(bool x86_64) {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines(x86_64);
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromAssembly(bool x86_64) {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines(x86_64);
+}
+
+bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (GetInstructionSet() != other->GetInstructionSet()) {
+    return false;
+  }
+  const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
+  return (IsSmp() == other->IsSmp()) &&
+      (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
+      (has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
+      (has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
+      (has_AVX_ == other_as_x86->has_AVX_) &&
+      (has_AVX2_ == other_as_x86->has_AVX2_);
+}
+
+uint32_t X86InstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) |
+      (has_SSSE3_ ? kSsse3Bitfield : 0) |
+      (has_SSE4_1_ ? kSse4_1Bitfield : 0) |
+      (has_SSE4_2_ ? kSse4_2Bitfield : 0) |
+      (has_AVX_ ? kAvxBitfield : 0) |
+      (has_AVX2_ ? kAvx2Bitfield : 0);
+}
+
+std::string X86InstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (has_SSSE3_) {
+    result += ",ssse3";
+  } else {
+    result += ",-ssse3";
+  }
+  if (has_SSE4_1_) {
+    result += ",sse4.1";
+  } else {
+    result += ",-sse4.1";
+  }
+  if (has_SSE4_2_) {
+    result += ",sse4.2";
+  } else {
+    result += ",-sse4.2";
+  }
+  if (has_AVX_) {
+    result += ",avx";
+  } else {
+    result += ",-avx";
+  }
+  if (has_AVX2_) {
+    result += ",avx2";
+  } else {
+    result += ",-avx2";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* X86InstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, bool x86_64,
+    std::string* error_msg) const {
+  bool has_SSSE3 = has_SSSE3_;
+  bool has_SSE4_1 = has_SSE4_1_;
+  bool has_SSE4_2 = has_SSE4_2_;
+  bool has_AVX = has_AVX_;
+  bool has_AVX2 = has_AVX2_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "ssse3") {
+      has_SSSE3 = true;
+    } else if (feature == "-ssse3") {
+      has_SSSE3 = false;
+    } else if (feature == "sse4.1") {
+      has_SSE4_1 = true;
+    } else if (feature == "-sse4.1") {
+      has_SSE4_1 = false;
+    } else if (feature == "sse4.2") {
+      has_SSE4_2 = true;
+    } else if (feature == "-sse4.2") {
+      has_SSE4_2 = false;
+    } else if (feature == "avx") {
+      has_AVX = true;
+    } else if (feature == "-avx") {
+      has_AVX = false;
+    } else if (feature == "avx2") {
+      has_AVX2 = true;
+    } else if (feature == "-avx2") {
+      has_AVX2 = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86/instruction_set_features_x86.h b/runtime/arch/x86/instruction_set_features_x86.h
new file mode 100644
index 0000000..926fabb
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86.h
@@ -0,0 +1,101 @@
+/*
+ * 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_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
+#define ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the X86 architecture.
+class X86InstructionSetFeatures : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "atom" or "nehalem" and create InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg,
+                                                        bool x86_64 = false);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromBitmap(uint32_t bitmap, bool x86_64 = false);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const X86InstructionSetFeatures* FromCppDefines(bool x86_64 = false);
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromCpuInfo(bool x86_64 = false);
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromHwcap(bool x86_64 = false);
+
+  // 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 X86InstructionSetFeatures* FromAssembly(bool x86_64 = false);
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  virtual InstructionSet GetInstructionSet() const OVERRIDE {
+    return kX86;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  std::string GetFeatureString() const OVERRIDE;
+
+  virtual ~X86InstructionSetFeatures() {}
+
+ protected:
+  // Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE {
+    return AddFeaturesFromSplitString(smp, features, false, error_msg);
+  }
+
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 bool x86_64, std::string* error_msg) const;
+
+  X86InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
+                            bool has_AVX, bool has_AVX2)
+      : InstructionSetFeatures(smp), has_SSSE3_(has_SSSE3), has_SSE4_1_(has_SSE4_1),
+        has_SSE4_2_(has_SSE4_2), has_AVX_(has_AVX), has_AVX2_(has_AVX2) {
+  }
+
+ private:
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kSsse3Bitfield = 2,
+    kSse4_1Bitfield = 4,
+    kSse4_2Bitfield = 8,
+    kAvxBitfield = 16,
+    kAvx2Bitfield = 32,
+  };
+
+  const bool has_SSSE3_;   // x86 128bit SIMD - Supplemental SSE.
+  const bool has_SSE4_1_;  // x86 128bit SIMD SSE4.1.
+  const bool has_SSE4_2_;  // x86 128bit SIMD SSE4.2.
+  const bool has_AVX_;     // x86 256bit SIMD AVX.
+  const bool has_AVX2_;    // x86 256bit SIMD AVX 2.0.
+
+  DISALLOW_COPY_AND_ASSIGN(X86InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
diff --git a/runtime/arch/x86/instruction_set_features_x86_test.cc b/runtime/arch/x86/instruction_set_features_x86_test.cc
new file mode 100644
index 0000000..d231beb
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86_test.cc
@@ -0,0 +1,70 @@
+/*
+ * 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 "instruction_set_features_x86.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(X86InstructionSetFeaturesTest, X86FeaturesFromDefaultVariant) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> x86_features(
+      InstructionSetFeatures::FromVariant(kX86, "default", &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("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2", x86_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_features->AsBitmap(), 1U);
+}
+
+TEST(X86InstructionSetFeaturesTest, X86FeaturesFromAtomVariant) {
+  // 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("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2", x86_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_features->AsBitmap(), 3U);
+
+  // Build features for a 32-bit x86 default processor.
+  std::unique_ptr<const InstructionSetFeatures> x86_default_features(
+      InstructionSetFeatures::FromVariant(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("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+               x86_default_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_default_features->AsBitmap(), 1U);
+
+  // 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("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+               x86_64_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_64_features->AsBitmap(), 3U);
+
+  EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
+  EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
+  EXPECT_FALSE(x86_features->Equals(x86_default_features.get()));
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S
deleted file mode 100644
index f5fe869..0000000
--- a/runtime/arch/x86/portable_entrypoints_x86.S
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "asm_support_x86.S"
-
-    /*
-     * Portable invocation stub.
-     * On entry:
-     *   [sp] = return address
-     *   [sp + 4] = method pointer
-     *   [sp + 8] = argument array or NULL for no argument methods
-     *   [sp + 12] = size of argument array in bytes
-     *   [sp + 16] = (managed) thread pointer
-     *   [sp + 20] = JValue* result
-     *   [sp + 24] = result type char
-     */
-DEFINE_FUNCTION art_portable_invoke_stub
-    PUSH ebp                      // save ebp
-    PUSH ebx                      // save ebx
-    mov %esp, %ebp                // copy value of stack pointer into base pointer
-    CFI_DEF_CFA_REGISTER(ebp)
-    mov 20(%ebp), %ebx            // get arg array size
-    addl LITERAL(28), %ebx        // reserve space for return addr, method*, ebx, and ebp in frame
-    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
-    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
-    pushl %eax                    // push stack pointer as destination of memcpy
-    call PLT_SYMBOL(memcpy)       // (void*, const void*, size_t)
-    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
-    mov %ebp, %esp                // restore stack pointer
-    POP ebx                       // pop ebx
-    POP ebp                       // pop ebp
-    mov 20(%esp), %ecx            // get result pointer
-    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
-    je .Lreturn_double_portable
-    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
-    je .Lreturn_float_portable
-    mov %eax, (%ecx)              // store the result
-    mov %edx, 4(%ecx)             // store the other half of the result
-    ret
-.Lreturn_double_portable:
-    fstpl (%ecx)                  // store the floating point result as double
-    ret
-.Lreturn_float_portable:
-    fstps (%ecx)                  // store the floating point result as float
-    ret
-END_FUNCTION art_portable_invoke_stub
-
-DEFINE_FUNCTION art_portable_proxy_invoke_handler
-    PUSH ebp                        // Set up frame.
-    movl %esp, %ebp
-    CFI_DEF_CFA_REGISTER(%ebp)
-    subl LITERAL(8), %esp           // Align stack
-    leal 8(%ebp), %edx              // %edx = ArtMethod** called_addr
-    movl 12(%ebp), %ecx             // %ecx = receiver
-    movl 0(%edx), %eax              // %eax = ArtMethod* called
-    pushl %edx                      // Pass called_addr.
-    pushl %fs:THREAD_SELF_OFFSET    // Pass thread.
-    pushl %ecx                      // Pass receiver.
-    pushl %eax                      // Pass called.
-    call SYMBOL(artPortableProxyInvokeHandler)  // (called, receiver, Thread*, &called)
-    leave
-    CFI_RESTORE(%ebp)
-    CFI_DEF_CFA(%esp, 4)
-    movd %eax, %xmm0              // Place return value also into floating point return value.
-    movd %edx, %xmm1
-    punpckldq %xmm1, %xmm0
-    ret
-END_FUNCTION art_portable_proxy_invoke_handler
-
-DEFINE_FUNCTION art_portable_resolution_trampoline
-  PUSH ebp                        // Set up frame.
-  movl %esp, %ebp
-  CFI_DEF_CFA_REGISTER(%ebp)
-  subl LITERAL(8), %esp           // Align stack
-  leal 8(%ebp), %edx              // %edx = ArtMethod** called_addr
-  movl 12(%ebp), %ecx             // %ecx = receiver
-  movl 0(%edx), %eax              // %eax = ArtMethod* called
-  pushl %edx                      // Pass called_addr.
-  pushl %fs:THREAD_SELF_OFFSET    // Pass thread.
-  pushl %ecx                      // Pass receiver.
-  pushl %eax                      // Pass called.
-  call SYMBOL(artPortableResolutionTrampoline)  // (called, receiver, Thread*, &called)
-  leave
-  CFI_RESTORE(%ebp)
-  CFI_DEF_CFA(%esp, 4)
-  testl %eax, %eax
-  jz  .Lresolve_fail
-  jmp * %eax
-.Lresolve_fail:                   // Resolution failed, return with exception pending.
-  ret
-END_FUNCTION art_portable_resolution_trampoline
-
-DEFINE_FUNCTION_NO_HIDE art_portable_to_interpreter_bridge
-  PUSH ebp                        // Set up frame.
-  movl %esp, %ebp
-  CFI_DEF_CFA_REGISTER(%ebp)
-  subl LITERAL(12), %esp           // Align stack
-  leal 8(%ebp), %edx              // %edx = ArtMethod** called_addr
-  movl 0(%edx), %eax              // %eax = ArtMethod* called
-  pushl %edx                      // Pass called_addr.
-  pushl %fs:THREAD_SELF_OFFSET    // Pass thread.
-  pushl %eax                      // Pass called.
-  call SYMBOL(artPortableToInterpreterBridge)  // (called, Thread*, &called)
-  leave
-  CFI_RESTORE(%ebp)
-  CFI_DEF_CFA(%esp, 4)
-  ret
-END_FUNCTION art_portable_to_interpreter_bridge
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 4155b7e..4a0d7f8 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)
@@ -268,28 +297,34 @@
 DEFINE_FUNCTION art_quick_invoke_stub
     PUSH ebp                      // save ebp
     PUSH ebx                      // save ebx
+    PUSH esi                      // save esi
+    PUSH edi                      // save edi
     mov %esp, %ebp                // copy value of stack pointer into base pointer
     CFI_DEF_CFA_REGISTER(ebp)
-    mov 20(%ebp), %ebx            // get arg array size
-    addl LITERAL(28), %ebx        // reserve space for return addr, method*, ebx, and ebp in frame
-    andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
-    subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
+    mov 28(%ebp), %ebx            // get arg array size
+    // reserve space for return addr, method*, ebx, ebp, esi, and edi in frame
+    addl LITERAL(36), %ebx
+    // align frame size to 16 bytes
+    andl LITERAL(0xFFFFFFF0), %ebx
+    subl LITERAL(20), %ebx        // remove space for return address, ebx, ebp, esi and edi
     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
+    pushl 28(%ebp)                // push size of region to memcpy
+    pushl 24(%ebp)                // push arg array as source of memcpy
     pushl %eax                    // push stack pointer as destination of memcpy
     call PLT_SYMBOL(memcpy)       // (void*, const void*, size_t)
     addl LITERAL(12), %esp        // pop arguments to memcpy
     movl LITERAL(0), (%esp)       // store NULL for method*
-    mov 12(%ebp), %eax            // move method pointer into eax
+    mov 20(%ebp), %eax            // move method pointer into eax
     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_32(%eax) // call the method
     mov %ebp, %esp                // restore stack pointer
     CFI_DEF_CFA_REGISTER(esp)
+    POP edi                       // pop edi
+    POP esi                       // pop esi
     POP ebx                       // pop ebx
     POP ebp                       // pop ebp
     mov 20(%esp), %ecx            // get result pointer
@@ -311,120 +346,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 +485,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
@@ -560,13 +601,13 @@
 TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO
 TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO
 
-TWO_ARG_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
+TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
 
 DEFINE_FUNCTION art_quick_lock_object
     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 +616,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 +628,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 +657,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 +703,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 +726,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 +737,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 +757,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 +768,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 +777,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 +895,77 @@
     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
+    movd %ebx, %xmm0
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx  // save ref containing registers for GC
+    movd %xmm0, %ebx
+    // Outgoing argument set up
     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 +987,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 +1016,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 +1029,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 +1093,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 +1111,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 +1119,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)
-    pushl 40(%esp)                // Pass LR.
+    subl LITERAL(12), %esp        // Align stack.
+    CFI_ADJUST_CFA_OFFSET(12)
+    pushl FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-4+16(%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 +1148,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 +1174,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 +1185,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 +1204,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 +1247,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/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc
index 7699eaf..6e9b99c 100644
--- a/runtime/arch/x86_64/context_x86_64.cc
+++ b/runtime/arch/x86_64/context_x86_64.cc
@@ -17,9 +17,8 @@
 #include "context_x86_64.h"
 
 #include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
 #include "quick/quick_method_frame_info.h"
-#include "stack.h"
+#include "utils.h"
 
 namespace art {
 namespace x86_64 {
@@ -129,7 +128,7 @@
   }
 
   // We want to load the stack pointer one slot below so that the ret will pop eip.
-  uintptr_t rsp = gprs[kNumberOfCpuRegisters - RSP - 1] - kWordSize;
+  uintptr_t rsp = gprs[kNumberOfCpuRegisters - RSP - 1] - sizeof(intptr_t);
   gprs[kNumberOfCpuRegisters] = rsp;
   *(reinterpret_cast<uintptr_t*>(rsp)) = rip_;
 
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index c9028e1..b25d7a7 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -16,116 +16,23 @@
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/jni/jni_entrypoints.h"
-#include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/quick/quick_default_externs.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*);
-
 // Cast entrypoints.
 extern "C" uint32_t art_quick_assignable_from_code(const mirror::Class* klass,
-                                            const mirror::Class* ref_class);
-extern "C" void art_quick_check_cast(void*, void*);
-
-// DexCache entrypoints.
-extern "C" void* art_quick_initialize_static_storage(uint32_t, void*);
-extern "C" void* art_quick_initialize_type(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, void*);
-extern "C" void* art_quick_resolve_string(void*, uint32_t);
-
-// Field entrypoints.
-extern "C" int art_quick_set8_instance(uint32_t, void*, int8_t);
-extern "C" int art_quick_set8_static(uint32_t, int8_t);
-extern "C" int art_quick_set16_instance(uint32_t, void*, int16_t);
-extern "C" int art_quick_set16_static(uint32_t, int16_t);
-extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t);
-extern "C" int art_quick_set32_static(uint32_t, int32_t);
-extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t);
-extern "C" int art_quick_set64_static(uint32_t, int64_t);
-extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*);
-extern "C" int art_quick_set_obj_static(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_instance(uint32_t, void*);
-extern "C" uint8_t art_quick_get_boolean_instance(uint32_t, void*);
-extern "C" int8_t art_quick_get_byte_static(uint32_t);
-extern "C" uint8_t art_quick_get_boolean_static(uint32_t);
-extern "C" int16_t art_quick_get_short_instance(uint32_t, void*);
-extern "C" uint16_t art_quick_get_char_instance(uint32_t, void*);
-extern "C" int16_t art_quick_get_short_static(uint32_t);
-extern "C" uint16_t art_quick_get_char_static(uint32_t);
-extern "C" int32_t art_quick_get32_instance(uint32_t, void*);
-extern "C" int32_t art_quick_get32_static(uint32_t);
-extern "C" int64_t art_quick_get64_instance(uint32_t, void*);
-extern "C" int64_t art_quick_get64_static(uint32_t);
-extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
-extern "C" void* art_quick_get_obj_static(uint32_t);
-
-// Array entrypoints.
-extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
-extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
-extern "C" void art_quick_handle_fill_data(void*, void*);
-
-// Lock entrypoints.
-extern "C" void art_quick_lock_object(void*);
-extern "C" void art_quick_unlock_object(void*);
-
-// Math entrypoints.
-extern "C" int64_t art_quick_d2l(double);
-extern "C" int64_t art_quick_f2l(float);
-extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
-extern "C" int64_t art_quick_lmod(int64_t, int64_t);
-extern "C" int64_t art_quick_lmul(int64_t, int64_t);
-extern "C" uint64_t art_quick_lshl(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_lshr(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_lushr(uint64_t, uint32_t);
-
-// Intrinsic entrypoints.
-extern "C" int32_t art_quick_string_compareto(void*, void*);
-extern "C" void* art_quick_memcpy(void*, const void*, size_t);
-
-// Invoke entrypoints.
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-
-// Thread entrypoints.
-extern "C" void art_quick_test_suspend();
-
-// Throw entrypoints.
-extern "C" void art_quick_deliver_exception(void*);
-extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
-extern "C" void art_quick_throw_div_zero();
-extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
-extern "C" void art_quick_throw_null_pointer_exception();
-extern "C" void art_quick_throw_stack_overflow(void*);
-
-// Generic JNI entrypoint
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-
-extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
+                                                   const mirror::Class* ref_class);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
-                     PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
+                     QuickEntryPoints* qpoints) {
 #if defined(__APPLE__)
+  UNUSED(ipoints, jpoints, qpoints);
   UNIMPLEMENTED(FATAL);
 #else
   // Interpreter
@@ -135,10 +42,6 @@
   // JNI
   jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
 
-  // Portable
-  ppoints->pPortableResolutionTrampoline = art_portable_resolution_trampoline;
-  ppoints->pPortableToInterpreterBridge = art_portable_to_interpreter_bridge;
-
   // Alloc
   ResetQuickAllocEntryPoints(qpoints);
 
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64.h b/runtime/arch/x86_64/instruction_set_features_x86_64.h
new file mode 100644
index 0000000..3280177
--- /dev/null
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64.h
@@ -0,0 +1,88 @@
+/*
+ * 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_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
+#define ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
+
+#include "arch/x86/instruction_set_features_x86.h"
+
+namespace art {
+
+// Instruction set features relevant to the X86_64 architecture.
+class X86_64InstructionSetFeatures FINAL : public X86InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "atom" or "nehalem" and create InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                         std::string* error_msg) {
+    return X86InstructionSetFeatures::FromVariant(variant, error_msg, true)
+        ->AsX86_64InstructionSetFeatures();
+  }
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromBitmap(uint32_t bitmap) {
+    return X86InstructionSetFeatures::FromBitmap(bitmap, true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const X86_64InstructionSetFeatures* FromCppDefines() {
+    return X86InstructionSetFeatures::FromCppDefines(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromCpuInfo() {
+    return X86InstructionSetFeatures::FromCpuInfo(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromHwcap() {
+    return X86InstructionSetFeatures::FromHwcap(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // 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 X86_64InstructionSetFeatures* FromAssembly() {
+    return X86InstructionSetFeatures::FromAssembly(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kX86_64;
+  }
+
+  virtual ~X86_64InstructionSetFeatures() {}
+
+ protected:
+  // Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE {
+    return X86InstructionSetFeatures::AddFeaturesFromSplitString(smp, features, true, error_msg);
+  }
+
+ private:
+  X86_64InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
+                               bool has_AVX, bool has_AVX2)
+      : X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2) {
+  }
+
+  friend class X86InstructionSetFeatures;
+
+  DISALLOW_COPY_AND_ASSIGN(X86_64InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
new file mode 100644
index 0000000..5171080
--- /dev/null
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
@@ -0,0 +1,35 @@
+/*
+ * 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 "instruction_set_features_x86_64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(X86_64InstructionSetFeaturesTest, X86Features) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+      InstructionSetFeatures::FromVariant(kX86_64, "default", &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("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+               x86_64_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_64_features->AsBitmap(), 1U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86_64/portable_entrypoints_x86_64.S b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
deleted file mode 100644
index 7b84d17..0000000
--- a/runtime/arch/x86_64/portable_entrypoints_x86_64.S
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "asm_support_x86_64.S"
-
-    /*
-     * Portable invocation stub.
-     */
-UNIMPLEMENTED art_portable_invoke_stub
-
-UNIMPLEMENTED art_portable_proxy_invoke_handler
-
-UNIMPLEMENTED art_portable_resolution_trampoline
-
-UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index e68cfbc..48f5e85 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
@@ -450,15 +487,21 @@
     PUSH rbp                      // Save rbp.
     PUSH r8                       // Save r8/result*.
     PUSH r9                       // Save r9/shorty*.
+    PUSH rbx                      // Save native callee save rbx
+    PUSH r12                      // Save native callee save r12
+    PUSH r13                      // Save native callee save r13
+    PUSH r14                      // Save native callee save r14
+    PUSH r15                      // Save native callee save r15
     movq %rsp, %rbp               // Copy value of stack pointer into base pointer.
     CFI_DEF_CFA_REGISTER(rbp)
 
     movl %edx, %r10d
-    addl LITERAL(60), %edx        // Reserve space for return addr, StackReference<method>, rbp,
-                                  // r8 and r9 in frame.
-    andl LITERAL(0xFFFFFFF0), %edx    // Align frame size to 16 bytes.
-    subl LITERAL(32), %edx        // Remove space for return address, rbp, r8 and r9.
-    subq %rdx, %rsp               // Reserve stack space for argument array.
+    addl LITERAL(100), %edx        // Reserve space for return addr, StackReference<method>, rbp,
+                                   // r8, r9, rbx, r12, r13, r14, and r15 in frame.
+    andl LITERAL(0xFFFFFFF0), %edx // Align frame size to 16 bytes.
+    subl LITERAL(72), %edx         // Remove space for return address, rbp, r8, r9, rbx, r12,
+                                   // r13, r14, and r15
+    subq %rdx, %rsp                // Reserve stack space for argument array.
 
 #if (STACK_REFERENCE_SIZE != 4)
 #error "STACK_REFERENCE_SIZE(X86_64) size not as expected."
@@ -466,25 +509,29 @@
     movl LITERAL(0), (%rsp)       // Store NULL for method*
 
     movl %r10d, %ecx              // Place size of args in rcx.
-    movq %rdi, %rax               // RAX := method to be called
-    movq %rsi, %r11               // R11 := arg_array
-    leaq 4(%rsp), %rdi            // Rdi is pointing just above the StackReference<method> in the
+    movq %rdi, %rax               // rax := method to be called
+    movq %rsi, %r11               // r11 := arg_array
+    leaq 4(%rsp), %rdi            // rdi is pointing just above the StackReference<method> in the
                                   // stack arguments.
     // Copy arg array into stack.
     rep movsb                     // while (rcx--) { *rdi++ = *rsi++ }
-    leaq 1(%r9), %r10             // R10 := shorty + 1  ; ie skip return arg character
-    movq %rax, %rdi               // RDI := method to be called
-    movl (%r11), %esi             // RSI := this pointer
+    leaq 1(%r9), %r10             // r10 := shorty + 1  ; ie skip return arg character
+    movq %rax, %rdi               // rdi := method to be called
+    movl (%r11), %esi             // rsi := this pointer
     addq LITERAL(4), %r11         // arg_array++
     LOOP_OVER_SHORTY_LOADING_GPRS rdx, edx, .Lgpr_setup_finished
     LOOP_OVER_SHORTY_LOADING_GPRS rcx, ecx, .Lgpr_setup_finished
     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_64(%rdi) // Call the method.
     movq %rbp, %rsp               // Restore stack pointer.
-    CFI_DEF_CFA_REGISTER(rsp)
-    POP r9                        // Pop r9 - shorty*.
+    POP r15                       // Pop r15
+    POP r14                       // Pop r14
+    POP r13                       // Pop r13
+    POP r12                       // Pop r12
+    POP rbx                       // Pop rbx
+    POP r9                        // Pop r9 - shorty*
     POP r8                        // Pop r8 - result*.
     POP rbp                       // Pop rbp
     cmpb LITERAL(68), (%r9)       // Test if result type char == 'D'.
@@ -494,10 +541,10 @@
     movq %rax, (%r8)              // Store the result assuming its a long, int or Object*
     ret
 .Lreturn_double_quick:
-    movsd %xmm0, (%r8)           // Store the double floating point result.
+    movsd %xmm0, (%r8)            // Store the double floating point result.
     ret
 .Lreturn_float_quick:
-    movss %xmm0, (%r8)           // Store the floating point result.
+    movss %xmm0, (%r8)            // Store the floating point result.
     ret
 #endif  // __APPLE__
 END_FUNCTION art_quick_invoke_stub
@@ -534,53 +581,63 @@
     PUSH rbp                      // Save rbp.
     PUSH r8                       // Save r8/result*.
     PUSH r9                       // Save r9/shorty*.
+    PUSH rbx                      // Save rbx
+    PUSH r12                      // Save r12
+    PUSH r13                      // Save r13
+    PUSH r14                      // Save r14
+    PUSH r15                      // Save r15
     movq %rsp, %rbp               // Copy value of stack pointer into base pointer.
     CFI_DEF_CFA_REGISTER(rbp)
 
     movl %edx, %r10d
-    addl LITERAL(60), %edx        // Reserve space for return addr, StackReference<method>, rbp,
-                                  // r8 and r9 in frame.
-    andl LITERAL(0xFFFFFFF0), %edx    // Align frame size to 16 bytes.
-    subl LITERAL(32), %edx        // Remove space for return address, rbp, r8 and r9.
-    subq %rdx, %rsp               // Reserve stack space for argument array.
+    addl LITERAL(100), %edx        // Reserve space for return addr, StackReference<method>, rbp,
+                                   // r8, r9, r12, r13, r14, and r15 in frame.
+    andl LITERAL(0xFFFFFFF0), %edx // Align frame size to 16 bytes.
+    subl LITERAL(72), %edx         // Remove space for return address, rbp, r8, r9, rbx, r12,
+                                   // r13, r14, and r15.
+    subq %rdx, %rsp                // Reserve stack space for argument array.
 
 #if (STACK_REFERENCE_SIZE != 4)
 #error "STACK_REFERENCE_SIZE(X86_64) size not as expected."
 #endif
-    movl LITERAL(0), (%rsp)       // Store NULL for method*
+    movl LITERAL(0), (%rsp)        // Store NULL for method*
 
-    movl %r10d, %ecx              // Place size of args in rcx.
-    movq %rdi, %rax               // RAX := method to be called
-    movq %rsi, %r11               // R11 := arg_array
-    leaq 4(%rsp), %rdi            // Rdi is pointing just above the StackReference<method> in the
-                                  // stack arguments.
+    movl %r10d, %ecx               // Place size of args in rcx.
+    movq %rdi, %rax                // rax := method to be called
+    movq %rsi, %r11                // r11 := arg_array
+    leaq 4(%rsp), %rdi             // rdi is pointing just above the StackReference<method> in the
+                                   // stack arguments.
     // Copy arg array into stack.
-    rep movsb                     // while (rcx--) { *rdi++ = *rsi++ }
-    leaq 1(%r9), %r10             // R10 := shorty + 1  ; ie skip return arg character
-    movq %rax, %rdi               // RDI := method to be called
+    rep movsb                      // while (rcx--) { *rdi++ = *rsi++ }
+    leaq 1(%r9), %r10              // r10 := shorty + 1  ; ie skip return arg character
+    movq %rax, %rdi                // rdi := method to be called
     LOOP_OVER_SHORTY_LOADING_GPRS rsi, esi, .Lgpr_setup_finished2
     LOOP_OVER_SHORTY_LOADING_GPRS rdx, edx, .Lgpr_setup_finished2
     LOOP_OVER_SHORTY_LOADING_GPRS rcx, ecx, .Lgpr_setup_finished2
     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.
-    movq %rbp, %rsp               // Restore stack pointer.
-    CFI_DEF_CFA_REGISTER(rsp)
-    POP r9                        // Pop r9 - shorty*.
-    POP r8                        // Pop r8 - result*.
-    POP rbp                       // Pop rbp
-    cmpb LITERAL(68), (%r9)       // Test if result type char == 'D'.
+    call *MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method.
+    movq %rbp, %rsp                // Restore stack pointer.
+    POP r15                        // Pop r15
+    POP r14                        // Pop r14
+    POP r13                        // Pop r13
+    POP r12                        // Pop r12
+    POP rbx                        // Pop rbx
+    POP r9                         // Pop r9 - shorty*.
+    POP r8                         // Pop r8 - result*.
+    POP rbp                        // Pop rbp
+    cmpb LITERAL(68), (%r9)        // Test if result type char == 'D'.
     je .Lreturn_double_quick2
-    cmpb LITERAL(70), (%r9)       // Test if result type char == 'F'.
+    cmpb LITERAL(70), (%r9)        // Test if result type char == 'F'.
     je .Lreturn_float_quick2
-    movq %rax, (%r8)              // Store the result assuming its a long, int or Object*
+    movq %rax, (%r8)               // Store the result assuming its a long, int or Object*
     ret
 .Lreturn_double_quick2:
-    movsd %xmm0, (%r8)           // Store the double floating point result.
+    movsd %xmm0, (%r8)             // Store the double floating point result.
     ret
 .Lreturn_float_quick2:
-    movss %xmm0, (%r8)           // Store the floating point result.
+    movss %xmm0, (%r8)             // Store the floating point result.
     ret
 #endif  // __APPLE__
 END_FUNCTION art_quick_invoke_static_stub
@@ -639,88 +696,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
 
@@ -858,13 +908,13 @@
 TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO
 TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO
 
-TWO_ARG_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
+TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
 
 DEFINE_FUNCTION art_quick_lock_object
     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 +922,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 +931,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 +953,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 +984,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 +1017,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 +1034,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 +1063,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 +1080,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 +1100,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 +1125,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 +1151,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 +1184,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 +1282,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 +1443,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 +1461,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.
+    movq FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-8(%rsp), %rcx   // 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 +1476,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 +1485,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 +1525,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 +1539,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 +1593,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..a35e05b 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_QUICK_CODE_OFFSET_32        (36 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_ART_METHOD_QUICK_CODE_OFFSET_32,
+            art::mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value())
+
+#define MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64        (48 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64,
+            art::mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(8).Int32Value())
+
+#if defined(__cplusplus)
+}  // End of CheckAsmSupportOffsets.
 #endif
 
 #endif  // ART_RUNTIME_ASM_SUPPORT_H_
diff --git a/runtime/atomic.h b/runtime/atomic.h
index e57c0c0..87de506 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -46,6 +46,9 @@
 class QuasiAtomic {
 #if defined(__mips__) && !defined(__LP64__)
   static constexpr bool kNeedSwapMutexes = true;
+#elif defined(__mips__) && defined(__LP64__)
+  // TODO - mips64 still need this for Cas64 ???
+  static constexpr bool kNeedSwapMutexes = true;
 #else
   static constexpr bool kNeedSwapMutexes = false;
 #endif
@@ -293,17 +296,17 @@
 
 typedef Atomic<int32_t> AtomicInteger;
 
-COMPILE_ASSERT(sizeof(AtomicInteger) == sizeof(int32_t), weird_atomic_int_size);
-COMPILE_ASSERT(alignof(AtomicInteger) == alignof(int32_t),
-               atomic_int_alignment_differs_from_that_of_underlying_type);
-COMPILE_ASSERT(sizeof(Atomic<int64_t>) == sizeof(int64_t), weird_atomic_int64_size);
+static_assert(sizeof(AtomicInteger) == sizeof(int32_t), "Weird AtomicInteger size");
+static_assert(alignof(AtomicInteger) == alignof(int32_t),
+              "AtomicInteger alignment differs from that of underlyingtype");
+static_assert(sizeof(Atomic<int64_t>) == sizeof(int64_t), "Weird Atomic<int64> size");
 
 // Assert the alignment of 64-bit integers is 64-bit. This isn't true on certain 32-bit
 // architectures (e.g. x86-32) but we know that 64-bit integers here are arranged to be 8-byte
 // aligned.
 #if defined(__LP64__)
-  COMPILE_ASSERT(alignof(Atomic<int64_t>) == alignof(int64_t),
-                 atomic_int64_alignment_differs_from_that_of_underlying_type);
+  static_assert(alignof(Atomic<int64_t>) == alignof(int64_t),
+                "Atomic<int64> alignment differs from that of underlying type");
 #endif
 
 }  // namespace art
diff --git a/runtime/barrier.cc b/runtime/barrier.cc
index b8edad3..66ee870 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -23,7 +23,7 @@
 
 Barrier::Barrier(int count)
     : count_(count),
-      lock_("GC barrier lock"),
+      lock_("GC barrier lock", kThreadSuspendCountLock),
       condition_("GC barrier condition", lock_) {
 }
 
@@ -52,7 +52,7 @@
   // Pass function is called by the last thread, the count will
   // be decremented to zero and a Broadcast will be made on the
   // condition variable, thus waking this up.
-  if (count_ != 0) {
+  while (count_ != 0) {
     condition_.Wait(self);
   }
 }
@@ -62,7 +62,18 @@
   SetCountLocked(self, count_ + delta);
   bool timed_out = false;
   if (count_ != 0) {
-    timed_out = condition_.TimedWait(self, timeout_ms, 0);
+    uint32_t timeout_ns = 0;
+    uint64_t abs_timeout = NanoTime() + MsToNs(timeout_ms);
+    for (;;) {
+      timed_out = condition_.TimedWait(self, timeout_ms, timeout_ns);
+      if (timed_out || count_ == 0) return timed_out;
+      // Compute time remaining on timeout.
+      uint64_t now = NanoTime();
+      int64_t time_left = abs_timeout - now;
+      if (time_left <= 0) return true;
+      timeout_ns = time_left % (1000*1000);
+      timeout_ms = time_left / (1000*1000);
+    }
   }
   return timed_out;
 }
diff --git a/runtime/barrier.h b/runtime/barrier.h
index 167e1d6..0e7f61e 100644
--- a/runtime/barrier.h
+++ b/runtime/barrier.h
@@ -14,6 +14,16 @@
  * limitations under the License.
  */
 
+// CAUTION: THIS IS NOT A FULLY GENERAL BARRIER API.
+
+// It may either be used as a "latch" or single-use barrier, or it may be reused under
+// very limited conditions, e.g. if only Pass(), but not Wait() is called.  Unlike a standard
+// latch API, it is possible to initialize the latch to a count of zero, repeatedly call
+// Pass() or Wait(), and only then set the count using the Increment() method.  Threads at
+// a Wait() are only awoken if the count reaches zero AFTER the decrement is applied.
+// This works because, also unlike most latch APIs, there is no way to Wait() without
+// decrementing the count, and thus nobody can spuriosly wake up on the initial zero.
+
 #ifndef ART_RUNTIME_BARRIER_H_
 #define ART_RUNTIME_BARRIER_H_
 
@@ -22,20 +32,23 @@
 
 namespace art {
 
+// TODO: Maybe give this a better name.
 class Barrier {
  public:
   explicit Barrier(int count);
   virtual ~Barrier();
 
-  // Pass through the barrier, decrements the count but does not block.
+  // Pass through the barrier, decrement the count but do not block.
   void Pass(Thread* self);
 
   // Wait on the barrier, decrement the count.
   void Wait(Thread* self);
 
-  // Set the count to a new value, if the value is 0 then everyone waiting on the condition
-  // variable is resumed.
-  void Init(Thread* self, int count);
+  // The following three calls are only safe if we somehow know that no other thread both
+  // - has been woken up, and
+  // - has not left the Wait() or Increment() call.
+  // If these calls are made in that situation, the offending thread is likely to go back
+  // to sleep, resulting in a deadlock.
 
   // Increment the count by delta, wait on condition if count is non zero.
   void Increment(Thread* self, int delta) LOCKS_EXCLUDED(lock_);
@@ -44,13 +57,17 @@
   // true if time out occurred.
   bool Increment(Thread* self, int delta, uint32_t timeout_ms) LOCKS_EXCLUDED(lock_);
 
+  // Set the count to a new value.  This should only be used if there is no possibility that
+  // another thread is still in Wait().  See above.
+  void Init(Thread* self, int count);
+
  private:
   void SetCountLocked(Thread* self, int count) EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Counter, when this reaches 0 all people blocked on the barrier are signalled.
   int count_ GUARDED_BY(lock_);
 
-  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  Mutex lock_ ACQUIRED_AFTER(Locks::abort_lock_);
   ConditionVariable condition_ GUARDED_BY(lock_);
 };
 
diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc
index de348dc..f68a5d4 100644
--- a/runtime/barrier_test.cc
+++ b/runtime/barrier_test.cc
@@ -27,22 +27,17 @@
 namespace art {
 class CheckWaitTask : public Task {
  public:
-  CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2,
-                   AtomicInteger* count3)
+  CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2)
       : barrier_(barrier),
         count1_(count1),
-        count2_(count2),
-        count3_(count3) {}
+        count2_(count2) {}
 
   void Run(Thread* self) {
-    LOG(INFO) << "Before barrier 1 " << *self;
+    LOG(INFO) << "Before barrier" << *self;
     ++*count1_;
     barrier_->Wait(self);
     ++*count2_;
-    LOG(INFO) << "Before barrier 2 " << *self;
-    barrier_->Wait(self);
-    ++*count3_;
-    LOG(INFO) << "After barrier 2 " << *self;
+    LOG(INFO) << "After barrier" << *self;
   }
 
   virtual void Finalize() {
@@ -53,7 +48,6 @@
   Barrier* const barrier_;
   AtomicInteger* const count1_;
   AtomicInteger* const count2_;
-  AtomicInteger* const count3_;
 };
 
 class BarrierTest : public CommonRuntimeTest {
@@ -67,31 +61,27 @@
 TEST_F(BarrierTest, CheckWait) {
   Thread* self = Thread::Current();
   ThreadPool thread_pool("Barrier test thread pool", num_threads);
-  Barrier barrier(0);
+  Barrier barrier(num_threads + 1);  // One extra Wait() in main thread.
+  Barrier timeout_barrier(0);  // Only used for sleeping on timeout.
   AtomicInteger count1(0);
   AtomicInteger count2(0);
-  AtomicInteger count3(0);
   for (int32_t i = 0; i < num_threads; ++i) {
-    thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2, &count3));
+    thread_pool.AddTask(self, new CheckWaitTask(&barrier, &count1, &count2));
   }
   thread_pool.StartWorkers(self);
-  barrier.Increment(self, num_threads);
-  // At this point each thread should have passed through the barrier. The first count should be
-  // equal to num_threads.
-  EXPECT_EQ(num_threads, count1.LoadRelaxed());
-  // Count 3 should still be zero since no thread should have gone past the second barrier.
-  EXPECT_EQ(0, count3.LoadRelaxed());
-  // Now lets tell the threads to pass again.
-  barrier.Increment(self, num_threads);
-  // Count 2 should be equal to num_threads since each thread must have passed the second barrier
-  // at this point.
-  EXPECT_EQ(num_threads, count2.LoadRelaxed());
+  while (count1.LoadRelaxed() != num_threads) {
+    timeout_barrier.Increment(self, 1, 100);  // sleep 100 msecs
+  }
+  // Count 2 should still be zero since no thread should have gone past the barrier.
+  EXPECT_EQ(0, count2.LoadRelaxed());
+  // Perform one additional Wait(), allowing pool threads to proceed.
+  barrier.Wait(self);
   // Wait for all the threads to finish.
   thread_pool.Wait(self, true, false);
-  // All three counts should be equal to num_threads now.
-  EXPECT_EQ(count1.LoadRelaxed(), count2.LoadRelaxed());
-  EXPECT_EQ(count2.LoadRelaxed(), count3.LoadRelaxed());
-  EXPECT_EQ(num_threads, count3.LoadRelaxed());
+  // Both counts should be equal to num_threads now.
+  EXPECT_EQ(count1.LoadRelaxed(), num_threads);
+  EXPECT_EQ(count2.LoadRelaxed(), num_threads);
+  timeout_barrier.Init(self, 0);  // Reset to zero for destruction.
 }
 
 class CheckPassTask : public Task {
diff --git a/runtime/base/allocator.cc b/runtime/base/allocator.cc
index 64cdbbf..4f2fc07 100644
--- a/runtime/base/allocator.cc
+++ b/runtime/base/allocator.cc
@@ -25,20 +25,16 @@
 
 namespace art {
 
-Atomic<uint64_t> TrackedAllocators::bytes_used_[kAllocatorTagCount];
-Atomic<uint64_t> TrackedAllocators::max_bytes_used_[kAllocatorTagCount];
-Atomic<uint64_t> TrackedAllocators::total_bytes_used_[kAllocatorTagCount];
-
 class MallocAllocator FINAL : public Allocator {
  public:
   explicit MallocAllocator() {}
   ~MallocAllocator() {}
 
-  virtual void* Alloc(size_t size) {
+  void* Alloc(size_t size) {
     return calloc(sizeof(uint8_t), size);
   }
 
-  virtual void Free(void* p) {
+  void Free(void* p) {
     free(p);
   }
 
@@ -53,13 +49,15 @@
   explicit NoopAllocator() {}
   ~NoopAllocator() {}
 
-  virtual void* Alloc(size_t size) {
+  void* Alloc(size_t size) {
+    UNUSED(size);
     LOG(FATAL) << "NoopAllocator::Alloc should not be called";
-    return NULL;
+    UNREACHABLE();
   }
 
-  virtual void Free(void* p) {
+  void Free(void* p) {
     // Noop.
+    UNUSED(p);
   }
 
  private:
@@ -76,13 +74,20 @@
   return &g_noop_allocator;
 }
 
-void TrackedAllocators::Dump(std::ostream& os) {
+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];
+
+void Dump(std::ostream& os) {
   if (kEnableTrackingAllocator) {
     os << "Dumping native memory usage\n";
     for (size_t i = 0; i < kAllocatorTagCount; ++i) {
-      uint64_t bytes_used = bytes_used_[i].LoadRelaxed();
-      uint64_t max_bytes_used = max_bytes_used_[i].LoadRelaxed();
-      uint64_t total_bytes_used = total_bytes_used_[i].LoadRelaxed();
+      uint64_t bytes_used = g_bytes_used[i].LoadRelaxed();
+      uint64_t max_bytes_used = g_max_bytes_used[i];
+      uint64_t total_bytes_used = g_total_bytes_used[i].LoadRelaxed();
       if (total_bytes_used != 0) {
         os << static_cast<AllocatorTag>(i) << " active=" << bytes_used << " max="
            << max_bytes_used << " total=" << total_bytes_used << "\n";
@@ -91,4 +96,6 @@
   }
 }
 
+}  // namespace TrackedAllocators
+
 }  // namespace art
diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h
index 2c3e966..8720f0e 100644
--- a/runtime/base/allocator.h
+++ b/runtime/base/allocator.h
@@ -22,7 +22,7 @@
 #include "atomic.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "utils.h"
+#include "base/type_static_if.h"
 
 namespace art {
 
@@ -62,7 +62,7 @@
   kAllocatorTagRememberedSet,
   kAllocatorTagModUnionCardSet,
   kAllocatorTagModUnionReferenceArray,
-  kAllocatorTagJNILibrarires,
+  kAllocatorTagJNILibraries,
   kAllocatorTagCompileTimeClassPath,
   kAllocatorTagOatFile,
   kAllocatorTagDexFileVerifier,
@@ -71,28 +71,37 @@
 };
 std::ostream& operator<<(std::ostream& os, const AllocatorTag& tag);
 
-class TrackedAllocators {
- public:
-  static bool Add(uint32_t tag, AtomicInteger* bytes_used);
-  static void Dump(std::ostream& os);
-  static void RegisterAllocation(AllocatorTag tag, uint64_t bytes) {
-    total_bytes_used_[tag].FetchAndAddSequentiallyConsistent(bytes);
-    uint64_t new_bytes = bytes_used_[tag].FetchAndAddSequentiallyConsistent(bytes) + bytes;
-    max_bytes_used_[tag].StoreRelaxed(std::max(max_bytes_used_[tag].LoadRelaxed(), new_bytes));
-  }
-  static void RegisterFree(AllocatorTag tag, uint64_t bytes) {
-    bytes_used_[tag].FetchAndSubSequentiallyConsistent(bytes);
-  }
+namespace TrackedAllocators {
 
- private:
-  static Atomic<uint64_t> bytes_used_[kAllocatorTagCount];
-  static Atomic<uint64_t> max_bytes_used_[kAllocatorTagCount];
-  static Atomic<uint64_t> total_bytes_used_[kAllocatorTagCount];
-};
+// Running count of number of bytes used for this kind of allocation. Increased by allocations,
+// decreased by deallocations.
+extern Atomic<size_t> g_bytes_used[kAllocatorTagCount];
 
-// Tracking allocator, tracks how much memory is used.
+// Largest value of bytes used seen.
+extern volatile size_t g_max_bytes_used[kAllocatorTagCount];
+
+// Total number of bytes allocated of this kind.
+extern Atomic<uint64_t> g_total_bytes_used[kAllocatorTagCount];
+
+void Dump(std::ostream& os);
+
+inline void RegisterAllocation(AllocatorTag tag, size_t bytes) {
+  g_total_bytes_used[tag].FetchAndAddSequentiallyConsistent(bytes);
+  size_t new_bytes = g_bytes_used[tag].FetchAndAddSequentiallyConsistent(bytes) + bytes;
+  if (g_max_bytes_used[tag] < new_bytes) {
+    g_max_bytes_used[tag] = new_bytes;
+  }
+}
+
+inline void RegisterFree(AllocatorTag tag, size_t bytes) {
+  g_bytes_used[tag].FetchAndSubSequentiallyConsistent(bytes);
+}
+
+}  // namespace TrackedAllocators
+
+// Tracking allocator for use with STL types, tracks how much memory is used.
 template<class T, AllocatorTag kTag>
-class TrackingAllocatorImpl {
+class TrackingAllocatorImpl : public std::allocator<T> {
  public:
   typedef typename std::allocator<T>::value_type value_type;
   typedef typename std::allocator<T>::size_type size_type;
@@ -105,11 +114,12 @@
   // Used internally by STL data structures.
   template <class U>
   TrackingAllocatorImpl(const TrackingAllocatorImpl<U, kTag>& alloc) throw() {
+    UNUSED(alloc);
   }
 
   // Used internally by STL data structures.
   TrackingAllocatorImpl() throw() {
-    COMPILE_ASSERT(kTag < kAllocatorTagCount, must_be_less_than_count);
+    static_assert(kTag < kAllocatorTagCount, "kTag must be less than kAllocatorTagCount");
   }
 
   // Enables an allocator for objects of one type to allocate storage for objects of another type.
@@ -120,6 +130,7 @@
   };
 
   pointer allocate(size_type n, const_pointer hint = 0) {
+    UNUSED(hint);
     const size_t size = n * sizeof(T);
     TrackedAllocators::RegisterAllocation(GetTag(), size);
     return reinterpret_cast<pointer>(malloc(size));
@@ -132,7 +143,7 @@
     free(p);
   }
 
-  static AllocatorTag GetTag() {
+  static constexpr AllocatorTag GetTag() {
     return kTag;
   }
 };
diff --git a/runtime/base/bit_field.h b/runtime/base/bit_field.h
index e041bd0..fd65d50 100644
--- a/runtime/base/bit_field.h
+++ b/runtime/base/bit_field.h
@@ -22,7 +22,7 @@
 
 namespace art {
 
-static const uword kUwordOne = 1U;
+static constexpr uintptr_t kUintPtrTOne = 1U;
 
 // BitField is a template for encoding and decoding a bit field inside
 // an unsigned machine word.
@@ -31,18 +31,18 @@
  public:
   // Tells whether the provided value fits into the bit field.
   static bool IsValid(T value) {
-    return (static_cast<uword>(value) & ~((kUwordOne << size) - 1)) == 0;
+    return (static_cast<uintptr_t>(value) & ~((kUintPtrTOne << size) - 1)) == 0;
   }
 
   // Returns a uword mask of the bit field.
-  static uword Mask() {
-    return (kUwordOne << size) - 1;
+  static uintptr_t Mask() {
+    return (kUintPtrTOne << size) - 1;
   }
 
   // Returns a uword mask of the bit field which can be applied directly to
   // the raw unshifted bits.
-  static uword MaskInPlace() {
-    return ((kUwordOne << size) - 1) << position;
+  static uintptr_t MaskInPlace() {
+    return ((kUintPtrTOne << size) - 1) << position;
   }
 
   // Returns the shift count needed to right-shift the bit field to
@@ -57,22 +57,22 @@
   }
 
   // Returns a uword with the bit field value encoded.
-  static uword Encode(T value) {
+  static uintptr_t Encode(T value) {
     DCHECK(IsValid(value));
-    return static_cast<uword>(value) << position;
+    return static_cast<uintptr_t>(value) << position;
   }
 
   // Extracts the bit field from the value.
-  static T Decode(uword value) {
-    return static_cast<T>((value >> position) & ((kUwordOne << size) - 1));
+  static T Decode(uintptr_t value) {
+    return static_cast<T>((value >> position) & ((kUintPtrTOne << size) - 1));
   }
 
   // Returns a uword with the bit field value encoded based on the
   // original value. Only the bits corresponding to this bit field
   // will be changed.
-  static uword Update(T value, uword original) {
+  static uintptr_t Update(T value, uintptr_t original) {
     DCHECK(IsValid(value));
-    return (static_cast<uword>(value) << position) |
+    return (static_cast<uintptr_t>(value) << position) |
         (~MaskInPlace() & original);
   }
 };
diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc
index 3d2f0de..4390180 100644
--- a/runtime/base/bit_vector.cc
+++ b/runtime/base/bit_vector.cc
@@ -16,6 +16,9 @@
 
 #include "bit_vector.h"
 
+#include <limits>
+#include <sstream>
+
 #include "allocator.h"
 #include "bit_vector-inl.h"
 
@@ -38,8 +41,8 @@
     storage_size_(storage_size),
     allocator_(allocator),
     expandable_(expandable) {
-  COMPILE_ASSERT(sizeof(*storage_) == kWordBytes, check_word_bytes);
-  COMPILE_ASSERT(sizeof(*storage_) * 8u == kWordBits, check_word_bits);
+  static_assert(sizeof(*storage_) == kWordBytes, "word bytes");
+  static_assert(sizeof(*storage_) * 8u == kWordBits, "word bits");
   if (storage_ == nullptr) {
     storage_size_ = BitsToWords(start_bits);
     storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * kWordBytes));
@@ -145,10 +148,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);
@@ -219,13 +219,13 @@
   uint32_t idx;
   // We can set every storage element with -1.
   for (idx = 0; idx < WordIndex(num_bits); idx++) {
-    storage_[idx] = -1;
+    storage_[idx] = std::numeric_limits<uint32_t>::max();
   }
 
   // Handle the potentially last few bits.
   uint32_t rem_num_bits = num_bits & 0x1f;
   if (rem_num_bits != 0) {
-    storage_[idx] = (1 << rem_num_bits) - 1;
+    storage_[idx] = (1U << rem_num_bits) - 1;
     ++idx;
   }
 
@@ -321,7 +321,12 @@
     memcpy(new_storage, storage_, storage_size_ * kWordBytes);
     // Zero out the new storage words.
     memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes);
-    // TOTO: collect stats on space wasted because of resize.
+    // TODO: collect stats on space wasted because of resize.
+
+    // Free old storage.
+    allocator_->Free(storage_);
+
+    // Set fields.
     storage_ = new_storage;
     storage_size_ = new_size;
   }
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..c7e39a2 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);
 }
 
@@ -82,7 +77,7 @@
 inline Dest bit_cast(const Source& source) {
   // Compile time assertion: sizeof(Dest) == sizeof(Source)
   // A compile error here means your Dest and Source have different sizes.
-  COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), verify_sizes_are_equal);
+  static_assert(sizeof(Dest) == sizeof(Source), "sizes should be equal");
   Dest dest;
   memcpy(&dest, &source, sizeof(dest));
   return dest;
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/hash_map.h b/runtime/base/hash_map.h
new file mode 100644
index 0000000..c0f903f
--- /dev/null
+++ b/runtime/base/hash_map.h
@@ -0,0 +1,60 @@
+/*
+ * 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_RUNTIME_BASE_HASH_MAP_H_
+#define ART_RUNTIME_BASE_HASH_MAP_H_
+
+#include <utility>
+
+#include "hash_set.h"
+
+namespace art {
+
+template <typename Fn>
+class HashMapWrapper {
+ public:
+  // Hash function.
+  template <class Key, class Value>
+  size_t operator()(const std::pair<Key, Value>& pair) const {
+    return fn_(pair.first);
+  }
+  template <class Key>
+  size_t operator()(const Key& key) const {
+    return fn_(key);
+  }
+  template <class Key, class Value>
+  bool operator()(const std::pair<Key, Value>& a, const std::pair<Key, Value>& b) const {
+    return fn_(a.first, b.first);
+  }
+  template <class Key, class Value, class Element>
+  bool operator()(const std::pair<Key, Value>& a, const Element& element) const {
+    return fn_(a.first, element);
+  }
+
+ private:
+  Fn fn_;
+};
+
+template <class Key, class Value, class EmptyFn = DefaultEmptyFn<Key>,
+    class HashFn = std::hash<Key>, class Pred = std::equal_to<Key>,
+    class Alloc = std::allocator<std::pair<Key, Value>>>
+class HashMap : public HashSet<std::pair<Key, Value>, EmptyFn, HashMapWrapper<HashFn>,
+                               HashMapWrapper<Pred>, Alloc> {
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_HASH_MAP_H_
diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h
new file mode 100644
index 0000000..992e5b1
--- /dev/null
+++ b/runtime/base/hash_set.h
@@ -0,0 +1,407 @@
+/*
+ * 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_RUNTIME_BASE_HASH_SET_H_
+#define ART_RUNTIME_BASE_HASH_SET_H_
+
+#include <functional>
+#include <memory>
+#include <stdint.h>
+#include <utility>
+
+#include "logging.h"
+
+namespace art {
+
+// Returns true if an item is empty.
+template <class T>
+class DefaultEmptyFn {
+ public:
+  void MakeEmpty(T& item) const {
+    item = T();
+  }
+  bool IsEmpty(const T& item) const {
+    return item == T();
+  }
+};
+
+template <class T>
+class DefaultEmptyFn<T*> {
+ public:
+  void MakeEmpty(T*& item) const {
+    item = nullptr;
+  }
+  bool IsEmpty(const T*& item) const {
+    return item == nullptr;
+  }
+};
+
+// Low memory version of a hash set, uses less memory than std::unordered_set since elements aren't
+// boxed. Uses linear probing.
+// EmptyFn needs to implement two functions MakeEmpty(T& item) and IsEmpty(const T& item)
+template <class T, class EmptyFn = DefaultEmptyFn<T>, class HashFn = std::hash<T>,
+    class Pred = std::equal_to<T>, class Alloc = std::allocator<T>>
+class HashSet {
+ public:
+  static constexpr double kDefaultMinLoadFactor = 0.5;
+  static constexpr double kDefaultMaxLoadFactor = 0.9;
+  static constexpr size_t kMinBuckets = 1000;
+
+  class Iterator {
+   public:
+    Iterator(const Iterator&) = default;
+    Iterator(HashSet* hash_set, size_t index) : hash_set_(hash_set), index_(index) {
+    }
+    Iterator& operator=(const Iterator&) = default;
+    bool operator==(const Iterator& other) const {
+      return hash_set_ == other.hash_set_ && index_ == other.index_;
+    }
+    bool operator!=(const Iterator& other) const {
+      return !(*this == other);
+    }
+    Iterator operator++() {  // Value after modification.
+      index_ = NextNonEmptySlot(index_);
+      return *this;
+    }
+    Iterator operator++(int) {
+      Iterator temp = *this;
+      index_ = NextNonEmptySlot(index_);
+      return temp;
+    }
+    T& operator*() {
+      DCHECK(!hash_set_->IsFreeSlot(GetIndex()));
+      return hash_set_->ElementForIndex(index_);
+    }
+    const T& operator*() const {
+      DCHECK(!hash_set_->IsFreeSlot(GetIndex()));
+      return hash_set_->ElementForIndex(index_);
+    }
+    T* operator->() {
+      return &**this;
+    }
+    const T* operator->() const {
+      return &**this;
+    }
+    // TODO: Operator -- --(int)
+
+   private:
+    HashSet* hash_set_;
+    size_t index_;
+
+    size_t GetIndex() const {
+      return index_;
+    }
+    size_t NextNonEmptySlot(size_t index) const {
+      const size_t num_buckets = hash_set_->NumBuckets();
+      DCHECK_LT(index, num_buckets);
+      do {
+        ++index;
+      } while (index < num_buckets && hash_set_->IsFreeSlot(index));
+      return index;
+    }
+
+    friend class HashSet;
+  };
+
+  void Clear() {
+    DeallocateStorage();
+    AllocateStorage(1);
+    num_elements_ = 0;
+    elements_until_expand_ = 0;
+  }
+  HashSet() : num_elements_(0), num_buckets_(0), data_(nullptr),
+      min_load_factor_(kDefaultMinLoadFactor), max_load_factor_(kDefaultMaxLoadFactor) {
+    Clear();
+  }
+  HashSet(const HashSet& other) : num_elements_(0), num_buckets_(0), data_(nullptr) {
+    *this = other;
+  }
+  HashSet(HashSet&& other) : num_elements_(0), num_buckets_(0), data_(nullptr) {
+    *this = std::move(other);
+  }
+  ~HashSet() {
+    DeallocateStorage();
+  }
+  HashSet& operator=(HashSet&& other) {
+    std::swap(data_, other.data_);
+    std::swap(num_buckets_, other.num_buckets_);
+    std::swap(num_elements_, other.num_elements_);
+    std::swap(elements_until_expand_, other.elements_until_expand_);
+    std::swap(min_load_factor_, other.min_load_factor_);
+    std::swap(max_load_factor_, other.max_load_factor_);
+    return *this;
+  }
+  HashSet& operator=(const HashSet& other) {
+    DeallocateStorage();
+    AllocateStorage(other.NumBuckets());
+    for (size_t i = 0; i < num_buckets_; ++i) {
+      ElementForIndex(i) = other.data_[i];
+    }
+    num_elements_ = other.num_elements_;
+    elements_until_expand_ = other.elements_until_expand_;
+    min_load_factor_ = other.min_load_factor_;
+    max_load_factor_ = other.max_load_factor_;
+    return *this;
+  }
+  // Lower case for c++11 for each.
+  Iterator begin() {
+    Iterator ret(this, 0);
+    if (num_buckets_ != 0 && IsFreeSlot(ret.GetIndex())) {
+      ++ret;  // Skip all the empty slots.
+    }
+    return ret;
+  }
+  // Lower case for c++11 for each.
+  Iterator end() {
+    return Iterator(this, NumBuckets());
+  }
+  bool Empty() {
+    return begin() == end();
+  }
+  // Erase algorithm:
+  // Make an empty slot where the iterator is pointing.
+  // Scan fowards until we hit another empty slot.
+  // If an element inbetween doesn't rehash to the range from the current empty slot to the
+  // iterator. It must be before the empty slot, in that case we can move it to the empty slot
+  // and set the empty slot to be the location we just moved from.
+  // Relies on maintaining the invariant that there's no empty slots from the 'ideal' index of an
+  // element to its actual location/index.
+  Iterator Erase(Iterator it) {
+    // empty_index is the index that will become empty.
+    size_t empty_index = it.GetIndex();
+    DCHECK(!IsFreeSlot(empty_index));
+    size_t next_index = empty_index;
+    bool filled = false;  // True if we filled the empty index.
+    while (true) {
+      next_index = NextIndex(next_index);
+      T& next_element = ElementForIndex(next_index);
+      // If the next element is empty, we are done. Make sure to clear the current empty index.
+      if (emptyfn_.IsEmpty(next_element)) {
+        emptyfn_.MakeEmpty(ElementForIndex(empty_index));
+        break;
+      }
+      // Otherwise try to see if the next element can fill the current empty index.
+      const size_t next_hash = hashfn_(next_element);
+      // Calculate the ideal index, if it is within empty_index + 1 to next_index then there is
+      // nothing we can do.
+      size_t next_ideal_index = IndexForHash(next_hash);
+      // Loop around if needed for our check.
+      size_t unwrapped_next_index = next_index;
+      if (unwrapped_next_index < empty_index) {
+        unwrapped_next_index += NumBuckets();
+      }
+      // Loop around if needed for our check.
+      size_t unwrapped_next_ideal_index = next_ideal_index;
+      if (unwrapped_next_ideal_index < empty_index) {
+        unwrapped_next_ideal_index += NumBuckets();
+      }
+      if (unwrapped_next_ideal_index <= empty_index ||
+          unwrapped_next_ideal_index > unwrapped_next_index) {
+        // If the target index isn't within our current range it must have been probed from before
+        // the empty index.
+        ElementForIndex(empty_index) = std::move(next_element);
+        filled = true;  // TODO: Optimize
+        empty_index = next_index;
+      }
+    }
+    --num_elements_;
+    // If we didn't fill the slot then we need go to the next non free slot.
+    if (!filled) {
+      ++it;
+    }
+    return it;
+  }
+  // Find an element, returns end() if not found.
+  // Allows custom K types, example of when this is useful.
+  // Set of Class* sorted by name, want to find a class with a name but can't allocate a dummy
+  // object in the heap for performance solution.
+  template <typename K>
+  Iterator Find(const K& element) {
+    return FindWithHash(element, hashfn_(element));
+  }
+  template <typename K>
+  Iterator FindWithHash(const K& element, size_t hash) {
+    DCHECK_EQ(hashfn_(element), hash);
+    size_t index = IndexForHash(hash);
+    while (true) {
+      T& slot = ElementForIndex(index);
+      if (emptyfn_.IsEmpty(slot)) {
+        return end();
+      }
+      if (pred_(slot, element)) {
+        return Iterator(this, index);
+      }
+      index = NextIndex(index);
+    }
+  }
+  // Insert an element, allows duplicates.
+  void Insert(const T& element) {
+    InsertWithHash(element, hashfn_(element));
+  }
+  void InsertWithHash(const T& element, size_t hash) {
+    DCHECK_EQ(hash, hashfn_(element));
+    if (num_elements_ >= elements_until_expand_) {
+      Expand();
+      DCHECK_LT(num_elements_, elements_until_expand_);
+    }
+    const size_t index = FirstAvailableSlot(IndexForHash(hash));
+    data_[index] = element;
+    ++num_elements_;
+  }
+  size_t Size() const {
+    return num_elements_;
+  }
+  void ShrinkToMaximumLoad() {
+    Resize(Size() / max_load_factor_);
+  }
+  // To distance that inserted elements were probed. Used for measuring how good hash functions
+  // are.
+  size_t TotalProbeDistance() const {
+    size_t total = 0;
+    for (size_t i = 0; i < NumBuckets(); ++i) {
+      const T& element = ElementForIndex(i);
+      if (!emptyfn_.IsEmpty(element)) {
+        size_t ideal_location = IndexForHash(hashfn_(element));
+        if (ideal_location > i) {
+          total += i + NumBuckets() - ideal_location;
+        } else {
+          total += i - ideal_location;
+        }
+      }
+    }
+    return total;
+  }
+  // Calculate the current load factor and return it.
+  double CalculateLoadFactor() const {
+    return static_cast<double>(Size()) / static_cast<double>(NumBuckets());
+  }
+  // Make sure that everything reinserts in the right spot. Returns the number of errors.
+  size_t Verify() {
+    size_t errors = 0;
+    for (size_t i = 0; i < num_buckets_; ++i) {
+      T& element = data_[i];
+      if (!emptyfn_.IsEmpty(element)) {
+        T temp;
+        emptyfn_.MakeEmpty(temp);
+        std::swap(temp, element);
+        size_t first_slot = FirstAvailableSlot(IndexForHash(hashfn_(temp)));
+        if (i != first_slot) {
+          LOG(ERROR) << "Element " << i << " should be in slot " << first_slot;
+          ++errors;
+        }
+        std::swap(temp, element);
+      }
+    }
+    return errors;
+  }
+
+ private:
+  T& ElementForIndex(size_t index) {
+    DCHECK_LT(index, NumBuckets());
+    DCHECK(data_ != nullptr);
+    return data_[index];
+  }
+  const T& ElementForIndex(size_t index) const {
+    DCHECK_LT(index, NumBuckets());
+    DCHECK(data_ != nullptr);
+    return data_[index];
+  }
+  size_t IndexForHash(size_t hash) const {
+    return hash % num_buckets_;
+  }
+  size_t NextIndex(size_t index) const {
+    if (UNLIKELY(++index >= num_buckets_)) {
+      DCHECK_EQ(index, NumBuckets());
+      return 0;
+    }
+    return index;
+  }
+  bool IsFreeSlot(size_t index) const {
+    return emptyfn_.IsEmpty(ElementForIndex(index));
+  }
+  size_t NumBuckets() const {
+    return num_buckets_;
+  }
+  // Allocate a number of buckets.
+  void AllocateStorage(size_t num_buckets) {
+    num_buckets_ = num_buckets;
+    data_ = allocfn_.allocate(num_buckets_);
+    for (size_t i = 0; i < num_buckets_; ++i) {
+      allocfn_.construct(allocfn_.address(data_[i]));
+      emptyfn_.MakeEmpty(data_[i]);
+    }
+  }
+  void DeallocateStorage() {
+    if (num_buckets_ != 0) {
+      for (size_t i = 0; i < NumBuckets(); ++i) {
+        allocfn_.destroy(allocfn_.address(data_[i]));
+      }
+      allocfn_.deallocate(data_, NumBuckets());
+      data_ = nullptr;
+      num_buckets_ = 0;
+    }
+  }
+  // Expand the set based on the load factors.
+  void Expand() {
+    size_t min_index = static_cast<size_t>(Size() / min_load_factor_);
+    if (min_index < kMinBuckets) {
+      min_index = kMinBuckets;
+    }
+    // Resize based on the minimum load factor.
+    Resize(min_index);
+    // When we hit elements_until_expand_, we are at the max load factor and must expand again.
+    elements_until_expand_ = NumBuckets() * max_load_factor_;
+  }
+  // Expand / shrink the table to the new specified size.
+  void Resize(size_t new_size) {
+    DCHECK_GE(new_size, Size());
+    T* old_data = data_;
+    size_t old_num_buckets = num_buckets_;
+    // Reinsert all of the old elements.
+    AllocateStorage(new_size);
+    for (size_t i = 0; i < old_num_buckets; ++i) {
+      T& element = old_data[i];
+      if (!emptyfn_.IsEmpty(element)) {
+        data_[FirstAvailableSlot(IndexForHash(hashfn_(element)))] = std::move(element);
+      }
+      allocfn_.destroy(allocfn_.address(element));
+    }
+    allocfn_.deallocate(old_data, old_num_buckets);
+  }
+  ALWAYS_INLINE size_t FirstAvailableSlot(size_t index) const {
+    while (!emptyfn_.IsEmpty(data_[index])) {
+      index = NextIndex(index);
+    }
+    return index;
+  }
+
+  Alloc allocfn_;  // Allocator function.
+  HashFn hashfn_;  // Hashing function.
+  EmptyFn emptyfn_;  // IsEmpty/SetEmpty function.
+  Pred pred_;  // Equals function.
+  size_t num_elements_;  // Number of inserted elements.
+  size_t num_buckets_;  // Number of hash table buckets.
+  size_t elements_until_expand_;  // Maxmimum number of elements until we expand the table.
+  T* data_;  // Backing storage.
+  double min_load_factor_;
+  double max_load_factor_;
+
+  friend class Iterator;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_HASH_SET_H_
diff --git a/runtime/base/hash_set_test.cc b/runtime/base/hash_set_test.cc
new file mode 100644
index 0000000..5f498d9
--- /dev/null
+++ b/runtime/base/hash_set_test.cc
@@ -0,0 +1,223 @@
+/*
+ * 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 "hash_set.h"
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <unordered_set>
+
+#include "common_runtime_test.h"
+#include "hash_map.h"
+
+namespace art {
+
+struct IsEmptyFnString {
+  void MakeEmpty(std::string& item) const {
+    item.clear();
+  }
+  bool IsEmpty(const std::string& item) const {
+    return item.empty();
+  }
+};
+
+class HashSetTest : public CommonRuntimeTest {
+ public:
+  HashSetTest() : seed_(97421), unique_number_(0) {
+  }
+  std::string RandomString(size_t len) {
+    std::ostringstream oss;
+    for (size_t i = 0; i < len; ++i) {
+      oss << static_cast<char>('A' + PRand() % 64);
+    }
+    static_assert(' ' < 'A', "space must be less than a");
+    oss << " " << unique_number_++;  // Relies on ' ' < 'A'
+    return oss.str();
+  }
+  void SetSeed(size_t seed) {
+    seed_ = seed;
+  }
+  size_t PRand() {  // Pseudo random.
+    seed_ = seed_ * 1103515245 + 12345;
+    return seed_;
+  }
+
+ private:
+  size_t seed_;
+  size_t unique_number_;
+};
+
+TEST_F(HashSetTest, TestSmoke) {
+  HashSet<std::string, IsEmptyFnString> hash_set;
+  const std::string test_string = "hello world 1234";
+  ASSERT_TRUE(hash_set.Empty());
+  ASSERT_EQ(hash_set.Size(), 0U);
+  hash_set.Insert(test_string);
+  auto it = hash_set.Find(test_string);
+  ASSERT_EQ(*it, test_string);
+  auto after_it = hash_set.Erase(it);
+  ASSERT_TRUE(after_it == hash_set.end());
+  ASSERT_TRUE(hash_set.Empty());
+  ASSERT_EQ(hash_set.Size(), 0U);
+  it = hash_set.Find(test_string);
+  ASSERT_TRUE(it == hash_set.end());
+}
+
+TEST_F(HashSetTest, TestInsertAndErase) {
+  HashSet<std::string, IsEmptyFnString> hash_set;
+  static constexpr size_t count = 1000;
+  std::vector<std::string> strings;
+  for (size_t i = 0; i < count; ++i) {
+    // Insert a bunch of elements and make sure we can find them.
+    strings.push_back(RandomString(10));
+    hash_set.Insert(strings[i]);
+    auto it = hash_set.Find(strings[i]);
+    ASSERT_TRUE(it != hash_set.end());
+    ASSERT_EQ(*it, strings[i]);
+  }
+  ASSERT_EQ(strings.size(), hash_set.Size());
+  // Try to erase the odd strings.
+  for (size_t i = 1; i < count; i += 2) {
+    auto it = hash_set.Find(strings[i]);
+    ASSERT_TRUE(it != hash_set.end());
+    ASSERT_EQ(*it, strings[i]);
+    hash_set.Erase(it);
+  }
+  // Test removed.
+  for (size_t i = 1; i < count; i += 2) {
+    auto it = hash_set.Find(strings[i]);
+    ASSERT_TRUE(it == hash_set.end());
+  }
+  for (size_t i = 0; i < count; i += 2) {
+    auto it = hash_set.Find(strings[i]);
+    ASSERT_TRUE(it != hash_set.end());
+    ASSERT_EQ(*it, strings[i]);
+  }
+}
+
+TEST_F(HashSetTest, TestIterator) {
+  HashSet<std::string, IsEmptyFnString> hash_set;
+  ASSERT_TRUE(hash_set.begin() == hash_set.end());
+  static constexpr size_t count = 1000;
+  std::vector<std::string> strings;
+  for (size_t i = 0; i < count; ++i) {
+    // Insert a bunch of elements and make sure we can find them.
+    strings.push_back(RandomString(10));
+    hash_set.Insert(strings[i]);
+  }
+  // Make sure we visit each string exactly once.
+  std::map<std::string, size_t> found_count;
+  for (const std::string& s : hash_set) {
+    ++found_count[s];
+  }
+  for (size_t i = 0; i < count; ++i) {
+    ASSERT_EQ(found_count[strings[i]], 1U);
+  }
+  found_count.clear();
+  // Remove all the elements with iterator erase.
+  for (auto it = hash_set.begin(); it != hash_set.end();) {
+    ++found_count[*it];
+    it = hash_set.Erase(it);
+    ASSERT_EQ(hash_set.Verify(), 0U);
+  }
+  for (size_t i = 0; i < count; ++i) {
+    ASSERT_EQ(found_count[strings[i]], 1U);
+  }
+}
+
+TEST_F(HashSetTest, TestSwap) {
+  HashSet<std::string, IsEmptyFnString> hash_seta, hash_setb;
+  std::vector<std::string> strings;
+  static constexpr size_t count = 1000;
+  for (size_t i = 0; i < count; ++i) {
+    strings.push_back(RandomString(10));
+    hash_seta.Insert(strings[i]);
+  }
+  std::swap(hash_seta, hash_setb);
+  hash_seta.Insert("TEST");
+  hash_setb.Insert("TEST2");
+  for (size_t i = 0; i < count; ++i) {
+    strings.push_back(RandomString(10));
+    hash_seta.Insert(strings[i]);
+  }
+}
+
+TEST_F(HashSetTest, TestStress) {
+  HashSet<std::string, IsEmptyFnString> hash_set;
+  std::unordered_multiset<std::string> std_set;
+  std::vector<std::string> strings;
+  static constexpr size_t string_count = 2000;
+  static constexpr size_t operations = 100000;
+  static constexpr size_t target_size = 5000;
+  for (size_t i = 0; i < string_count; ++i) {
+    strings.push_back(RandomString(i % 10 + 1));
+  }
+  const size_t seed = time(nullptr);
+  SetSeed(seed);
+  LOG(INFO) << "Starting stress test with seed " << seed;
+  for (size_t i = 0; i < operations; ++i) {
+    ASSERT_EQ(hash_set.Size(), std_set.size());
+    size_t delta = std::abs(static_cast<ssize_t>(target_size) -
+                            static_cast<ssize_t>(hash_set.Size()));
+    size_t n = PRand();
+    if (n % target_size == 0) {
+      hash_set.Clear();
+      std_set.clear();
+      ASSERT_TRUE(hash_set.Empty());
+      ASSERT_TRUE(std_set.empty());
+    } else  if (n % target_size < delta) {
+      // Skew towards adding elements until we are at the desired size.
+      const std::string& s = strings[PRand() % string_count];
+      hash_set.Insert(s);
+      std_set.insert(s);
+      ASSERT_EQ(*hash_set.Find(s), *std_set.find(s));
+    } else {
+      const std::string& s = strings[PRand() % string_count];
+      auto it1 = hash_set.Find(s);
+      auto it2 = std_set.find(s);
+      ASSERT_EQ(it1 == hash_set.end(), it2 == std_set.end());
+      if (it1 != hash_set.end()) {
+        ASSERT_EQ(*it1, *it2);
+        hash_set.Erase(it1);
+        std_set.erase(it2);
+      }
+    }
+  }
+}
+
+struct IsEmptyStringPair {
+  void MakeEmpty(std::pair<std::string, int>& pair) const {
+    pair.first.clear();
+  }
+  bool IsEmpty(const std::pair<std::string, int>& pair) const {
+    return pair.first.empty();
+  }
+};
+
+TEST_F(HashSetTest, TestHashMap) {
+  HashMap<std::string, int, IsEmptyStringPair> hash_map;
+  hash_map.Insert(std::make_pair(std::string("abcd"), 123));
+  hash_map.Insert(std::make_pair(std::string("abcd"), 124));
+  hash_map.Insert(std::make_pair(std::string("bags"), 444));
+  auto it = hash_map.Find(std::string("abcd"));
+  ASSERT_EQ(it->second, 123);
+  hash_map.Erase(it);
+  it = hash_map.Find(std::string("abcd"));
+  ASSERT_EQ(it->second, 124);
+}
+
+}  // namespace art
diff --git a/runtime/base/hex_dump.cc b/runtime/base/hex_dump.cc
index 936c52b..5423ff0 100644
--- a/runtime/base/hex_dump.cc
+++ b/runtime/base/hex_dump.cc
@@ -35,7 +35,7 @@
   static const char gHexDigit[] = "0123456789abcdef";
   const unsigned char* addr = reinterpret_cast<const unsigned char*>(address_);
   // 01234560: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff  0123456789abcdef
-  char out[(kBitsPerWord / 4) + /* offset */
+  char out[(kBitsPerIntPtrT / 4) + /* offset */
            1 + /* colon */
            (16 * 3) + /* 16 hex digits and space */
            2 + /* white space */
@@ -49,7 +49,7 @@
     offset = 0;
   }
   memset(out, ' ', sizeof(out)-1);
-  out[kBitsPerWord / 4] = ':';
+  out[kBitsPerIntPtrT / 4] = ':';
   out[sizeof(out)-1] = '\0';
 
   size_t byte_count = byte_count_;
@@ -58,11 +58,11 @@
     size_t line_offset = offset & ~0x0f;
 
     char* hex = out;
-    char* asc = out + (kBitsPerWord / 4) + /* offset */ 1 + /* colon */
+    char* asc = out + (kBitsPerIntPtrT / 4) + /* offset */ 1 + /* colon */
         (16 * 3) + /* 16 hex digits and space */ 2 /* white space */;
 
-    for (int i = 0; i < (kBitsPerWord / 4); i++) {
-      *hex++ = gHexDigit[line_offset >> (kBitsPerWord - 4)];
+    for (int i = 0; i < (kBitsPerIntPtrT / 4); i++) {
+      *hex++ = gHexDigit[line_offset >> (kBitsPerIntPtrT - 4)];
       line_offset <<= 4;
     }
     hex++;
diff --git a/runtime/base/hex_dump_test.cc b/runtime/base/hex_dump_test.cc
index 3d782b2..bfd5c75 100644
--- a/runtime/base/hex_dump_test.cc
+++ b/runtime/base/hex_dump_test.cc
@@ -56,7 +56,7 @@
   std::ostringstream oss;
   oss << HexDump(&g16byte_aligned_number, 8, true, "");
   // Compare ignoring pointer.
-  EXPECT_STREQ(oss.str().c_str() + (kBitsPerWord / 4),
+  EXPECT_STREQ(oss.str().c_str() + (kBitsPerIntPtrT / 4),
                ": 68 67 66 65 64 63 62 61                          hgfedcba        ");
 }
 
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index 4c18ce4..812ed86 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -35,10 +35,13 @@
     DCHECK_GT(new_max, max_);
     GrowBuckets(new_max);
   }
-
   BucketiseValue(value);
 }
 
+template <class Value> inline void Histogram<Value>::AdjustAndAddValue(Value value) {
+  AddValue(value / kAdjust);
+}
+
 template <class Value> inline Histogram<Value>::Histogram(const char* name)
     : kAdjust(0),
       kInitialBucketCount(0),
@@ -195,6 +198,11 @@
   DCHECK_LE(std::abs(out_data->perc_.back() - 1.0), 0.001);
 }
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
 template <class Value>
 inline double Histogram<Value>::Percentile(double per, const CumulativeData& data) const {
   DCHECK_GT(data.perc_.size(), 0ull);
@@ -235,6 +243,10 @@
   return value;
 }
 
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
 }  // namespace art
 #endif  // ART_RUNTIME_BASE_HISTOGRAM_INL_H_
 
diff --git a/runtime/base/histogram.h b/runtime/base/histogram.h
index 1e12be8..78f6e1c 100644
--- a/runtime/base/histogram.h
+++ b/runtime/base/histogram.h
@@ -46,6 +46,7 @@
   // This is the expected constructor when creating new Histograms.
   Histogram(const char* name, Value initial_bucket_width, size_t max_buckets = 100);
   void AddValue(Value);
+  void AdjustAndAddValue(Value);  // Add a value after dividing it by kAdjust.
   // Builds the cumulative distribution function from the frequency data.
   // Accumulative summation of frequencies.
   // cumulative_freq[i] = sum(frequency[j] : 0 < j < i )
diff --git a/runtime/base/histogram_test.cc b/runtime/base/histogram_test.cc
index 454f2ab..7aa5f90 100644
--- a/runtime/base/histogram_test.cc
+++ b/runtime/base/histogram_test.cc
@@ -41,14 +41,14 @@
     hist->AddValue(static_cast<uint64_t>(50));
   }
   mean = hist->Mean();
-  EXPECT_EQ(mean, 50);
+  EXPECT_DOUBLE_EQ(mean, 50.0);
   hist->Reset();
   hist->AddValue(9);
   hist->AddValue(17);
   hist->AddValue(28);
   hist->AddValue(28);
   mean = hist->Mean();
-  EXPECT_EQ(20.5, mean);
+  EXPECT_DOUBLE_EQ(20.5, mean);
 }
 
 TEST(Histtest, VarianceTest) {
@@ -60,7 +60,7 @@
   hist->AddValue(28);
   hist->AddValue(28);
   variance = hist->Variance();
-  EXPECT_EQ(64.25, variance);
+  EXPECT_DOUBLE_EQ(64.25, variance);
 }
 
 TEST(Histtest, Percentile) {
@@ -236,7 +236,7 @@
   }
   hist->CreateHistogram(&data);
   per_995 = hist->Percentile(0.995, data);
-  EXPECT_EQ(per_995, 0);
+  EXPECT_DOUBLE_EQ(per_995, 0.0);
   hist->Reset();
   for (size_t idx = 0; idx < 200; idx++) {
     for (uint64_t val = 1ull; val <= 4ull; val++) {
@@ -246,8 +246,8 @@
   hist->CreateHistogram(&data);
   per_005 = hist->Percentile(0.005, data);
   per_995 = hist->Percentile(0.995, data);
-  EXPECT_EQ(1, per_005);
-  EXPECT_EQ(4, per_995);
+  EXPECT_DOUBLE_EQ(1.0, per_005);
+  EXPECT_DOUBLE_EQ(4.0, per_995);
 }
 
 TEST(Histtest, SpikyValues) {
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index b2ad1d0..0764b87 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -16,17 +16,27 @@
 
 #include "logging.h"
 
+#include <iostream>
+#include <limits>
+#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;
@@ -34,6 +44,19 @@
 static std::unique_ptr<std::string> gProgramInvocationName;
 static std::unique_ptr<std::string> gProgramInvocationShortName;
 
+// Print INTERNAL_FATAL messages directly instead of at destruction time. This only works on the
+// host right now: for the device, a stream buf collating output into lines and calling LogLine or
+// lower-level logging is necessary.
+#ifdef HAVE_ANDROID_OS
+static constexpr bool kPrintInternalFatalDirectly = false;
+#else
+static constexpr bool kPrintInternalFatalDirectly = !kIsTargetBuild;
+#endif
+
+static bool PrintDirectly(LogSeverity severity) {
+  return kPrintInternalFatalDirectly && severity == INTERNAL_FATAL;
+}
+
 const char* GetCmdLine() {
   return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
 }
@@ -47,14 +70,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 +80,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 +134,182 @@
   }
 }
 
-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)) {
+  if (PrintDirectly(severity)) {
+    static const char* log_characters = "VDIWEFF";
+    CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
+    stream() << ProgramInvocationShortName() << " " << log_characters[static_cast<size_t>(severity)]
+             << " " << getpid() << " " << ::art::GetTid() << " " << file << ":" <<  line << "]";
+  }
 }
-
 LogMessage::~LogMessage() {
-  if (data_->severity < gMinimumLogSeverity) {
-    return;  // No need to format something we're not going to output.
-  }
+  if (!PrintDirectly(data_->GetSeverity())) {
+    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);
-  }
-  std::string msg(data_->buffer.str());
+    // Finish constructing the message.
+    if (data_->GetError() != -1) {
+      data_->GetBuffer() << ": " << strerror(data_->GetError());
+    }
+    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());
-    } 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]);
-        i = nl + 1;
+    // Do the actual logging with the lock held.
+    {
+      MutexLock mu(Thread::Current(), *Locks::logging_lock_);
+      if (msg.find('\n') == std::string::npos) {
+        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_->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() {
+  if (PrintDirectly(data_->GetSeverity())) {
+    return std::cerr;
+  }
+  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
+};
+static_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
+}
+
+void LogMessage::LogLineLowStack(const char* file, unsigned int line, LogSeverity log_severity,
+                                 const char* message) {
+#ifdef HAVE_ANDROID_OS
+  // Use android_writeLog() to avoid stack-based buffers used by android_printLog().
+  const char* tag = ProgramInvocationShortName();
+  int priority = kLogSeverityToAndroidLogPriority[log_severity];
+  char* buf = nullptr;
+  size_t buf_size = 0u;
+  if (priority == ANDROID_LOG_FATAL) {
+    // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line, message) below.
+    // If allocation fails, fall back to printing only the message.
+    buf_size = strlen(file) + 1 /* ':' */ + std::numeric_limits<typeof(line)>::max_digits10 +
+        2 /* "] " */ + strlen(message) + 1 /* terminating 0 */;
+    buf = reinterpret_cast<char*>(malloc(buf_size));
+  }
+  if (buf != nullptr) {
+    snprintf(buf, buf_size, "%s:%u] %s", file, line, message);
+    android_writeLog(priority, tag, buf);
+    free(buf);
+  } else {
+    android_writeLog(priority, tag, message);
+  }
+#else
+  static const char* log_characters = "VDIWEFF";
+  CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
+
+  const char* program_name = ProgramInvocationShortName();
+  write(STDERR_FILENO, program_name, strlen(program_name));
+  write(STDERR_FILENO, " ", 1);
+  write(STDERR_FILENO, &log_characters[log_severity], 1);
+  write(STDERR_FILENO, " ", 1);
+  // TODO: pid and tid.
+  write(STDERR_FILENO, file, strlen(file));
+  // TODO: line.
+  UNUSED(line);
+  write(STDERR_FILENO, "] ", 2);
+  write(STDERR_FILENO, message, strlen(message));
+  write(STDERR_FILENO, "\n", 1);
+#endif
+}
+
+ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
+  old_ = gMinimumLogSeverity;
+  gMinimumLogSeverity = level;
+}
+
+ScopedLogSeverity::~ScopedLogSeverity() {
+  gMinimumLogSeverity = old_;
+}
+
 }  // namespace art
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index cf3e763..cc1a4a1 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,44 @@
 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);
+
+  // A variant of the above for use with little stack.
+  static void LogLineLowStack(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 {
+// Allows to temporarily change the minimum severity level for logging.
+class ScopedLogSeverity {
  public:
-  explicit Dumpable(T& value) : value_(value) {
-  }
-
-  void Dump(std::ostream& os) const {
-    value_.Dump(os);
-  }
+  explicit ScopedLogSeverity(LogSeverity level);
+  ~ScopedLogSeverity();
 
  private:
-  T& value_;
-
-  DISALLOW_COPY_AND_ASSIGN(Dumpable);
+  LogSeverity old_;
 };
 
-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 b66d528..f705469 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -41,44 +41,35 @@
 #define FINAL
 #endif
 
-// The COMPILE_ASSERT macro can be used to verify that a compile time
-// expression is true. For example, you could use it to verify the
-// size of a static array:
-//
-//   COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
-//                  content_type_names_incorrect_size);
-//
-// or to make sure a struct is smaller than a certain size:
-//
-//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
-//
-// The second argument to the macro is the name of the variable. If
-// the expression is false, most compilers will issue a warning/error
-// containing the name of the variable.
+// 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
 
-template <bool>
-struct CompileAssert {
-};
-
-#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.
+// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
+// declarations in a class.
+#if !defined(DISALLOW_COPY_AND_ASSIGN)
 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);               \
-  void operator=(const TypeName&)
+  TypeName(const TypeName&) = delete;  \
+  void operator=(const TypeName&) = delete
+#endif
 
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
+// 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
@@ -167,6 +158,8 @@
 #define ALWAYS_INLINE_LAMBDA ALWAYS_INLINE
 #endif
 
+#define NO_INLINE __attribute__ ((noinline))
+
 #if defined (__APPLE__)
 #define HOT_ATTR
 #define COLD_ATTR
@@ -178,9 +171,63 @@
 #define PURE __attribute__ ((__pure__))
 #define WARN_UNUSED __attribute__((warn_unused_result))
 
-template<typename T> void UNUSED(const T&) {}
+// A deprecated function to call to create a false use of the parameter, for example:
+//   int foo(int x) { UNUSED(x); return 10; }
+// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
+template<typename... T> void UNUSED(const T&...) {}
+
+// An attribute to place on a parameter to a function, for example:
+//   int foo(int x ATTRIBUTE_UNUSED) { return 10; }
+// to avoid compiler warnings.
+#define ATTRIBUTE_UNUSED __attribute__((__unused__))
+
+// Define that a position within code is unreachable, for example:
+//   int foo () { LOG(FATAL) << "Don't call me"; UNREACHABLE(); }
+// without the UNREACHABLE a return statement would be necessary.
 #define UNREACHABLE  __builtin_unreachable
 
+// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
+// between switch labels:
+//  switch (x) {
+//    case 40:
+//    case 41:
+//      if (truth_is_out_there) {
+//        ++x;
+//        FALLTHROUGH_INTENDED;  // Use instead of/along with annotations in
+//                               // comments.
+//      } else {
+//        return x;
+//      }
+//    case 42:
+//      ...
+//
+//  As shown in the example above, the FALLTHROUGH_INTENDED macro should be
+//  followed by a semicolon. It is designed to mimic control-flow statements
+//  like 'break;', so it can be placed in most places where 'break;' can, but
+//  only if there are no statements on the execution path between it and the
+//  next switch label.
+//
+//  When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
+//  expanded to [[clang::fallthrough]] attribute, which is analysed when
+//  performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
+//  See clang documentation on language extensions for details:
+//  http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
+//
+//  When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
+//  effect on diagnostics.
+//
+//  In either case this macro has no effect on runtime behavior and performance
+//  of code.
+#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
+#endif
+#endif
+
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED do { } while (0)
+#endif
+
 // Annotalysis thread-safety analysis support.
 #if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
 #define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index f70db35..cb69817 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -21,58 +21,29 @@
 
 #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"
 
-namespace art {
-
-#define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_)
-
 #if ART_USE_FUTEXES
 #include "linux/futex.h"
 #include "sys/syscall.h"
 #ifndef SYS_futex
 #define SYS_futex __NR_futex
 #endif
+#endif  // ART_USE_FUTEXES
+
+#define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_)
+
+namespace art {
+
+#if ART_USE_FUTEXES
 static inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3) {
   return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
 }
 #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());
@@ -126,7 +97,9 @@
         }
       }
     }
-    CHECK(!bad_mutexes_held);
+    if (gAborting == 0) {  // Avoid recursive aborts.
+      CHECK(!bad_mutexes_held);
+    }
   }
   // Don't record monitors as they are outside the scope of analysis. They may be inspected off of
   // the monitor list.
@@ -141,7 +114,7 @@
     return;
   }
   if (level_ != kMonitorLock) {
-    if (kDebugLocking && !gAborting) {
+    if (kDebugLocking && gAborting == 0) {  // Avoid recursive aborts.
       CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_;
     }
     self->SetHeldMutex(level_, NULL);
@@ -158,15 +131,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 4383a7c..17b2ac9 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"
@@ -53,7 +57,6 @@
 Mutex* Locks::reference_queue_weak_references_lock_ = nullptr;
 Mutex* Locks::runtime_shutdown_lock_ = nullptr;
 Mutex* Locks::thread_list_lock_ = nullptr;
-Mutex* Locks::thread_list_suspend_thread_lock_ = nullptr;
 Mutex* Locks::thread_suspend_count_lock_ = nullptr;
 Mutex* Locks::trace_lock_ = nullptr;
 Mutex* Locks::unexpected_signal_lock_ = nullptr;
@@ -83,22 +86,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);
@@ -161,7 +201,7 @@
       if (i != level_) {
         BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
         // We expect waits to happen while holding the thread list suspend thread lock.
-        if (held_mutex != NULL && i != kThreadListSuspendThreadLock) {
+        if (held_mutex != NULL) {
           LOG(ERROR) << "Holding \"" << held_mutex->name_ << "\" "
                      << "(level " << LockLevel(i) << ") while performing wait on "
                      << "\"" << name_ << "\" (level " << level_ << ")";
@@ -169,7 +209,9 @@
         }
       }
     }
-    CHECK(!bad_mutexes_held);
+    if (gAborting == 0) {  // Avoid recursive aborts.
+      CHECK(!bad_mutexes_held);
+    }
   }
 }
 
@@ -285,8 +327,12 @@
     LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " << exclusive_owner_;
   } else {
     CHECK_EQ(exclusive_owner_, 0U)  << "unexpectedly found an owner on unlocked mutex " << name_;
-    CHECK_EQ(num_contenders_.LoadSequentiallyConsistent(), 0)
-        << "unexpectedly found a contender on mutex " << name_;
+    if (level_ != kMonitorLock) {
+      // Only check the lock level for non monitor locks since we may still have java threads
+      // waiting on monitors.
+      CHECK_EQ(num_contenders_.LoadSequentiallyConsistent(), 0)
+          << "unexpectedly found a contender on mutex " << name_;
+    }
   }
 #else
   // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread
@@ -388,7 +434,17 @@
 }
 
 void Mutex::ExclusiveUnlock(Thread* self) {
-  DCHECK(self == NULL || self == Thread::Current());
+  if (kIsDebugBuild && self != nullptr && self != Thread::Current()) {
+    std::string name1 = "<null>";
+    std::string name2 = "<null>";
+    if (self != nullptr) {
+      self->GetThreadName(name1);
+    }
+    if (Thread::Current() != nullptr) {
+      Thread::Current()->GetThreadName(name2);
+    }
+    LOG(FATAL) << name1 << " " << name2;
+  }
   AssertHeld(self);
   DCHECK_NE(exclusive_owner_, 0U);
   recursion_count_--;
@@ -421,9 +477,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);
         }
       }
@@ -556,7 +612,7 @@
 #if ART_USE_FUTEXES
   bool done = false;
   timespec end_abs_ts;
-  InitTimeSpec(true, CLOCK_REALTIME, ms, ns, &end_abs_ts);
+  InitTimeSpec(true, CLOCK_MONOTONIC, ms, ns, &end_abs_ts);
   do {
     int32_t cur_state = state_.LoadRelaxed();
     if (cur_state == 0) {
@@ -565,7 +621,7 @@
     } else {
       // Failed to acquire, hang up.
       timespec now_abs_ts;
-      InitTimeSpec(true, CLOCK_REALTIME, 0, 0, &now_abs_ts);
+      InitTimeSpec(true, CLOCK_MONOTONIC, 0, 0, &now_abs_ts);
       timespec rel_ts;
       if (ComputeRelativeTimeSpec(&rel_ts, end_abs_ts, now_abs_ts)) {
         return false;  // Timed out.
@@ -605,6 +661,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
@@ -648,7 +718,13 @@
 void ReaderWriterMutex::Dump(std::ostream& os) const {
   os << name_
       << " level=" << static_cast<int>(level_)
-      << " owner=" << GetExclusiveOwnerTid() << " ";
+      << " owner=" << GetExclusiveOwnerTid()
+#if ART_USE_FUTEXES
+      << " state=" << state_.LoadSequentiallyConsistent()
+      << " num_pending_writers=" << num_pending_writers_.LoadSequentiallyConsistent()
+      << " num_pending_readers=" << num_pending_readers_.LoadSequentiallyConsistent()
+#endif
+      << " ";
   DumpContention(os);
 }
 
@@ -667,7 +743,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
@@ -857,16 +933,14 @@
     DCHECK(mutator_lock_ != nullptr);
     DCHECK(profiler_lock_ != nullptr);
     DCHECK(thread_list_lock_ != nullptr);
-    DCHECK(thread_list_suspend_thread_lock_ != nullptr);
     DCHECK(thread_suspend_count_lock_ != nullptr);
     DCHECK(trace_lock_ != nullptr);
     DCHECK(unexpected_signal_lock_ != nullptr);
   } else {
     // Create global locks in level order from highest lock level to lowest.
-    LockLevel current_lock_level = kThreadListSuspendThreadLock;
-    DCHECK(thread_list_suspend_thread_lock_ == nullptr);
-    thread_list_suspend_thread_lock_ =
-        new Mutex("thread list suspend thread by .. lock", current_lock_level);
+    LockLevel current_lock_level = kInstrumentEntrypointsLock;
+    DCHECK(instrument_entrypoints_lock_ == nullptr);
+    instrument_entrypoints_lock_ = new Mutex("instrument entrypoint lock", current_lock_level);
 
     #define UPDATE_CURRENT_LOCK_LEVEL(new_level) \
       if (new_level >= current_lock_level) { \
@@ -877,10 +951,6 @@
       } \
       current_lock_level = new_level;
 
-    UPDATE_CURRENT_LOCK_LEVEL(kInstrumentEntrypointsLock);
-    DCHECK(instrument_entrypoints_lock_ == nullptr);
-    instrument_entrypoints_lock_ = new Mutex("instrument entrypoint lock", current_lock_level);
-
     UPDATE_CURRENT_LOCK_LEVEL(kMutatorLock);
     DCHECK(mutator_lock_ == nullptr);
     mutator_lock_ = new ReaderWriterMutex("mutator lock", current_lock_level);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 516fa07..9c93cc6 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -101,7 +101,6 @@
   kHeapBitmapLock,
   kMutatorLock,
   kInstrumentEntrypointsLock,
-  kThreadListSuspendThreadLock,
   kZygoteCreationLock,
 
   kLockLevelCount  // Must come last.
@@ -361,6 +360,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.
@@ -432,7 +434,7 @@
   DISALLOW_COPY_AND_ASSIGN(MutexLock);
 };
 // Catch bug where variable name is omitted. "MutexLock (lock);" instead of "MutexLock mu(lock)".
-#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_declaration_missing_variable_name)
+#define MutexLock(x) static_assert(0, "MutexLock declaration missing variable name")
 
 // Scoped locker/unlocker for a ReaderWriterMutex that acquires read access to mu upon
 // construction and releases it upon destruction.
@@ -454,7 +456,7 @@
 };
 // Catch bug where variable name is omitted. "ReaderMutexLock (lock);" instead of
 // "ReaderMutexLock mu(lock)".
-#define ReaderMutexLock(x) COMPILE_ASSERT(0, reader_mutex_lock_declaration_missing_variable_name)
+#define ReaderMutexLock(x) static_assert(0, "ReaderMutexLock declaration missing variable name")
 
 // Scoped locker/unlocker for a ReaderWriterMutex that acquires write access to mu upon
 // construction and releases it upon destruction.
@@ -476,24 +478,15 @@
 };
 // Catch bug where variable name is omitted. "WriterMutexLock (lock);" instead of
 // "WriterMutexLock mu(lock)".
-#define WriterMutexLock(x) COMPILE_ASSERT(0, writer_mutex_lock_declaration_missing_variable_name)
+#define WriterMutexLock(x) static_assert(0, "WriterMutexLock declaration missing variable name")
 
 // Global mutexes corresponding to the levels above.
 class Locks {
  public:
   static void Init();
 
-  // There's a potential race for two threads to try to suspend each other and for both of them
-  // to succeed and get blocked becoming runnable. This lock ensures that only one thread is
-  // requesting suspension of another at any time. As the the thread list suspend thread logic
-  // transitions to runnable, if the current thread were tried to be suspended then this thread
-  // would block holding this lock until it could safely request thread suspension of the other
-  // thread without that thread having a suspension request against this thread. This avoids a
-  // potential deadlock cycle.
-  static Mutex* thread_list_suspend_thread_lock_;
-
   // Guards allocation entrypoint instrumenting.
-  static Mutex* instrument_entrypoints_lock_ ACQUIRED_AFTER(thread_list_suspend_thread_lock_);
+  static Mutex* instrument_entrypoints_lock_;
 
   // The mutator_lock_ is used to allow mutators to execute in a shared (reader) mode or to block
   // mutators by having an exclusive (writer) owner. In normal execution each mutator thread holds
diff --git a/runtime/base/scoped_flock.cc b/runtime/base/scoped_flock.cc
index bf091d0..0e93eee 100644
--- a/runtime/base/scoped_flock.cc
+++ b/runtime/base/scoped_flock.cc
@@ -27,6 +27,9 @@
 
 bool ScopedFlock::Init(const char* filename, std::string* error_msg) {
   while (true) {
+    if (file_.get() != nullptr) {
+      UNUSED(file_->FlushCloseOrErase());  // Ignore result.
+    }
     file_.reset(OS::OpenFileWithFlags(filename, O_CREAT | O_RDWR));
     if (file_.get() == NULL) {
       *error_msg = StringPrintf("Failed to open file '%s': %s", filename, strerror(errno));
@@ -59,7 +62,7 @@
 }
 
 bool ScopedFlock::Init(File* file, std::string* error_msg) {
-  file_.reset(new File(dup(file->Fd())));
+  file_.reset(new File(dup(file->Fd()), true));
   if (file_->Fd() == -1) {
     file_.reset();
     *error_msg = StringPrintf("Failed to duplicate open file '%s': %s",
@@ -89,6 +92,9 @@
   if (file_.get() != NULL) {
     int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN));
     CHECK_EQ(0, flock_result);
+    if (file_->FlushCloseOrErase() != 0) {
+      PLOG(WARNING) << "Could not close scoped file lock file.";
+    }
   }
 }
 
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index ff9f40c..3c5565c 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -57,8 +57,8 @@
 // If container is NULL, this function is a no-op.
 //
 // As an alternative to calling STLDeleteElements() directly, consider
-// ElementDeleter (defined below), which ensures that your container's elements
-// are deleted when the ElementDeleter goes out of scope.
+// using a container of std::unique_ptr, which ensures that your container's
+// elements are deleted when the container goes out of scope.
 template <class T>
 void STLDeleteElements(T *container) {
   if (!container) return;
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/stringpiece.h b/runtime/base/stringpiece.h
index b8de308..d793bb6 100644
--- a/runtime/base/stringpiece.h
+++ b/runtime/base/stringpiece.h
@@ -67,8 +67,8 @@
     ptr_ = nullptr;
     length_ = 0;
   }
-  void set(const char* data, size_type len) {
-    ptr_ = data;
+  void set(const char* data_in, size_type len) {
+    ptr_ = data_in;
     length_ = len;
   }
   void set(const char* str) {
@@ -79,8 +79,8 @@
       length_ = 0;
     }
   }
-  void set(const void* data, size_type len) {
-    ptr_ = reinterpret_cast<const char*>(data);
+  void set(const void* data_in, size_type len) {
+    ptr_ = reinterpret_cast<const char*>(data_in);
     length_ = len;
   }
 
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/type_static_if.h b/runtime/base/type_static_if.h
new file mode 100644
index 0000000..a74d79a
--- /dev/null
+++ b/runtime/base/type_static_if.h
@@ -0,0 +1,32 @@
+/*
+ * 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_RUNTIME_BASE_TYPE_STATIC_IF_H_
+#define ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
+
+// A static if which determines whether to return type A or B based on the condition boolean.
+template <bool condition, typename A, typename B>
+struct TypeStaticIf {
+  typedef A type;
+};
+
+// Specialization to handle the false case.
+template <typename A, typename B>
+struct TypeStaticIf<false, A,  B> {
+  typedef B type;
+};
+
+#endif  // ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index f29a7ec..f272d88 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -14,28 +14,68 @@
  * limitations under the License.
  */
 
-#include "base/logging.h"
 #include "base/unix_file/fd_file.h"
+
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "base/logging.h"
+
 namespace unix_file {
 
-FdFile::FdFile() : fd_(-1), auto_close_(true) {
+FdFile::FdFile() : guard_state_(GuardState::kClosed), fd_(-1), auto_close_(true) {
 }
 
-FdFile::FdFile(int fd) : fd_(fd), auto_close_(true) {
+FdFile::FdFile(int fd, bool check_usage)
+    : guard_state_(check_usage ? GuardState::kBase : GuardState::kNoCheck),
+      fd_(fd), auto_close_(true) {
 }
 
-FdFile::FdFile(int fd, const std::string& path) : fd_(fd), file_path_(path), auto_close_(true) {
+FdFile::FdFile(int fd, const std::string& path, bool check_usage)
+    : guard_state_(check_usage ? GuardState::kBase : GuardState::kNoCheck),
+      fd_(fd), file_path_(path), auto_close_(true) {
   CHECK_NE(0U, path.size());
 }
 
 FdFile::~FdFile() {
+  if (kCheckSafeUsage && (guard_state_ < GuardState::kNoCheck)) {
+    if (guard_state_ < GuardState::kFlushed) {
+      LOG(::art::ERROR) << "File " << file_path_ << " wasn't explicitly flushed before destruction.";
+    }
+    if (guard_state_ < GuardState::kClosed) {
+      LOG(::art::ERROR) << "File " << file_path_ << " wasn't explicitly closed before destruction.";
+    }
+    CHECK_GE(guard_state_, GuardState::kClosed);
+  }
   if (auto_close_ && fd_ != -1) {
-    Close();
+    if (Close() != 0) {
+      PLOG(::art::WARNING) << "Failed to close file " << file_path_;
+    }
+  }
+}
+
+void FdFile::moveTo(GuardState target, GuardState warn_threshold, const char* warning) {
+  if (kCheckSafeUsage) {
+    if (guard_state_ < GuardState::kNoCheck) {
+      if (warn_threshold < GuardState::kNoCheck && guard_state_ >= warn_threshold) {
+        LOG(::art::ERROR) << warning;
+      }
+      guard_state_ = target;
+    }
+  }
+}
+
+void FdFile::moveUp(GuardState target, const char* warning) {
+  if (kCheckSafeUsage) {
+    if (guard_state_ < GuardState::kNoCheck) {
+      if (guard_state_ < target) {
+        guard_state_ = target;
+      } else if (target < guard_state_) {
+        LOG(::art::ERROR) << warning;
+      }
+    }
   }
 }
 
@@ -54,11 +94,28 @@
     return false;
   }
   file_path_ = path;
+  static_assert(O_RDONLY == 0, "Readonly flag has unexpected value.");
+  if (kCheckSafeUsage && (flags & (O_RDWR | O_CREAT | O_WRONLY)) != 0) {
+    // Start in the base state (not flushed, not closed).
+    guard_state_ = GuardState::kBase;
+  } else {
+    // We are not concerned with read-only files. In that case, proper flushing and closing is
+    // not important.
+    guard_state_ = GuardState::kNoCheck;
+  }
   return true;
 }
 
 int FdFile::Close() {
   int result = TEMP_FAILURE_RETRY(close(fd_));
+
+  // Test here, so the file is closed and not leaked.
+  if (kCheckSafeUsage) {
+    CHECK_GE(guard_state_, GuardState::kFlushed) << "File " << file_path_
+        << " has not been flushed before closing.";
+    moveUp(GuardState::kClosed, nullptr);
+  }
+
   if (result == -1) {
     return -errno;
   } else {
@@ -74,6 +131,7 @@
 #else
   int rc = TEMP_FAILURE_RETRY(fsync(fd_));
 #endif
+  moveUp(GuardState::kFlushed, "Flushing closed file.");
   return (rc == -1) ? -errno : rc;
 }
 
@@ -92,6 +150,7 @@
 #else
   int rc = TEMP_FAILURE_RETRY(ftruncate(fd_, new_length));
 #endif
+  moveTo(GuardState::kBase, GuardState::kClosed, "Truncating closed file.");
   return (rc == -1) ? -errno : rc;
 }
 
@@ -107,6 +166,7 @@
 #else
   int rc = TEMP_FAILURE_RETRY(pwrite(fd_, buf, byte_count, offset));
 #endif
+  moveTo(GuardState::kBase, GuardState::kClosed, "Writing into closed file.");
   return (rc == -1) ? -errno : rc;
 }
 
@@ -118,10 +178,16 @@
   return fd_ >= 0;
 }
 
-bool FdFile::ReadFully(void* buffer, size_t byte_count) {
+static ssize_t ReadIgnoreOffset(int fd, void *buf, size_t count, off_t offset) {
+  DCHECK_EQ(offset, 0);
+  return read(fd, buf, count);
+}
+
+template <ssize_t (*read_func)(int, void*, size_t, off_t)>
+static bool ReadFullyGeneric(int fd, void* buffer, size_t byte_count, size_t offset) {
   char* ptr = static_cast<char*>(buffer);
   while (byte_count > 0) {
-    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd_, ptr, byte_count));
+    ssize_t bytes_read = TEMP_FAILURE_RETRY(read_func(fd, ptr, byte_count, offset));
     if (bytes_read <= 0) {
       // 0: end of file
       // -1: error
@@ -129,12 +195,22 @@
     }
     byte_count -= bytes_read;  // Reduce the number of remaining bytes.
     ptr += bytes_read;  // Move the buffer forward.
+    offset += static_cast<size_t>(bytes_read);  // Move the offset forward.
   }
   return true;
 }
 
+bool FdFile::ReadFully(void* buffer, size_t byte_count) {
+  return ReadFullyGeneric<ReadIgnoreOffset>(fd_, buffer, byte_count, 0);
+}
+
+bool FdFile::PreadFully(void* buffer, size_t byte_count, size_t offset) {
+  return ReadFullyGeneric<pread>(fd_, buffer, byte_count, offset);
+}
+
 bool FdFile::WriteFully(const void* buffer, size_t byte_count) {
   const char* ptr = static_cast<const char*>(buffer);
+  moveTo(GuardState::kBase, GuardState::kClosed, "Writing into closed file.");
   while (byte_count > 0) {
     ssize_t bytes_written = TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count));
     if (bytes_written == -1) {
@@ -146,4 +222,42 @@
   return true;
 }
 
+void FdFile::Erase() {
+  TEMP_FAILURE_RETRY(SetLength(0));
+  TEMP_FAILURE_RETRY(Flush());
+  TEMP_FAILURE_RETRY(Close());
+}
+
+int FdFile::FlushCloseOrErase() {
+  int flush_result = TEMP_FAILURE_RETRY(Flush());
+  if (flush_result != 0) {
+    LOG(::art::ERROR) << "CloseOrErase failed while flushing a file.";
+    Erase();
+    return flush_result;
+  }
+  int close_result = TEMP_FAILURE_RETRY(Close());
+  if (close_result != 0) {
+    LOG(::art::ERROR) << "CloseOrErase failed while closing a file.";
+    Erase();
+    return close_result;
+  }
+  return 0;
+}
+
+int FdFile::FlushClose() {
+  int flush_result = TEMP_FAILURE_RETRY(Flush());
+  if (flush_result != 0) {
+    LOG(::art::ERROR) << "FlushClose failed while flushing a file.";
+  }
+  int close_result = TEMP_FAILURE_RETRY(Close());
+  if (close_result != 0) {
+    LOG(::art::ERROR) << "FlushClose failed while closing a file.";
+  }
+  return (flush_result != 0) ? flush_result : close_result;
+}
+
+void FdFile::MarkUnchecked() {
+  guard_state_ = GuardState::kNoCheck;
+}
+
 }  // namespace unix_file
diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h
index 01f4ca2..d51fbd6 100644
--- a/runtime/base/unix_file/fd_file.h
+++ b/runtime/base/unix_file/fd_file.h
@@ -24,6 +24,9 @@
 
 namespace unix_file {
 
+// If true, check whether Flush and Close are called before destruction.
+static constexpr bool kCheckSafeUsage = true;
+
 // A RandomAccessFile implementation backed by a file descriptor.
 //
 // Not thread safe.
@@ -32,8 +35,8 @@
   FdFile();
   // Creates an FdFile using the given file descriptor. Takes ownership of the
   // file descriptor. (Use DisableAutoClose to retain ownership.)
-  explicit FdFile(int fd);
-  explicit FdFile(int fd, const std::string& path);
+  explicit FdFile(int fd, bool checkUsage);
+  explicit FdFile(int fd, const std::string& path, bool checkUsage);
 
   // Destroys an FdFile, closing the file descriptor if Close hasn't already
   // been called. (If you care about the return value of Close, call it
@@ -47,12 +50,21 @@
   bool Open(const std::string& file_path, int flags, mode_t mode);
 
   // RandomAccessFile API.
-  virtual int Close();
-  virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const;
-  virtual int SetLength(int64_t new_length);
+  virtual int Close() WARN_UNUSED;
+  virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const WARN_UNUSED;
+  virtual int SetLength(int64_t new_length) WARN_UNUSED;
   virtual int64_t GetLength() const;
-  virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset);
-  virtual int Flush();
+  virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset) WARN_UNUSED;
+  virtual int Flush() WARN_UNUSED;
+
+  // Short for SetLength(0); Flush(); Close();
+  void Erase();
+
+  // Try to Flush(), then try to Close(); If either fails, call Erase().
+  int FlushCloseOrErase() WARN_UNUSED;
+
+  // Try to Flush and Close(). Attempts both, but returns the first error.
+  int FlushClose() WARN_UNUSED;
 
   // Bonus API.
   int Fd() const;
@@ -61,8 +73,39 @@
     return file_path_;
   }
   void DisableAutoClose();
-  bool ReadFully(void* buffer, size_t byte_count);
-  bool WriteFully(const void* buffer, size_t byte_count);
+  bool ReadFully(void* buffer, size_t byte_count) WARN_UNUSED;
+  bool PreadFully(void* buffer, size_t byte_count, size_t offset) WARN_UNUSED;
+  bool WriteFully(const void* buffer, size_t byte_count) WARN_UNUSED;
+
+  // This enum is public so that we can define the << operator over it.
+  enum class GuardState {
+    kBase,           // Base, file has not been flushed or closed.
+    kFlushed,        // File has been flushed, but not closed.
+    kClosed,         // File has been flushed and closed.
+    kNoCheck         // Do not check for the current file instance.
+  };
+
+  // WARNING: Only use this when you know what you're doing!
+  void MarkUnchecked();
+
+ protected:
+  // If the guard state indicates checking (!=kNoCheck), go to the target state "target". Print the
+  // given warning if the current state is or exceeds warn_threshold.
+  void moveTo(GuardState target, GuardState warn_threshold, const char* warning);
+
+  // If the guard state indicates checking (<kNoCheck), and is below the target state "target", go
+  // to "target." If the current state is higher (excluding kNoCheck) than the trg state, print the
+  // warning.
+  void moveUp(GuardState target, const char* warning);
+
+  // Forcefully sets the state to the given one. This can overwrite kNoCheck.
+  void resetGuard(GuardState new_state) {
+    if (kCheckSafeUsage) {
+      guard_state_ = new_state;
+    }
+  }
+
+  GuardState guard_state_;
 
  private:
   int fd_;
@@ -72,6 +115,8 @@
   DISALLOW_COPY_AND_ASSIGN(FdFile);
 };
 
+std::ostream& operator<<(std::ostream& os, const FdFile::GuardState& kind);
+
 }  // namespace unix_file
 
 #endif  // ART_RUNTIME_BASE_UNIX_FILE_FD_FILE_H_
diff --git a/runtime/base/unix_file/fd_file_test.cc b/runtime/base/unix_file/fd_file_test.cc
index 3481f2f..388f717 100644
--- a/runtime/base/unix_file/fd_file_test.cc
+++ b/runtime/base/unix_file/fd_file_test.cc
@@ -24,7 +24,7 @@
 class FdFileTest : public RandomAccessFileTest {
  protected:
   virtual RandomAccessFile* MakeTestFile() {
-    return new FdFile(fileno(tmpfile()));
+    return new FdFile(fileno(tmpfile()), false);
   }
 };
 
@@ -53,6 +53,7 @@
   ASSERT_TRUE(file.Open(good_path, O_CREAT | O_WRONLY));
   EXPECT_GE(file.Fd(), 0);
   EXPECT_TRUE(file.IsOpened());
+  EXPECT_EQ(0, file.Flush());
   EXPECT_EQ(0, file.Close());
   EXPECT_EQ(-1, file.Fd());
   EXPECT_FALSE(file.IsOpened());
@@ -60,7 +61,7 @@
   EXPECT_GE(file.Fd(), 0);
   EXPECT_TRUE(file.IsOpened());
 
-  file.Close();
+  ASSERT_EQ(file.Close(), 0);
   ASSERT_EQ(unlink(good_path.c_str()), 0);
 }
 
@@ -75,4 +76,38 @@
   EXPECT_FALSE(file.ReadFully(&buffer, 4));
 }
 
+template <size_t Size>
+static void NullTerminateCharArray(char (&array)[Size]) {
+  array[Size - 1] = '\0';
+}
+
+TEST_F(FdFileTest, ReadFullyWithOffset) {
+  // New scratch file, zero-length.
+  art::ScratchFile tmp;
+  FdFile file;
+  ASSERT_TRUE(file.Open(tmp.GetFilename(), O_RDWR));
+  EXPECT_GE(file.Fd(), 0);
+  EXPECT_TRUE(file.IsOpened());
+
+  char ignore_prefix[20] = {'a', };
+  NullTerminateCharArray(ignore_prefix);
+  char read_suffix[10] = {'b', };
+  NullTerminateCharArray(read_suffix);
+
+  off_t offset = 0;
+  // Write scratch data to file that we can read back into.
+  EXPECT_TRUE(file.Write(ignore_prefix, sizeof(ignore_prefix), offset));
+  offset += sizeof(ignore_prefix);
+  EXPECT_TRUE(file.Write(read_suffix, sizeof(read_suffix), offset));
+
+  ASSERT_EQ(file.Flush(), 0);
+
+  // Reading at an offset should only produce 'bbbb...', since we ignore the 'aaa...' prefix.
+  char buffer[sizeof(read_suffix)];
+  EXPECT_TRUE(file.PreadFully(buffer, sizeof(read_suffix), offset));
+  EXPECT_STREQ(&read_suffix[0], &buffer[0]);
+
+  ASSERT_EQ(file.Close(), 0);
+}
+
 }  // namespace unix_file
diff --git a/runtime/base/unix_file/mapped_file.cc b/runtime/base/unix_file/mapped_file.cc
deleted file mode 100644
index 63927b1..0000000
--- a/runtime/base/unix_file/mapped_file.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2008 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 "base/logging.h"
-#include "base/unix_file/mapped_file.h"
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <algorithm>
-#include <string>
-
-namespace unix_file {
-
-MappedFile::~MappedFile() {
-}
-
-int MappedFile::Close() {
-  if (IsMapped()) {
-    Unmap();
-  }
-  return FdFile::Close();
-}
-
-bool MappedFile::MapReadOnly() {
-  CHECK(IsOpened());
-  CHECK(!IsMapped());
-  struct stat st;
-  int result = TEMP_FAILURE_RETRY(fstat(Fd(), &st));
-  if (result == -1) {
-    PLOG(WARNING) << "Failed to stat file '" << GetPath() << "'";
-    return false;
-  }
-  file_size_ = st.st_size;
-  do {
-    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";
-    return false;
-  }
-  map_mode_ = kMapReadOnly;
-  return true;
-}
-
-bool MappedFile::MapReadWrite(int64_t file_size) {
-  CHECK(IsOpened());
-  CHECK(!IsMapped());
-#ifdef __linux__
-  int result = TEMP_FAILURE_RETRY(ftruncate64(Fd(), file_size));
-#else
-  int result = TEMP_FAILURE_RETRY(ftruncate(Fd(), file_size));
-#endif
-  if (result == -1) {
-    PLOG(ERROR) << "Failed to truncate file '" << GetPath()
-                << "' to size " << file_size;
-    return false;
-  }
-  file_size_ = file_size;
-  do {
-    mapped_file_ =
-        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 "
-                  << file_size_ << " bytes to memory";
-    return false;
-  }
-  map_mode_ = kMapReadWrite;
-  return true;
-}
-
-bool MappedFile::Unmap() {
-  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_;
-    return false;
-  } else {
-    mapped_file_ = NULL;
-    file_size_ = -1;
-    return true;
-  }
-}
-
-int64_t MappedFile::Read(char* buf, int64_t byte_count, int64_t offset) const {
-  if (IsMapped()) {
-    if (offset < 0) {
-      errno = EINVAL;
-      return -errno;
-    }
-    int64_t read_size = std::max(static_cast<int64_t>(0),
-                                 std::min(byte_count, file_size_ - offset));
-    if (read_size > 0) {
-      memcpy(buf, data() + offset, read_size);
-    }
-    return read_size;
-  } else {
-    return FdFile::Read(buf, byte_count, offset);
-  }
-}
-
-int MappedFile::SetLength(int64_t new_length) {
-  CHECK(!IsMapped());
-  return FdFile::SetLength(new_length);
-}
-
-int64_t MappedFile::GetLength() const {
-  if (IsMapped()) {
-    return file_size_;
-  } else {
-    return FdFile::GetLength();
-  }
-}
-
-int MappedFile::Flush() {
-  int rc = IsMapped() ? TEMP_FAILURE_RETRY(msync(mapped_file_, file_size_, 0)) : FdFile::Flush();
-  return rc == -1 ? -errno : 0;
-}
-
-int64_t MappedFile::Write(const char* buf, int64_t byte_count, int64_t offset) {
-  if (IsMapped()) {
-    CHECK_EQ(kMapReadWrite, map_mode_);
-    if (offset < 0) {
-      errno = EINVAL;
-      return -errno;
-    }
-    int64_t write_size = std::max(static_cast<int64_t>(0),
-                                  std::min(byte_count, file_size_ - offset));
-    if (write_size > 0) {
-      memcpy(data() + offset, buf, write_size);
-    }
-    return write_size;
-  } else {
-    return FdFile::Write(buf, byte_count, offset);
-  }
-}
-
-int64_t MappedFile::size() const {
-  return GetLength();
-}
-
-bool MappedFile::IsMapped() const {
-  return mapped_file_ != NULL && mapped_file_ != MAP_FAILED;
-}
-
-char* MappedFile::data() const {
-  CHECK(IsMapped());
-  return static_cast<char*>(mapped_file_);
-}
-
-}  // namespace unix_file
diff --git a/runtime/base/unix_file/mapped_file.h b/runtime/base/unix_file/mapped_file.h
deleted file mode 100644
index 73056e9..0000000
--- a/runtime/base/unix_file/mapped_file.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2008 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_UNIX_FILE_MAPPED_FILE_H_
-#define ART_RUNTIME_BASE_UNIX_FILE_MAPPED_FILE_H_
-
-#include <fcntl.h>
-#include <string>
-#include "base/unix_file/fd_file.h"
-
-namespace unix_file {
-
-// Random access file which handles an mmap(2), munmap(2) pair in C++
-// RAII style. When a file is mmapped, the random access file
-// interface accesses the mmapped memory directly; otherwise, the
-// standard file I/O is used. Whenever a function fails, it returns
-// false and errno is set to the corresponding error code.
-class MappedFile : public FdFile {
- public:
-  // File modes used in Open().
-  enum FileMode {
-#ifdef __linux__
-    kReadOnlyMode = O_RDONLY | O_LARGEFILE,
-    kReadWriteMode = O_CREAT | O_RDWR | O_LARGEFILE,
-#else
-    kReadOnlyMode = O_RDONLY,
-    kReadWriteMode = O_CREAT | O_RDWR,
-#endif
-  };
-
-  MappedFile() : FdFile(), file_size_(-1), mapped_file_(NULL) {
-  }
-  // Creates a MappedFile using the given file descriptor. Takes ownership of
-  // the file descriptor.
-  explicit MappedFile(int fd) : FdFile(fd), file_size_(-1), mapped_file_(NULL) {
-  }
-
-  // Unmaps and closes the file if needed.
-  virtual ~MappedFile();
-
-  // Maps an opened file to memory in the read-only mode.
-  bool MapReadOnly();
-
-  // Maps an opened file to memory in the read-write mode. Before the
-  // file is mapped, it is truncated to 'file_size' bytes.
-  bool MapReadWrite(int64_t file_size);
-
-  // Unmaps a mapped file so that, e.g., SetLength() may be invoked.
-  bool Unmap();
-
-  // RandomAccessFile API.
-  // The functions below require that the file is open, but it doesn't
-  // have to be mapped.
-  virtual int Close();
-  virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const;
-  // SetLength() requires that the file is not mmapped.
-  virtual int SetLength(int64_t new_length);
-  virtual int64_t GetLength() const;
-  virtual int Flush();
-  // Write() requires that, if the file is mmapped, it is mmapped in
-  // the read-write mode. Writes past the end of file are discarded.
-  virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset);
-
-  // A convenience method equivalent to GetLength().
-  int64_t size() const;
-
-  // Returns true if the file has been mmapped.
-  bool IsMapped() const;
-
-  // Returns a pointer to the start of the memory mapping once the
-  // file is successfully mapped; crashes otherwise.
-  char* data() const;
-
- private:
-  enum MapMode {
-    kMapReadOnly = 1,
-    kMapReadWrite = 2,
-  };
-
-  mutable int64_t file_size_;  // May be updated in GetLength().
-  void* mapped_file_;
-  MapMode map_mode_;
-
-  DISALLOW_COPY_AND_ASSIGN(MappedFile);
-};
-
-}  // namespace unix_file
-
-#endif  // ART_RUNTIME_BASE_UNIX_FILE_MAPPED_FILE_H_
diff --git a/runtime/base/unix_file/mapped_file_test.cc b/runtime/base/unix_file/mapped_file_test.cc
deleted file mode 100644
index 59334d4..0000000
--- a/runtime/base/unix_file/mapped_file_test.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2008 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 "base/unix_file/mapped_file.h"
-#include "base/logging.h"
-#include "base/unix_file/fd_file.h"
-#include "base/unix_file/random_access_file_test.h"
-#include "base/unix_file/random_access_file_utils.h"
-#include "base/unix_file/string_file.h"
-#include "gtest/gtest.h"
-
-namespace unix_file {
-
-class MappedFileTest : public RandomAccessFileTest {
- protected:
-  MappedFileTest() : kContent("some content") {
-  }
-
-  void SetUp() {
-    RandomAccessFileTest::SetUp();
-
-    good_path_ = GetTmpPath("some-file.txt");
-    int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666));
-    FdFile dst(fd);
-
-    StringFile src;
-    src.Assign(kContent);
-
-    ASSERT_TRUE(CopyFile(src, &dst));
-  }
-
-  void TearDown() {
-    ASSERT_EQ(unlink(good_path_.c_str()), 0);
-
-    RandomAccessFileTest::TearDown();
-  }
-
-  virtual RandomAccessFile* MakeTestFile() {
-    TEMP_FAILURE_RETRY(truncate(good_path_.c_str(), 0));
-    MappedFile* f = new MappedFile;
-    CHECK(f->Open(good_path_, MappedFile::kReadWriteMode));
-    return f;
-  }
-
-  const std::string kContent;
-  std::string good_path_;
-};
-
-TEST_F(MappedFileTest, OkayToNotUse) {
-  MappedFile file;
-  EXPECT_EQ(-1, file.Fd());
-  EXPECT_FALSE(file.IsOpened());
-  EXPECT_FALSE(file.IsMapped());
-}
-
-TEST_F(MappedFileTest, OpenClose) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  EXPECT_GE(file.Fd(), 0);
-  EXPECT_TRUE(file.IsOpened());
-  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
-  EXPECT_EQ(0, file.Close());
-  EXPECT_EQ(-1, file.Fd());
-  EXPECT_FALSE(file.IsOpened());
-}
-
-TEST_F(MappedFileTest, OpenFdClose) {
-  FILE* f = tmpfile();
-  ASSERT_TRUE(f != NULL);
-  MappedFile file(fileno(f));
-  EXPECT_GE(file.Fd(), 0);
-  EXPECT_TRUE(file.IsOpened());
-  EXPECT_EQ(0, file.Close());
-}
-
-TEST_F(MappedFileTest, CanUseAfterMapReadOnly) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  EXPECT_FALSE(file.IsMapped());
-  EXPECT_TRUE(file.MapReadOnly());
-  EXPECT_TRUE(file.IsMapped());
-  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
-  ASSERT_TRUE(file.data());
-  EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size()));
-  EXPECT_EQ(0, file.Flush());
-}
-
-TEST_F(MappedFileTest, CanUseAfterMapReadWrite) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
-  EXPECT_FALSE(file.IsMapped());
-  EXPECT_TRUE(file.MapReadWrite(1));
-  EXPECT_TRUE(file.IsMapped());
-  EXPECT_EQ(1, file.size());
-  ASSERT_TRUE(file.data());
-  EXPECT_EQ(kContent[0], *file.data());
-  EXPECT_EQ(0, file.Flush());
-}
-
-TEST_F(MappedFileTest, CanWriteNewData) {
-  const std::string new_path(GetTmpPath("new-file.txt"));
-  ASSERT_EQ(-1, unlink(new_path.c_str()));
-  ASSERT_EQ(ENOENT, errno);
-
-  MappedFile file;
-  ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode));
-  EXPECT_TRUE(file.MapReadWrite(kContent.size()));
-  EXPECT_TRUE(file.IsMapped());
-  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
-  ASSERT_TRUE(file.data());
-  memcpy(file.data(), kContent.c_str(), kContent.size());
-  EXPECT_EQ(0, file.Close());
-  EXPECT_FALSE(file.IsMapped());
-
-  FdFile new_file(TEMP_FAILURE_RETRY(open(new_path.c_str(), O_RDONLY)));
-  StringFile buffer;
-  ASSERT_TRUE(CopyFile(new_file, &buffer));
-  EXPECT_EQ(kContent, buffer.ToStringPiece());
-  EXPECT_EQ(0, unlink(new_path.c_str()));
-}
-
-TEST_F(MappedFileTest, FileMustExist) {
-  const std::string bad_path(GetTmpPath("does-not-exist.txt"));
-  MappedFile file;
-  EXPECT_FALSE(file.Open(bad_path, MappedFile::kReadOnlyMode));
-  EXPECT_EQ(-1, file.Fd());
-}
-
-TEST_F(MappedFileTest, FileMustBeWritable) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  EXPECT_FALSE(file.MapReadWrite(10));
-}
-
-TEST_F(MappedFileTest, RemappingAllowedUntilSuccess) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  EXPECT_FALSE(file.MapReadWrite(10));
-  EXPECT_FALSE(file.MapReadWrite(10));
-}
-
-TEST_F(MappedFileTest, ResizeMappedFile) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
-  ASSERT_TRUE(file.MapReadWrite(10));
-  EXPECT_EQ(10, file.GetLength());
-  EXPECT_TRUE(file.Unmap());
-  EXPECT_TRUE(file.MapReadWrite(20));
-  EXPECT_EQ(20, file.GetLength());
-  EXPECT_EQ(0, file.Flush());
-  EXPECT_TRUE(file.Unmap());
-  EXPECT_EQ(0, file.Flush());
-  EXPECT_EQ(0, file.SetLength(5));
-  EXPECT_TRUE(file.MapReadOnly());
-  EXPECT_EQ(5, file.GetLength());
-}
-
-TEST_F(MappedFileTest, ReadNotMapped) {
-  TestRead();
-}
-
-TEST_F(MappedFileTest, SetLengthNotMapped) {
-  TestSetLength();
-}
-
-TEST_F(MappedFileTest, WriteNotMapped) {
-  TestWrite();
-}
-
-TEST_F(MappedFileTest, ReadMappedReadOnly) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  ASSERT_TRUE(file.MapReadOnly());
-  TestReadContent(kContent, &file);
-}
-
-TEST_F(MappedFileTest, ReadMappedReadWrite) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
-  ASSERT_TRUE(file.MapReadWrite(kContent.size()));
-  TestReadContent(kContent, &file);
-}
-
-TEST_F(MappedFileTest, WriteMappedReadWrite) {
-  TEMP_FAILURE_RETRY(unlink(good_path_.c_str()));
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
-  ASSERT_TRUE(file.MapReadWrite(kContent.size()));
-
-  // Can't write to a negative offset.
-  EXPECT_EQ(-EINVAL, file.Write(kContent.c_str(), 0, -123));
-
-  // A zero-length write is a no-op.
-  EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0));
-  // But the file size is as given when mapped.
-  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.GetLength()));
-
-  // Data written past the end are discarded.
-  EXPECT_EQ(kContent.size() - 1,
-            static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 1)));
-  EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1));
-
-  // Data can be overwritten.
-  EXPECT_EQ(kContent.size(),
-            static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 0)));
-  EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size()));
-}
-
-#if 0  // death tests don't work on android yet
-
-class MappedFileDeathTest : public MappedFileTest {};
-
-TEST_F(MappedFileDeathTest, MustMapBeforeUse) {
-  MappedFile file;
-  EXPECT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  EXPECT_DEATH(file.data(), "mapped_");
-}
-
-TEST_F(MappedFileDeathTest, RemappingNotAllowedReadOnly) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  ASSERT_TRUE(file.MapReadOnly());
-  EXPECT_DEATH(file.MapReadOnly(), "mapped_");
-}
-
-TEST_F(MappedFileDeathTest, RemappingNotAllowedReadWrite) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
-  ASSERT_TRUE(file.MapReadWrite(10));
-  EXPECT_DEATH(file.MapReadWrite(10), "mapped_");
-}
-
-TEST_F(MappedFileDeathTest, SetLengthMappedReadWrite) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
-  ASSERT_TRUE(file.MapReadWrite(10));
-  EXPECT_EQ(10, file.GetLength());
-  EXPECT_DEATH(file.SetLength(0), ".*");
-}
-
-TEST_F(MappedFileDeathTest, SetLengthMappedReadOnly) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  ASSERT_TRUE(file.MapReadOnly());
-  EXPECT_EQ(kContent.size(), file.GetLength());
-  EXPECT_DEATH(file.SetLength(0), ".*");
-}
-
-TEST_F(MappedFileDeathTest, WriteMappedReadOnly) {
-  MappedFile file;
-  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
-  ASSERT_TRUE(file.MapReadOnly());
-  char buf[10];
-  EXPECT_DEATH(file.Write(buf, 0, 0), ".*");
-}
-
-#endif
-
-}  // namespace unix_file
diff --git a/runtime/base/unix_file/null_file.cc b/runtime/base/unix_file/null_file.cc
deleted file mode 100644
index 050decb..0000000
--- a/runtime/base/unix_file/null_file.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2009 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 "base/unix_file/null_file.h"
-#include <errno.h>
-
-namespace unix_file {
-
-NullFile::NullFile() {
-}
-
-NullFile::~NullFile() {
-}
-
-int NullFile::Close() {
-  return 0;
-}
-
-int NullFile::Flush() {
-  return 0;
-}
-
-int64_t NullFile::Read(char* buf, int64_t byte_count, int64_t offset) const {
-  if (offset < 0) {
-    return -EINVAL;
-  }
-  return 0;
-}
-
-int NullFile::SetLength(int64_t new_length) {
-  if (new_length < 0) {
-    return -EINVAL;
-  }
-  return 0;
-}
-
-int64_t NullFile::GetLength() const {
-  return 0;
-}
-
-int64_t NullFile::Write(const char* buf, int64_t byte_count, int64_t offset) {
-  if (offset < 0) {
-    return -EINVAL;
-  }
-  return byte_count;
-}
-
-}  // namespace unix_file
diff --git a/runtime/base/unix_file/null_file.h b/runtime/base/unix_file/null_file.h
deleted file mode 100644
index 3394731..0000000
--- a/runtime/base/unix_file/null_file.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2009 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_UNIX_FILE_NULL_FILE_H_
-#define ART_RUNTIME_BASE_UNIX_FILE_NULL_FILE_H_
-
-#include "base/unix_file/random_access_file.h"
-#include "base/macros.h"
-
-namespace unix_file {
-
-// A RandomAccessFile implementation equivalent to /dev/null. Writes are
-// discarded, and there's no data to be read. Callers could use FdFile in
-// conjunction with /dev/null, but that's not portable and costs a file
-// descriptor. NullFile is "free".
-//
-// Thread safe.
-class NullFile : public RandomAccessFile {
- public:
-  NullFile();
-  virtual ~NullFile();
-
-  // RandomAccessFile API.
-  virtual int Close();
-  virtual int Flush();
-  virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const;
-  virtual int SetLength(int64_t new_length);
-  virtual int64_t GetLength() const;
-  virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NullFile);
-};
-
-}  // namespace unix_file
-
-#endif  // ART_RUNTIME_BASE_UNIX_FILE_NULL_FILE_H_
diff --git a/runtime/base/unix_file/null_file_test.cc b/runtime/base/unix_file/null_file_test.cc
deleted file mode 100644
index 410fdfc..0000000
--- a/runtime/base/unix_file/null_file_test.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2009 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 "base/unix_file/null_file.h"
-
-#include <errno.h>
-
-#include "gtest/gtest.h"
-
-namespace unix_file {
-
-class NullFileTest : public testing::Test { };
-
-TEST_F(NullFileTest, Read) {
-  NullFile f;
-  char buf[256];
-  // You can't read a negative number of bytes...
-  ASSERT_EQ(-EINVAL, f.Read(buf, 0, -1));
-  // ...but everything else is fine (though you'll get no data).
-  ASSERT_EQ(0, f.Read(buf, 128, 0));
-  ASSERT_EQ(0, f.Read(buf, 128, 128));
-}
-
-TEST_F(NullFileTest, SetLength) {
-  NullFile f;
-  // You can't set a negative length...
-  ASSERT_EQ(-EINVAL, f.SetLength(-1));
-  // ...but everything else is fine.
-  ASSERT_EQ(0, f.SetLength(0));
-  ASSERT_EQ(0, f.SetLength(128));
-}
-
-TEST_F(NullFileTest, GetLength) {
-  const std::string content("hello");
-  NullFile f;
-  // The length is always 0.
-  ASSERT_EQ(0, f.GetLength());
-  ASSERT_EQ(content.size(), static_cast<uint64_t>(f.Write(content.data(), content.size(), 0)));
-  ASSERT_EQ(0, f.GetLength());
-}
-
-TEST_F(NullFileTest, Write) {
-  const std::string content("hello");
-  NullFile f;
-  // You can't write at a negative offset...
-  ASSERT_EQ(-EINVAL, f.Write(content.data(), content.size(), -128));
-  // But you can write anywhere else...
-  ASSERT_EQ(content.size(), static_cast<uint64_t>(f.Write(content.data(), content.size(), 0)));
-  ASSERT_EQ(content.size(), static_cast<uint64_t>(f.Write(content.data(), content.size(), 128)));
-  // ...though the file will remain empty.
-  ASSERT_EQ(0, f.GetLength());
-}
-
-}  // namespace unix_file
diff --git a/runtime/base/unix_file/random_access_file_test.h b/runtime/base/unix_file/random_access_file_test.h
index 0002433..e7ace4c 100644
--- a/runtime/base/unix_file/random_access_file_test.h
+++ b/runtime/base/unix_file/random_access_file_test.h
@@ -76,6 +76,8 @@
     ASSERT_EQ(content.size(), static_cast<uint64_t>(file->Write(content.data(), content.size(), 0)));
 
     TestReadContent(content, file.get());
+
+    CleanUp(file.get());
   }
 
   void TestReadContent(const std::string& content, RandomAccessFile* file) {
@@ -131,6 +133,8 @@
     ASSERT_EQ(new_length, file->GetLength());
     ASSERT_TRUE(ReadString(file.get(), &new_content));
     ASSERT_EQ('\0', new_content[new_length - 1]);
+
+    CleanUp(file.get());
   }
 
   void TestWrite() {
@@ -163,6 +167,11 @@
     ASSERT_EQ(file->GetLength(), new_length);
     ASSERT_TRUE(ReadString(file.get(), &new_content));
     ASSERT_EQ(std::string("hello\0hello", new_length), new_content);
+
+    CleanUp(file.get());
+  }
+
+  virtual void CleanUp(RandomAccessFile* file ATTRIBUTE_UNUSED) {
   }
 
  protected:
diff --git a/runtime/base/unix_file/random_access_file_utils_test.cc b/runtime/base/unix_file/random_access_file_utils_test.cc
deleted file mode 100644
index 6317922..0000000
--- a/runtime/base/unix_file/random_access_file_utils_test.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2009 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 "base/unix_file/random_access_file_utils.h"
-#include "base/unix_file/fd_file.h"
-#include "base/unix_file/string_file.h"
-#include "gtest/gtest.h"
-
-namespace unix_file {
-
-class RandomAccessFileUtilsTest : public testing::Test { };
-
-TEST_F(RandomAccessFileUtilsTest, CopyFile) {
-  StringFile src;
-  StringFile dst;
-
-  const std::string content("hello");
-  src.Assign(content);
-  ASSERT_EQ(src.ToStringPiece(), content);
-  ASSERT_EQ(dst.ToStringPiece(), "");
-
-  ASSERT_TRUE(CopyFile(src, &dst));
-  ASSERT_EQ(src.ToStringPiece(), dst.ToStringPiece());
-}
-
-TEST_F(RandomAccessFileUtilsTest, BadSrc) {
-  FdFile src(-1);
-  StringFile dst;
-  ASSERT_FALSE(CopyFile(src, &dst));
-}
-
-TEST_F(RandomAccessFileUtilsTest, BadDst) {
-  StringFile src;
-  FdFile dst(-1);
-
-  // We need some source content to trigger a write.
-  // Copying an empty file is a no-op.
-  src.Assign("hello");
-
-  ASSERT_FALSE(CopyFile(src, &dst));
-}
-
-}  // namespace unix_file
diff --git a/runtime/base/unix_file/string_file.cc b/runtime/base/unix_file/string_file.cc
deleted file mode 100644
index ff0d0fa..0000000
--- a/runtime/base/unix_file/string_file.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2009 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 "base/unix_file/string_file.h"
-#include <errno.h>
-#include <algorithm>
-#include "base/logging.h"
-
-namespace unix_file {
-
-StringFile::StringFile() {
-}
-
-StringFile::~StringFile() {
-}
-
-int StringFile::Close() {
-  return 0;
-}
-
-int StringFile::Flush() {
-  return 0;
-}
-
-int64_t StringFile::Read(char *buf, int64_t byte_count, int64_t offset) const {
-  CHECK(buf);
-  CHECK_GE(byte_count, 0);
-
-  if (offset < 0) {
-    return -EINVAL;
-  }
-
-  const int64_t available_bytes = std::min(byte_count, GetLength() - offset);
-  if (available_bytes < 0) {
-    return 0;  // Not an error, but nothing for us to do, either.
-  }
-  memcpy(buf, data_.data() + offset, available_bytes);
-  return available_bytes;
-}
-
-int StringFile::SetLength(int64_t new_length) {
-  if (new_length < 0) {
-    return -EINVAL;
-  }
-  data_.resize(new_length);
-  return 0;
-}
-
-int64_t StringFile::GetLength() const {
-  return data_.size();
-}
-
-int64_t StringFile::Write(const char *buf, int64_t byte_count, int64_t offset) {
-  CHECK(buf);
-  CHECK_GE(byte_count, 0);
-
-  if (offset < 0) {
-    return -EINVAL;
-  }
-
-  if (byte_count == 0) {
-    return 0;
-  }
-
-  // FUSE seems happy to allow writes past the end. (I'd guess it doesn't
-  // synthesize a write of zero bytes so that we're free to implement sparse
-  // files.) GNU as(1) seems to require such writes. Those files are small.
-  const int64_t bytes_past_end = offset - GetLength();
-  if (bytes_past_end > 0) {
-    data_.append(bytes_past_end, '\0');
-  }
-
-  data_.replace(offset, byte_count, buf, byte_count);
-  return byte_count;
-}
-
-void StringFile::Assign(const art::StringPiece &new_data) {
-  data_.assign(new_data.data(), new_data.size());
-}
-
-const art::StringPiece StringFile::ToStringPiece() const {
-  return data_;
-}
-
-}  // namespace unix_file
diff --git a/runtime/base/unix_file/string_file.h b/runtime/base/unix_file/string_file.h
deleted file mode 100644
index 26904f8..0000000
--- a/runtime/base/unix_file/string_file.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2009 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_UNIX_FILE_STRING_FILE_H_
-#define ART_RUNTIME_BASE_UNIX_FILE_STRING_FILE_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/stringpiece.h"
-#include "base/unix_file/random_access_file.h"
-
-namespace unix_file {
-
-// A RandomAccessFile implementation backed by a std::string. (That is, all data is
-// kept in memory.)
-//
-// Not thread safe.
-class StringFile : public RandomAccessFile {
- public:
-  StringFile();
-  virtual ~StringFile();
-
-  // RandomAccessFile API.
-  virtual int Close();
-  virtual int Flush();
-  virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const;
-  virtual int SetLength(int64_t new_length);
-  virtual int64_t GetLength() const;
-  virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset);
-
-  // Bonus API.
-  void Assign(const art::StringPiece& new_data);
-  const art::StringPiece ToStringPiece() const;
-
- private:
-  std::string data_;
-
-  DISALLOW_COPY_AND_ASSIGN(StringFile);
-};
-
-}  // namespace unix_file
-
-#endif  // ART_RUNTIME_BASE_UNIX_FILE_STRING_FILE_H_
diff --git a/runtime/base/unix_file/string_file_test.cc b/runtime/base/unix_file/string_file_test.cc
deleted file mode 100644
index 8821461..0000000
--- a/runtime/base/unix_file/string_file_test.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2009 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 "base/unix_file/string_file.h"
-#include "base/unix_file/random_access_file_test.h"
-#include "gtest/gtest.h"
-
-namespace unix_file {
-
-class StringFileTest : public RandomAccessFileTest {
- protected:
-  virtual RandomAccessFile* MakeTestFile() {
-    return new StringFile;
-  }
-};
-
-TEST_F(StringFileTest, Read) {
-  TestRead();
-}
-
-TEST_F(StringFileTest, SetLength) {
-  TestSetLength();
-}
-
-TEST_F(StringFileTest, Write) {
-  TestWrite();
-}
-
-}  // namespace unix_file
diff --git a/runtime/base/value_object.h b/runtime/base/value_object.h
new file mode 100644
index 0000000..8c752a9
--- /dev/null
+++ b/runtime/base/value_object.h
@@ -0,0 +1,31 @@
+/*
+ * 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_RUNTIME_BASE_VALUE_OBJECT_H_
+#define ART_RUNTIME_BASE_VALUE_OBJECT_H_
+
+#include "base/macros.h"
+
+namespace art {
+
+class ValueObject {
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_VALUE_OBJECT_H_
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index bfe44a2..e45d3a3 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
+#include "check_jni.h"
 
 #include <sys/mman.h>
 #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"
-#include "field_helper.h"
 #include "gc/space/space.h"
 #include "java_vm_ext.h"
+#include "jni_internal.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -511,7 +512,7 @@
     return true;
   }
 
-  bool CheckReferenceKind(IndirectRefKind expected_kind, JavaVMExt* vm, Thread* self, jobject obj) {
+  bool CheckReferenceKind(IndirectRefKind expected_kind, Thread* self, jobject obj) {
     IndirectRefKind found_kind;
     if (expected_kind == kLocal) {
       found_kind = GetIndirectRefKind(obj);
@@ -1128,7 +1129,7 @@
           *errorKind = "continuation";
           return utf8;
         }
-        // Fall through to take care of the final byte.
+        FALLTHROUGH_INTENDED;  // Fall-through to take care of the final byte.
       case 0x0c:
       case 0x0d:
         // Bit pattern 110x, so there is one additional byte.
@@ -2397,7 +2398,7 @@
       }
       if (sc.Check(soa, false, "L", &result)) {
         DCHECK_EQ(IsSameObject(env, obj, result.L), JNI_TRUE);
-        DCHECK(sc.CheckReferenceKind(kind, soa.Vm(), soa.Self(), result.L));
+        DCHECK(sc.CheckReferenceKind(kind, soa.Self(), result.L));
         return result.L;
       }
     }
@@ -2409,7 +2410,7 @@
     ScopedCheck sc(kFlag_ExcepOkay, function_name);
     JniValueType args[2] = {{.E = env}, {.L = obj}};
     sc.Check(soa, true, "EL", args);
-    if (sc.CheckReferenceKind(kind, soa.Vm(), soa.Self(), obj)) {
+    if (sc.CheckReferenceKind(kind, soa.Self(), obj)) {
       JniValueType result;
       switch (kind) {
         case kGlobal:
@@ -3115,7 +3116,7 @@
   static jarray NewPrimitiveArray(const char* function_name, JNIEnv* env, jsize length,
                                   Primitive::Type type) {
     ScopedObjectAccess soa(env);
-    ScopedCheck sc(kFlag_Default, __FUNCTION__);
+    ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[2] = {{.E = env}, {.z = length}};
     if (sc.Check(soa, true, "Ez", args)) {
       JniValueType result;
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 1a78d72..4fe3852 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;
     }
 
@@ -53,7 +53,7 @@
 
   void CheckReferences(int* registers, int number_of_references, uint32_t native_pc_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (GetMethod()->IsOptimized()) {
+    if (GetMethod()->IsOptimized(sizeof(void*))) {
       CheckOptimizedMethod(registers, number_of_references, native_pc_offset);
     } else {
       CheckQuickMethod(registers, number_of_references, native_pc_offset);
@@ -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;
       }
     }
@@ -94,7 +98,7 @@
   void CheckQuickMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::ArtMethod* m = GetMethod();
-    NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
+    NativePcOffsetToReferenceMap map(m->GetNativeGcMap(sizeof(void*)));
     const uint8_t* ref_bitmap = map.FindBitMap(native_pc_offset);
     CHECK(ref_bitmap);
     for (int i = 0; i < number_of_references; ++i) {
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 875efbb..5198769 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -58,9 +58,9 @@
 
 inline mirror::String* ClassLinker::ResolveString(uint32_t string_idx,
                                                   mirror::ArtMethod* referrer) {
-  mirror::String* resolved_string = referrer->GetDexCacheStrings()->Get(string_idx);
+  mirror::Class* declaring_class = referrer->GetDeclaringClass();
+  mirror::String* resolved_string = declaring_class->GetDexCacheStrings()->Get(string_idx);
   if (UNLIKELY(resolved_string == NULL)) {
-    mirror::Class* declaring_class = referrer->GetDeclaringClass();
     StackHandleScope<1> hs(Thread::Current());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
     const DexFile& dex_file = *dex_cache->GetDexFile();
@@ -105,8 +105,7 @@
 }
 
 inline mirror::ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx,
-                                                         mirror::ArtMethod* referrer,
-                                                         InvokeType type) {
+                                                         mirror::ArtMethod* referrer) {
   mirror::ArtMethod* resolved_method = referrer->GetDexCacheResolvedMethod(method_idx);
   if (resolved_method == nullptr || resolved_method->IsRuntimeMethod()) {
     return nullptr;
@@ -117,7 +116,7 @@
 inline mirror::ArtMethod* ClassLinker::ResolveMethod(Thread* self, uint32_t method_idx,
                                                      mirror::ArtMethod** referrer,
                                                      InvokeType type) {
-  mirror::ArtMethod* resolved_method = GetResolvedMethod(method_idx, *referrer, type);
+  mirror::ArtMethod* resolved_method = GetResolvedMethod(method_idx, *referrer);
   if (LIKELY(resolved_method != nullptr)) {
     return resolved_method;
   }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 6ed27bb..b0d55c3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -17,9 +17,11 @@
 #include "class_linker.h"
 
 #include <deque>
+#include <iostream>
 #include <memory>
 #include <queue>
 #include <string>
+#include <unistd.h>
 #include <utility>
 #include <vector>
 
@@ -32,6 +34,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"
@@ -41,7 +44,6 @@
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "leb128.h"
-#include "method_helper-inl.h"
 #include "oat.h"
 #include "oat_file.h"
 #include "object_lock.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,15 +144,7 @@
     self->ThrowNewWrappedException(throw_location, "Ljava/lang/ExceptionInInitializerError;",
                                    nullptr);
   }
-}
-
-static size_t Hash(const char* s) {
-  // This is the java.lang.String hashcode for convenience, not interoperability.
-  size_t hash = 0;
-  for (; *s != '\0'; ++s) {
-    hash = hash * 31 + *s;
-  }
-  return hash;
+  VlogClassInitializationFailure(klass);
 }
 
 // Gap between two fields in object layout.
@@ -160,7 +164,7 @@
 typedef std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator> FieldGaps;
 
 // Adds largest aligned gaps to queue of gaps.
-void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) {
+static void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) {
   DCHECK(gaps != nullptr);
 
   uint32_t current_offset = gap_start;
@@ -181,15 +185,13 @@
 }
 // Shuffle fields forward, making use of gaps whenever possible.
 template<int n>
-static void ShuffleForward(const size_t num_fields, size_t* current_field_idx,
+static void ShuffleForward(size_t* current_field_idx,
                            MemberOffset* field_offset,
-                           mirror::ObjectArray<mirror::ArtField>* fields,
                            std::deque<mirror::ArtField*>* grouped_and_sorted_fields,
                            FieldGaps* gaps)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(current_field_idx != nullptr);
   DCHECK(grouped_and_sorted_fields != nullptr);
-  DCHECK(fields != nullptr || (num_fields == 0 && grouped_and_sorted_fields->empty()));
   DCHECK(gaps != nullptr);
   DCHECK(field_offset != nullptr);
 
@@ -207,7 +209,6 @@
     }
     CHECK(type != Primitive::kPrimNot) << PrettyField(field);  // should be primitive types
     grouped_and_sorted_fields->pop_front();
-    fields->Set<false>(*current_field_idx, field);
     if (!gaps->empty() && gaps->top().size >= n) {
       FieldGap gap = gaps->top();
       gaps->pop();
@@ -225,44 +226,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),
@@ -275,23 +238,15 @@
       log_new_dex_caches_roots_(false),
       log_new_class_table_roots_(false),
       intern_table_(intern_table),
-      portable_resolution_trampoline_(nullptr),
       quick_resolution_trampoline_(nullptr),
-      portable_imt_conflict_trampoline_(nullptr),
       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));
+      quick_to_interpreter_bridge_trampoline_(nullptr),
+      image_pointer_size_(sizeof(void*)) {
   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) {
+void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path) {
   VLOG(startup) << "ClassLinker::Init";
   CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it.";
 
@@ -422,10 +377,9 @@
   Handle<mirror::Class> java_lang_reflect_ArtMethod(hs.NewHandle(
     AllocClass(self, java_lang_Class.Get(), mirror::ArtMethod::ClassSize())));
   CHECK(java_lang_reflect_ArtMethod.Get() != nullptr);
-  java_lang_reflect_ArtMethod->SetObjectSize(mirror::ArtMethod::InstanceSize());
+  java_lang_reflect_ArtMethod->SetObjectSize(mirror::ArtMethod::InstanceSize(sizeof(void*)));
   SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.Get());
   java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
-
   mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.Get());
 
   // Set up array classes for string, field, method
@@ -451,10 +405,10 @@
   // DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses
   // these roots.
   CHECK_NE(0U, boot_class_path.size());
-  for (size_t i = 0; i != boot_class_path.size(); ++i) {
-    const DexFile* dex_file = boot_class_path[i];
-    CHECK(dex_file != nullptr);
+  for (auto& dex_file : boot_class_path) {
+    CHECK(dex_file.get() != nullptr);
     AppendToBootClassPath(self, *dex_file);
+    opened_dex_files_.push_back(std::move(dex_file));
   }
 
   // now we can use FindSystemClass
@@ -467,16 +421,17 @@
   Runtime* runtime = Runtime::Current();
   runtime->SetResolutionMethod(runtime->CreateResolutionMethod());
   runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod());
+  runtime->SetImtUnimplementedMethod(runtime->CreateImtConflictMethod());
   runtime->SetDefaultImt(runtime->CreateDefaultImt(this));
 
   // 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 +515,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.
@@ -620,6 +575,23 @@
                FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
   mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
 
+  // Ensure void type is resolved in the core's dex cache so java.lang.Void is correctly
+  // initialized.
+  {
+    const DexFile& dex_file = java_lang_Object->GetDexFile();
+    const DexFile::StringId* void_string_id = dex_file.FindStringId("V");
+    CHECK(void_string_id != nullptr);
+    uint32_t void_string_index = dex_file.GetIndexForStringId(*void_string_id);
+    const DexFile::TypeId* void_type_id = dex_file.FindTypeId(void_string_index);
+    CHECK(void_type_id != nullptr);
+    uint16_t void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
+    // Now we resolve void type so the dex cache contains it. We use java.lang.Object class
+    // as referrer so the used dex cache is core's one.
+    mirror::Class* resolved_type = ResolveType(dex_file, void_type_idx, java_lang_Object.Get());
+    CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid));
+    self->AssertNoPendingException();
+  }
+
   FinishInit(self);
 
   VLOG(startup) << "ClassLinker::InitFromCompiler exiting";
@@ -749,7 +721,14 @@
     argv.push_back(compiler_options[i].c_str());
   }
 
-  return Exec(argv, error_msg);
+  if (!Exec(argv, error_msg)) {
+    // Manually delete the file. Ensures there is no garbage left over if the process unexpectedly
+    // died. Ignore unlink failure, propagate the original error.
+    TEMP_FAILURE_RETRY(unlink(oat_cache_filename));
+    return false;
+  }
+
+  return true;
 }
 
 const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) {
@@ -816,7 +795,7 @@
                                          const uint32_t* dex_location_checksum,
                                          bool generated,
                                          std::vector<std::string>* error_msgs,
-                                         std::vector<const DexFile*>* dex_files) {
+                                         std::vector<std::unique_ptr<const DexFile>>* dex_files) {
   if (oat_file == nullptr) {
     return false;
   }
@@ -848,7 +827,6 @@
 
     if (oat_dex_file == nullptr) {
       if (i == 0 && generated) {
-        std::string error_msg;
         error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out "
                                  " file'%s'", dex_location, next_location_checksum,
                                  oat_file->GetLocation().c_str());
@@ -864,12 +842,12 @@
     }
 
     if (success) {
-      const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
-      if (dex_file == nullptr) {
+      std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
+      if (dex_file.get() == nullptr) {
         success = false;
         error_msgs->push_back(error_msg);
       } else {
-        dex_files->push_back(dex_file);
+        dex_files->push_back(std::move(dex_file));
       }
     }
 
@@ -887,14 +865,7 @@
   if (success) {
     return true;
   } else {
-    // Free all the dex files we have loaded.
-    auto it = dex_files->begin() + old_size;
-    auto it_end = dex_files->end();
-    for (; it != it_end; it++) {
-      delete *it;
-    }
-    dex_files->erase(dex_files->begin() + old_size, it_end);
-
+    dex_files->erase(dex_files->begin() + old_size, dex_files->end());
     return false;
   }
 }
@@ -905,7 +876,7 @@
 // multidex ahead of time.
 bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
                                       std::vector<std::string>* error_msgs,
-                                      std::vector<const DexFile*>* dex_files) {
+                                      std::vector<std::unique_ptr<const DexFile>>* dex_files) {
   // 1) Check whether we have an open oat file.
   // This requires a dex checksum, use the "primary" one.
   uint32_t dex_location_checksum;
@@ -1059,7 +1030,7 @@
                                                                uint32_t dex_location_checksum,
                                                                const char* oat_location,
                                                                std::string* error_msg) {
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr,
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, nullptr,
                                             !Runtime::Current()->IsCompiler(),
                                             error_msg));
   if (oat_file.get() == nullptr) {
@@ -1131,7 +1102,7 @@
     error_msgs->push_back(error_msg);
     return nullptr;
   }
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr,
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr, nullptr,
                                             !Runtime::Current()->IsCompiler(),
                                             &error_msg));
   if (oat_file.get() == nullptr) {
@@ -1192,9 +1163,13 @@
     image_patch_delta = image_header->GetPatchDelta();
   }
   const OatHeader& oat_header = oat_file->GetOatHeader();
-  bool ret = ((oat_header.GetImageFileLocationOatChecksum() == image_oat_checksum)
-              && (oat_header.GetImagePatchDelta() == image_patch_delta)
-              && (oat_header.GetImageFileLocationOatDataBegin() == image_oat_data_begin));
+  bool ret = (oat_header.GetImageFileLocationOatChecksum() == image_oat_checksum);
+
+  // If the oat file is PIC, it doesn't care if/how image was relocated. Ignore these checks.
+  if (!oat_file->IsPic()) {
+    ret = ret && (oat_header.GetImagePatchDelta() == image_patch_delta)
+              && (oat_header.GetImageFileLocationOatDataBegin() == image_oat_data_begin);
+  }
   if (!ret) {
     *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d, %d) with (0x%x, %" PRIdPTR ", %d)",
                               oat_file->GetLocation().c_str(),
@@ -1220,11 +1195,11 @@
   if (oat_dex_file == nullptr) {
     *error_msg = StringPrintf("oat file '%s' does not contain contents for '%s' with checksum 0x%x",
                               oat_file->GetLocation().c_str(), dex_location, dex_location_checksum);
-    for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
+    for (const OatFile::OatDexFile* oat_dex_file_in : oat_file->GetOatDexFiles()) {
       *error_msg  += StringPrintf("\noat file '%s' contains contents for '%s' with checksum 0x%x",
                                   oat_file->GetLocation().c_str(),
-                                  oat_dex_file->GetDexFileLocation().c_str(),
-                                  oat_dex_file->GetDexFileLocationChecksum());
+                                  oat_dex_file_in->GetDexFileLocation().c_str(),
+                                  oat_dex_file_in->GetDexFileLocationChecksum());
     }
     return false;
   }
@@ -1251,15 +1226,15 @@
                                 error_msg->c_str());
       return false;
     }
-    dex_file.reset(oat_dex_file->OpenDexFile(error_msg));
+    dex_file = oat_dex_file->OpenDexFile(error_msg);
   } else {
     bool verified = VerifyOatAndDexFileChecksums(oat_file, dex_location, *dex_location_checksum,
                                                  kRuntimeISA, error_msg);
     if (!verified) {
       return false;
     }
-    dex_file.reset(oat_file->GetOatDexFile(dex_location,
-                                           dex_location_checksum)->OpenDexFile(error_msg));
+    dex_file = oat_file->GetOatDexFile(dex_location,
+                                       dex_location_checksum)->OpenDexFile(error_msg);
   }
   return dex_file.get() != nullptr;
 }
@@ -1376,11 +1351,12 @@
   bool odex_checksum_verified = false;
   bool have_system_odex = false;
   {
-    // There is a high probability that these both these oat files map similar/the same address
+    // There is a high probability that both these oat files map similar/the same address
     // spaces so we must scope them like this so they each gets its turn.
     std::unique_ptr<OatFile> odex_oat_file(OatFile::Open(odex_filename, odex_filename, nullptr,
+                                                         nullptr,
                                                          executable, &odex_error_msg));
-    if (odex_oat_file.get() != nullptr && CheckOatFile(odex_oat_file.get(), isa,
+    if (odex_oat_file.get() != nullptr && CheckOatFile(runtime, odex_oat_file.get(), isa,
                                                        &odex_checksum_verified,
                                                        &odex_error_msg)) {
       return odex_oat_file.release();
@@ -1401,8 +1377,9 @@
   bool cache_checksum_verified = false;
   if (have_dalvik_cache) {
     std::unique_ptr<OatFile> cache_oat_file(OatFile::Open(cache_filename, cache_filename, nullptr,
+                                                          nullptr,
                                                           executable, &cache_error_msg));
-    if (cache_oat_file.get() != nullptr && CheckOatFile(cache_oat_file.get(), isa,
+    if (cache_oat_file.get() != nullptr && CheckOatFile(runtime, cache_oat_file.get(), isa,
                                                         &cache_checksum_verified,
                                                         &cache_error_msg)) {
       return cache_oat_file.release();
@@ -1477,7 +1454,7 @@
                                                   InstructionSet isa,
                                                   std::string* error_msg) {
   // We open it non-executable
-  std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, nullptr, false, error_msg));
+  std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, nullptr, nullptr, false, error_msg));
   if (output.get() == nullptr) {
     return nullptr;
   }
@@ -1496,13 +1473,15 @@
                                                 const std::string& image_location,
                                                 InstructionSet isa,
                                                 std::string* error_msg) {
-  if (!Runtime::Current()->GetHeap()->HasImageSpace()) {
+  Runtime* runtime = Runtime::Current();
+  DCHECK(runtime != nullptr);
+  if (!runtime->GetHeap()->HasImageSpace()) {
     // We don't have an image space so there is no point in trying to patchoat.
     LOG(WARNING) << "Patching of oat file '" << input_oat << "' not attempted because we are "
                  << "running without an image. Attempting to use oat file for interpretation.";
     return GetInterpretedOnlyOat(input_oat, isa, error_msg);
   }
-  if (!Runtime::Current()->IsDex2OatEnabled()) {
+  if (!runtime->IsDex2OatEnabled()) {
     // We don't have dex2oat so we can assume we don't have patchoat either. We should just use the
     // input_oat but make sure we only do interpretation on it's dex files.
     LOG(WARNING) << "Patching of oat file '" << input_oat << "' not attempted due to dex2oat being "
@@ -1510,7 +1489,7 @@
     return GetInterpretedOnlyOat(input_oat, isa, error_msg);
   }
   Locks::mutator_lock_->AssertNotHeld(Thread::Current());  // Avoid starving GC.
-  std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
+  std::string patchoat(runtime->GetPatchoatExecutable());
 
   std::string isa_arg("--instruction-set=");
   isa_arg += GetInstructionSetString(isa);
@@ -1532,10 +1511,11 @@
   LOG(INFO) << "Relocate Oat File: " << command_line;
   bool success = Exec(argv, error_msg);
   if (success) {
-    std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, nullptr,
-                                                  !Runtime::Current()->IsCompiler(), error_msg));
+    std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, nullptr, nullptr,
+                                                  !runtime->IsCompiler(), error_msg));
     bool checksum_verified = false;
-    if (output.get() != nullptr && CheckOatFile(output.get(), isa, &checksum_verified, error_msg)) {
+    if (output.get() != nullptr && CheckOatFile(runtime, output.get(), isa, &checksum_verified,
+                                                error_msg)) {
       return output.release();
     } else if (output.get() != nullptr) {
       *error_msg = StringPrintf("Patching of oat file '%s' succeeded "
@@ -1546,7 +1526,7 @@
                                 "but was unable to open output file '%s': %s",
                                 input_oat.c_str(), output_oat.c_str(), error_msg->c_str());
     }
-  } else if (!Runtime::Current()->IsCompiler()) {
+  } else if (!runtime->IsCompiler()) {
     // patchoat failed which means we probably don't have enough room to place the output oat file,
     // instead of failing we should just run the interpreter from the dex files in the input oat.
     LOG(WARNING) << "Patching of oat file '" << input_oat << "' failed. Attempting to use oat file "
@@ -1560,27 +1540,9 @@
   return nullptr;
 }
 
-int32_t ClassLinker::GetRequiredDelta(const OatFile* oat_file, InstructionSet isa) {
-  Runtime* runtime = Runtime::Current();
-  int32_t real_patch_delta;
-  const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
-  CHECK(image_space != nullptr);
-  if (isa == Runtime::Current()->GetInstructionSet()) {
-    const ImageHeader& image_header = image_space->GetImageHeader();
-    real_patch_delta = image_header.GetPatchDelta();
-  } else {
-    std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeaderOrDie(
-        image_space->GetImageLocation().c_str(), isa));
-    real_patch_delta = image_header->GetPatchDelta();
-  }
-  const OatHeader& oat_header = oat_file->GetOatHeader();
-  return real_patch_delta - oat_header.GetImagePatchDelta();
-}
-
-bool ClassLinker::CheckOatFile(const OatFile* oat_file, InstructionSet isa,
+bool ClassLinker::CheckOatFile(const Runtime* runtime, const OatFile* oat_file, InstructionSet isa,
                                bool* checksum_verified,
                                std::string* error_msg) {
-  Runtime* runtime = Runtime::Current();
   const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
   if (image_space == nullptr) {
     *error_msg = "No image space present";
@@ -1612,19 +1574,30 @@
                   real_image_checksum, oat_image_checksum);
   }
 
-  void* oat_image_oat_offset =
-      reinterpret_cast<void*>(oat_header.GetImageFileLocationOatDataBegin());
-  bool offset_verified = oat_image_oat_offset == real_image_oat_offset;
-  if (!offset_verified) {
-    StringAppendF(&compound_msg, " Oat Image oat offset incorrect (expected 0x%p, received 0x%p)",
-                  real_image_oat_offset, oat_image_oat_offset);
-  }
+  bool offset_verified;
+  bool patch_delta_verified;
 
-  int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
-  bool patch_delta_verified = oat_patch_delta == real_patch_delta;
-  if (!patch_delta_verified) {
-    StringAppendF(&compound_msg, " Oat image patch delta incorrect (expected 0x%x, received 0x%x)",
-                  real_patch_delta, oat_patch_delta);
+  if (!oat_file->IsPic()) {
+    // If an oat file is not PIC, we need to check that the image is at the expected location and
+    // patched in the same way.
+    void* oat_image_oat_offset =
+        reinterpret_cast<void*>(oat_header.GetImageFileLocationOatDataBegin());
+    offset_verified = oat_image_oat_offset == real_image_oat_offset;
+    if (!offset_verified) {
+      StringAppendF(&compound_msg, " Oat Image oat offset incorrect (expected 0x%p, received 0x%p)",
+                    real_image_oat_offset, oat_image_oat_offset);
+    }
+
+    int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
+    patch_delta_verified = oat_patch_delta == real_patch_delta;
+    if (!patch_delta_verified) {
+      StringAppendF(&compound_msg, " Oat image patch delta incorrect (expected 0x%x, "
+                    "received 0x%x)", real_patch_delta, oat_patch_delta);
+    }
+  } else {
+    // If an oat file is PIC, we ignore offset and patching delta.
+    offset_verified = true;
+    patch_delta_verified = true;
   }
 
   bool ret = (*checksum_verified && offset_verified && patch_delta_verified);
@@ -1641,24 +1614,23 @@
     return oat_file;
   }
 
-  return OatFile::Open(oat_location, oat_location, nullptr, !Runtime::Current()->IsCompiler(),
+  return OatFile::Open(oat_location, oat_location, nullptr, nullptr, !Runtime::Current()->IsCompiler(),
                        error_msg);
 }
 
-static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void ClassLinker::InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg) {
   ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
-
   DCHECK(obj != nullptr);
   DCHECK(class_linker != nullptr);
+  size_t pointer_size = class_linker->image_pointer_size_;
 
   if (obj->IsArtMethod()) {
     mirror::ArtMethod* method = obj->AsArtMethod();
     if (!method->IsNative()) {
-      method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+      method->SetEntryPointFromInterpreterPtrSize(artInterpreterToInterpreterBridge, pointer_size);
       if (method != Runtime::Current()->GetResolutionMethod()) {
-        method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
-        method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
+        method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
+                                                          pointer_size);
       }
     }
   }
@@ -1679,9 +1651,7 @@
   const char* image_file_location = oat_file.GetOatHeader().
       GetStoreValueByKey(OatHeader::kImageLocationKey);
   CHECK(image_file_location == nullptr || *image_file_location == 0);
-  portable_resolution_trampoline_ = oat_file.GetOatHeader().GetPortableResolutionTrampoline();
   quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline();
-  portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline();
   quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
   quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline();
   quick_to_interpreter_bridge_trampoline_ = oat_file.GetOatHeader().GetQuickToInterpreterBridge();
@@ -1702,32 +1672,48 @@
   CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
            static_cast<uint32_t>(dex_caches->GetLength()));
   for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
-    StackHandleScope<1> hs(self);
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_caches->Get(i)));
+    StackHandleScope<1> hs2(self);
+    Handle<mirror::DexCache> dex_cache(hs2.NewHandle(dex_caches->Get(i)));
     const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
     const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(),
                                                                      nullptr);
     CHECK(oat_dex_file != nullptr) << oat_file.GetLocation() << " " << dex_file_location;
     std::string error_msg;
-    const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
-    if (dex_file == nullptr) {
+    std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
+    if (dex_file.get() == nullptr) {
       LOG(FATAL) << "Failed to open dex file " << dex_file_location
                  << " from within oat file " << oat_file.GetLocation()
                  << " error '" << error_msg << "'";
+      UNREACHABLE();
     }
 
     CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
 
-    AppendToBootClassPath(*dex_file, dex_cache);
+    AppendToBootClassPath(*dex_file.get(), dex_cache);
+    opened_dex_files_.push_back(std::move(dex_file));
   }
 
   // Set classes on AbstractMethod early so that IsMethod tests can be performed during the live
   // bitmap walk.
   mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod));
+  size_t art_method_object_size = mirror::ArtMethod::GetJavaLangReflectArtMethod()->GetObjectSize();
+  if (!Runtime::Current()->IsCompiler()) {
+    // Compiler supports having an image with a different pointer size than the runtime. This
+    // happens on the host for compile 32 bit tests since we use a 64 bit libart compiler. We may
+    // also use 32 bit dex2oat on a system with 64 bit apps.
+    CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(sizeof(void*)))
+        << sizeof(void*);
+  }
+  if (art_method_object_size == mirror::ArtMethod::InstanceSize(4)) {
+    image_pointer_size_ = 4;
+  } else {
+    CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(8));
+    image_pointer_size_ = 8;
+  }
 
   // Set entry point to interpreter if in InterpretOnly mode.
-  if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
-    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+  Runtime* runtime = Runtime::Current();
+  if (!runtime->IsCompiler() && runtime->GetInstrumentation()->InterpretOnly()) {
     heap->VisitObjects(InitFromImageInterpretOnlyCallback, this);
   }
 
@@ -1737,7 +1723,7 @@
 
   // reinit array_iftable_ from any array class instance, they should be ==
   array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable());
-  DCHECK(array_iftable_.Read() == GetClassRoot(kBooleanArrayClass)->GetIfTable());
+  DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable());
   // String class root was set above
   mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
   mirror::ArtField::SetClass(GetClassRoot(kJavaLangReflectArtField));
@@ -1760,25 +1746,24 @@
 void ClassLinker::VisitClassRoots(RootCallback* callback, void* arg, VisitRootFlags flags) {
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   if ((flags & kVisitRootFlagAllRoots) != 0) {
-    for (std::pair<const size_t, GcRoot<mirror::Class> >& it : class_table_) {
-      it.second.VisitRoot(callback, arg, 0, kRootStickyClass);
+    for (GcRoot<mirror::Class>& root : class_table_) {
+      root.VisitRoot(callback, arg, RootInfo(kRootStickyClass));
+    }
+    for (GcRoot<mirror::Class>& root : pre_zygote_class_table_) {
+      root.VisitRoot(callback, arg, RootInfo(kRootStickyClass));
     }
   } else if ((flags & kVisitRootFlagNewRoots) != 0) {
-    for (auto& pair : new_class_roots_) {
-      mirror::Class* old_ref = pair.second.Read<kWithoutReadBarrier>();
-      pair.second.VisitRoot(callback, arg, 0, kRootStickyClass);
-      mirror::Class* new_ref = pair.second.Read<kWithoutReadBarrier>();
+    for (auto& root : new_class_roots_) {
+      mirror::Class* old_ref = root.Read<kWithoutReadBarrier>();
+      root.VisitRoot(callback, arg, RootInfo(kRootStickyClass));
+      mirror::Class* new_ref = root.Read<kWithoutReadBarrier>();
       if (UNLIKELY(new_ref != old_ref)) {
         // Uh ohes, GC moved a root in the log. Need to search the class_table and update the
         // corresponding object. This is slow, but luckily for us, this may only happen with a
         // concurrent moving GC.
-        for (auto it = class_table_.lower_bound(pair.first), end = class_table_.end();
-            it != end && it->first == pair.first; ++it) {
-          // If the class stored matches the old class, update it to the new value.
-          if (old_ref == it->second.Read<kWithoutReadBarrier>()) {
-            it->second = GcRoot<mirror::Class>(new_ref);
-          }
-        }
+        auto it = class_table_.Find(GcRoot<mirror::Class>(old_ref));
+        DCHECK(it != class_table_.end());
+        *it = GcRoot<mirror::Class>(new_ref);
       }
     }
   }
@@ -1798,17 +1783,17 @@
 // reinit references to when reinitializing a ClassLinker from a
 // mapped image.
 void ClassLinker::VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags) {
-  class_roots_.VisitRoot(callback, arg, 0, kRootVMInternal);
+  class_roots_.VisitRoot(callback, arg, RootInfo(kRootVMInternal));
   Thread* self = Thread::Current();
   {
     ReaderMutexLock mu(self, dex_lock_);
     if ((flags & kVisitRootFlagAllRoots) != 0) {
       for (GcRoot<mirror::DexCache>& dex_cache : dex_caches_) {
-        dex_cache.VisitRoot(callback, arg, 0, kRootVMInternal);
+        dex_cache.VisitRoot(callback, arg, RootInfo(kRootVMInternal));
       }
     } else if ((flags & kVisitRootFlagNewRoots) != 0) {
       for (size_t index : new_dex_cache_roots_) {
-        dex_caches_[index].VisitRoot(callback, arg, 0, kRootVMInternal);
+        dex_caches_[index].VisitRoot(callback, arg, RootInfo(kRootVMInternal));
       }
     }
     if ((flags & kVisitRootFlagClearRootLog) != 0) {
@@ -1821,12 +1806,10 @@
     }
   }
   VisitClassRoots(callback, arg, flags);
-  array_iftable_.VisitRoot(callback, arg, 0, kRootVMInternal);
+  array_iftable_.VisitRoot(callback, arg, RootInfo(kRootVMInternal));
   DCHECK(!array_iftable_.IsNull());
   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
-    if (!find_array_class_cache_[i].IsNull()) {
-      find_array_class_cache_[i].VisitRoot(callback, arg, 0, kRootVMInternal);
-    }
+    find_array_class_cache_[i].VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
   }
 }
 
@@ -1836,9 +1819,13 @@
   }
   // TODO: why isn't this a ReaderMutexLock?
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  for (std::pair<const size_t, GcRoot<mirror::Class> >& it : class_table_) {
-    mirror::Class* c = it.second.Read();
-    if (!visitor(c, arg)) {
+  for (GcRoot<mirror::Class>& root : class_table_) {
+    if (!visitor(root.Read(), arg)) {
+      return;
+    }
+  }
+  for (GcRoot<mirror::Class>& root : pre_zygote_class_table_) {
+    if (!visitor(root.Read(), arg)) {
       return;
     }
   }
@@ -1894,7 +1881,7 @@
       size_t class_table_size;
       {
         ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
-        class_table_size = class_table_.size();
+        class_table_size = class_table_.Size() + pre_zygote_class_table_.Size();
       }
       mirror::Class* class_type = mirror::Class::GetJavaLangClass();
       mirror::Class* array_of_class = FindArrayClass(self, &class_type);
@@ -1933,7 +1920,6 @@
   mirror::ShortArray::ResetArrayClass();
   mirror::Throwable::ResetClass();
   mirror::StackTraceElement::ResetClass();
-  STLDeleteElements(&boot_class_path_);
   STLDeleteElements(&oat_files_);
 }
 
@@ -2037,7 +2023,8 @@
     }
     CHECK(h_class->IsRetired());
     // Get the updated class from class table.
-    klass = LookupClass(self, descriptor, h_class.Get()->GetClassLoader());
+    klass = LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor),
+                        h_class.Get()->GetClassLoader());
   }
 
   // Wait for the class if it has not already been linked.
@@ -2071,44 +2058,47 @@
 
 // Search a collection of DexFiles for a descriptor
 ClassPathEntry FindInClassPath(const char* descriptor,
-                               const std::vector<const DexFile*>& class_path) {
-  for (size_t i = 0; i != class_path.size(); ++i) {
-    const DexFile* dex_file = class_path[i];
-    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+                               size_t hash, const std::vector<const DexFile*>& class_path) {
+  for (const DexFile* dex_file : class_path) {
+    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor, hash);
     if (dex_class_def != nullptr) {
       return ClassPathEntry(dex_file, dex_class_def);
     }
   }
-  // TODO: remove reinterpret_cast when issue with -std=gnu++0x host issue resolved
-  return ClassPathEntry(static_cast<const DexFile*>(nullptr),
-                        static_cast<const DexFile::ClassDef*>(nullptr));
+  return ClassPathEntry(nullptr, nullptr);
 }
 
 mirror::Class* ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                                        Thread* self, const char* descriptor,
+                                                       size_t hash,
                                                        Handle<mirror::ClassLoader> class_loader) {
+  // Can we special case for a well understood PathClassLoader with the BootClassLoader as parent?
   if (class_loader->GetClass() !=
       soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) ||
       class_loader->GetParent()->GetClass() !=
           soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)) {
     return nullptr;
   }
-  ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
+  ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
   // Check if this would be found in the parent boot class loader.
   if (pair.second != nullptr) {
-    mirror::Class* klass = LookupClass(self, descriptor, nullptr);
+    mirror::Class* klass = LookupClass(self, descriptor, hash, nullptr);
     if (klass != nullptr) {
-      return EnsureResolved(self, descriptor, klass);
+      // May return null if resolution on another thread fails.
+      klass = EnsureResolved(self, descriptor, klass);
+    } else {
+      // May OOME.
+      klass = DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
+                          *pair.second);
     }
-    klass = DefineClass(self, descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
-                        *pair.second);
-    if (klass != nullptr) {
-      return klass;
+    if (klass == nullptr) {
+      CHECK(self->IsExceptionPending()) << descriptor;
+      self->ClearException();
     }
-    CHECK(self->IsExceptionPending()) << descriptor;
-    self->ClearException();
+    return klass;
   } else {
-    // RegisterDexFile may allocate dex caches (and cause thread suspension).
+    // Handle as if this is the child PathClassLoader.
+    // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
     StackHandleScope<3> hs(self);
     // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
     // We need to get the DexPathList and loop through it.
@@ -2147,12 +2137,12 @@
               LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
               break;
             }
-            for (const DexFile* dex_file : *dex_files) {
-              const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+            for (const DexFile* cp_dex_file : *dex_files) {
+              const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash);
               if (dex_class_def != nullptr) {
-                RegisterDexFile(*dex_file);
-                mirror::Class* klass =
-                    DefineClass(self, descriptor, class_loader, *dex_file, *dex_class_def);
+                RegisterDexFile(*cp_dex_file);
+                mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader,
+                                                   *cp_dex_file, *dex_class_def);
                 if (klass == nullptr) {
                   CHECK(self->IsExceptionPending()) << descriptor;
                   self->ClearException();
@@ -2165,8 +2155,9 @@
         }
       }
     }
+    self->AssertNoPendingException();
+    return nullptr;
   }
-  return nullptr;
 }
 
 mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
@@ -2179,19 +2170,20 @@
     // for primitive classes that aren't backed by dex files.
     return FindPrimitiveClass(descriptor[0]);
   }
+  const size_t hash = ComputeModifiedUtf8Hash(descriptor);
   // Find the class in the loaded classes table.
-  mirror::Class* klass = LookupClass(self, descriptor, class_loader.Get());
+  mirror::Class* klass = LookupClass(self, descriptor, hash, class_loader.Get());
   if (klass != nullptr) {
     return EnsureResolved(self, descriptor, klass);
   }
   // Class is not yet loaded.
   if (descriptor[0] == '[') {
-    return CreateArrayClass(self, descriptor, class_loader);
+    return CreateArrayClass(self, descriptor, hash, class_loader);
   } else if (class_loader.Get() == nullptr) {
     // The boot class loader, search the boot class path.
-    ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
+    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
     if (pair.second != nullptr) {
-      return DefineClass(self, descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+      return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
                          *pair.second);
     } else {
       // The boot class loader is searched ahead of the application class loader, failures are
@@ -2204,16 +2196,16 @@
   } else if (Runtime::Current()->UseCompileTimeClassPath()) {
     // First try with the bootstrap class loader.
     if (class_loader.Get() != nullptr) {
-      klass = LookupClass(self, descriptor, nullptr);
+      klass = LookupClass(self, descriptor, hash, nullptr);
       if (klass != nullptr) {
         return EnsureResolved(self, descriptor, klass);
       }
     }
     // If the lookup failed search the boot class path. We don't perform a recursive call to avoid
     // a NoClassDefFoundError being allocated.
-    ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
+    ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
     if (pair.second != nullptr) {
-      return DefineClass(self, descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+      return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
                          *pair.second);
     }
     // Next try the compile time class path.
@@ -2224,9 +2216,9 @@
                                             soa.AddLocalReference<jobject>(class_loader.Get()));
       class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get());
     }
-    pair = FindInClassPath(descriptor, *class_path);
+    pair = FindInClassPath(descriptor, hash, *class_path);
     if (pair.second != nullptr) {
-      return DefineClass(self, descriptor, class_loader, *pair.first, *pair.second);
+      return DefineClass(self, descriptor, hash, class_loader, *pair.first, *pair.second);
     } else {
       // Use the pre-allocated NCDFE at compile time to avoid wasting time constructing exceptions.
       mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
@@ -2235,9 +2227,10 @@
     }
   } else {
     ScopedObjectAccessUnchecked soa(self);
-    mirror::Class* klass = FindClassInPathClassLoader(soa, self, descriptor, class_loader);
-    if (klass != nullptr) {
-      return klass;
+    mirror::Class* cp_klass = FindClassInPathClassLoader(soa, self, descriptor, hash,
+                                                         class_loader);
+    if (cp_klass != nullptr) {
+      return cp_klass;
     }
     ScopedLocalRef<jobject> class_loader_object(soa.Env(),
                                                 soa.AddLocalReference<jobject>(class_loader.Get()));
@@ -2272,13 +2265,12 @@
   UNREACHABLE();
 }
 
-mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor,
+mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash,
                                         Handle<mirror::ClassLoader> class_loader,
                                         const DexFile& dex_file,
                                         const DexFile::ClassDef& dex_class_def) {
   StackHandleScope<3> hs(self);
   auto klass = hs.NewHandle<mirror::Class>(nullptr);
-  bool should_allocate = false;
 
   // Load the class from the dex file.
   if (UNLIKELY(!init_done_)) {
@@ -2297,14 +2289,10 @@
       klass.Assign(GetClassRoot(kJavaLangReflectArtField));
     } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
       klass.Assign(GetClassRoot(kJavaLangReflectArtMethod));
-    } else {
-      should_allocate = true;
     }
-  } else {
-    should_allocate = true;
   }
 
-  if (should_allocate) {
+  if (klass.Get() == nullptr) {
     // Allocate a class with the status of not ready.
     // Interface object should get the right size here. Regular class will
     // figure out the right size later and be replaced with one of the right
@@ -2329,7 +2317,7 @@
   klass->SetClinitThreadId(self->GetTid());
 
   // Add the newly loaded class to the loaded classes table.
-  mirror::Class* existing = InsertClass(descriptor, klass.Get(), Hash(descriptor));
+  mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash);
   if (existing != nullptr) {
     // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
     // this thread to block.
@@ -2365,6 +2353,18 @@
 
   Handle<mirror::Class> new_class_h(hs.NewHandle(new_class));
 
+  // Instrumentation may have updated entrypoints for all methods of all
+  // classes. However it could not update methods of this class while we
+  // were loading it. Now the class is resolved, we can update entrypoints
+  // as required by instrumentation.
+  if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {
+    // We must be in the kRunnable state to prevent instrumentation from
+    // suspending all threads to update entrypoints while we are doing it
+    // for this class.
+    DCHECK_EQ(self->GetState(), kRunnable);
+    Runtime::Current()->GetInstrumentation()->InstallStubsForClass(new_class_h.Get());
+  }
+
   /*
    * We send CLASS_PREPARE events to the debugger from here.  The
    * definition of "preparation" is creating the static fields for a
@@ -2383,7 +2383,7 @@
 
 uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
                                                        const DexFile::ClassDef& dex_class_def) {
-  const byte* class_data = dex_file.GetClassData(dex_class_def);
+  const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
   size_t num_ref = 0;
   size_t num_8 = 0;
   size_t num_16 = 0;
@@ -2417,6 +2417,7 @@
           break;
         default:
           LOG(FATAL) << "Unknown descriptor: " << c;
+          UNREACHABLE();
       }
     }
   }
@@ -2438,7 +2439,7 @@
 static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx,
                                                  uint32_t method_idx) {
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
-  const byte* class_data = dex_file.GetClassData(class_def);
+  const uint8_t* class_data = dex_file.GetClassData(class_def);
   CHECK(class_data != nullptr);
   ClassDataItemIterator it(dex_file, class_data);
   // Skip fields
@@ -2466,7 +2467,7 @@
   }
   DCHECK(!it.HasNext());
   LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation();
-  return 0;
+  UNREACHABLE();
 }
 
 const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, bool* found) {
@@ -2482,17 +2483,18 @@
     // by search for its position in the declared virtual methods.
     oat_method_index = declaring_class->NumDirectMethods();
     size_t end = declaring_class->NumVirtualMethods();
-    bool found = false;
+    bool found_virtual = false;
     for (size_t i = 0; i < end; i++) {
       // Check method index instead of identity in case of duplicate method definitions.
       if (method->GetDexMethodIndex() ==
           declaring_class->GetVirtualMethod(i)->GetDexMethodIndex()) {
-        found = true;
+        found_virtual = true;
         break;
       }
       oat_method_index++;
     }
-    CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method);
+    CHECK(found_virtual) << "Didn't find oat method index for virtual method: "
+                         << PrettyMethod(method);
   }
   DCHECK_EQ(oat_method_index,
             GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(),
@@ -2501,10 +2503,9 @@
   OatFile::OatClass oat_class = FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
                                              declaring_class->GetDexClassDefIndex(),
                                              found);
-  if (!found) {
+  if (!(*found)) {
     return OatFile::OatMethod::Invalid();
   }
-  *found = true;
   return oat_class.GetOatMethod(oat_method_index);
 }
 
@@ -2524,10 +2525,7 @@
   if (result == nullptr) {
     if (method->IsNative()) {
       // No code and native? Use generic trampoline.
-      result = GetQuickGenericJniTrampoline();
-    } else if (method->IsPortableCompiled()) {
-      // No code? Do we expect portable code?
-      result = GetQuickToPortableBridge();
+      result = GetQuickGenericJniStub();
     } else {
       // No code? You must mean to go into the interpreter.
       result = GetQuickToInterpreterBridge();
@@ -2536,36 +2534,6 @@
   return result;
 }
 
-const void* ClassLinker::GetPortableOatCodeFor(mirror::ArtMethod* method,
-                                               bool* have_portable_code) {
-  CHECK(!method->IsAbstract()) << PrettyMethod(method);
-  *have_portable_code = false;
-  if (method->IsProxyMethod()) {
-    return GetPortableProxyInvokeHandler();
-  }
-  bool found;
-  OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
-  const void* result = nullptr;
-  const void* quick_code = nullptr;
-  if (found) {
-    result = oat_method.GetPortableCode();
-    quick_code = oat_method.GetQuickCode();
-  }
-
-  if (result == nullptr) {
-    if (quick_code == nullptr) {
-      // No code? You must mean to go into the interpreter.
-      result = GetPortableToInterpreterBridge();
-    } else {
-      // No code? But there's quick code, so use a bridge.
-      result = GetPortableToQuickBridge();
-    }
-  } else {
-    *have_portable_code = true;
-  }
-  return result;
-}
-
 const void* ClassLinker::GetOatMethodQuickCodeFor(mirror::ArtMethod* method) {
   if (method->IsNative() || method->IsAbstract() || method->IsProxyMethod()) {
     return nullptr;
@@ -2575,15 +2543,6 @@
   return found ? oat_method.GetQuickCode() : nullptr;
 }
 
-const void* ClassLinker::GetOatMethodPortableCodeFor(mirror::ArtMethod* method) {
-  if (method->IsNative() || method->IsAbstract() || method->IsProxyMethod()) {
-    return nullptr;
-  }
-  bool found;
-  OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
-  return found ? oat_method.GetPortableCode() : nullptr;
-}
-
 const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
                                             uint32_t method_idx) {
   bool found;
@@ -2595,34 +2554,15 @@
   return oat_class.GetOatMethod(oat_method_idx).GetQuickCode();
 }
 
-const void* ClassLinker::GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
-                                               uint32_t method_idx) {
-  bool found;
-  OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found);
-  if (!found) {
-    return nullptr;
-  }
-  uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
-  return oat_class.GetOatMethod(oat_method_idx).GetPortableCode();
-}
-
 // Returns true if the method must run with interpreter, false otherwise.
-static bool NeedsInterpreter(
-    mirror::ArtMethod* method, const void* quick_code, const void* portable_code)
+static bool NeedsInterpreter(mirror::ArtMethod* method, const void* quick_code)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if ((quick_code == nullptr) && (portable_code == nullptr)) {
+  if (quick_code == nullptr) {
     // No code: need interpreter.
     // May return true for native code, in the case of generic JNI
     // DCHECK(!method->IsNative());
     return true;
   }
-#ifdef ART_SEA_IR_MODE
-  ScopedObjectAccess soa(Thread::Current());
-  if (std::string::npos != PrettyMethod(method).find("fibonacci")) {
-    LOG(INFO) << "Found " << PrettyMethod(method);
-    return false;
-  }
-#endif
   // If interpreter mode is enabled, every method (except native and proxy) must
   // be run with interpreter.
   return Runtime::Current()->GetInstrumentation()->InterpretOnly() &&
@@ -2644,7 +2584,7 @@
   const DexFile& dex_file = klass->GetDexFile();
   const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
   CHECK(dex_class_def != nullptr);
-  const byte* class_data = dex_file.GetClassData(*dex_class_def);
+  const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
   // There should always be class data if there were direct methods.
   CHECK(class_data != nullptr) << PrettyDescriptor(klass);
   ClassDataItemIterator it(dex_file, class_data);
@@ -2665,118 +2605,83 @@
       // Only update static methods.
       continue;
     }
-    const void* portable_code = nullptr;
     const void* quick_code = nullptr;
     if (has_oat_class) {
       OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
-      portable_code = oat_method.GetPortableCode();
       quick_code = oat_method.GetQuickCode();
     }
-    const bool enter_interpreter = NeedsInterpreter(method, quick_code, portable_code);
-    bool have_portable_code = false;
+    const bool enter_interpreter = NeedsInterpreter(method, quick_code);
     if (enter_interpreter) {
       // 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();
-        portable_code = GetPortableToQuickBridge();
+      if (quick_code == nullptr && method->IsNative()) {
+        quick_code = GetQuickGenericJniStub();
       } else {
-        portable_code = GetPortableToInterpreterBridge();
         quick_code = GetQuickToInterpreterBridge();
       }
-    } else {
-      if (portable_code == nullptr) {
-        portable_code = GetPortableToQuickBridge();
-      } else {
-        have_portable_code = true;
-      }
-      if (quick_code == nullptr) {
-        quick_code = GetQuickToPortableBridge();
-      }
     }
-    runtime->GetInstrumentation()->UpdateMethodsCode(method, quick_code, portable_code,
-                                                     have_portable_code);
+    runtime->GetInstrumentation()->UpdateMethodsCode(method, quick_code);
   }
   // Ignore virtual methods on the iterator.
 }
 
 void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
                            const OatFile::OatClass* oat_class,
-                           const DexFile& dex_file, uint32_t dex_method_index,
-                           uint32_t method_index) {
-  if (Runtime::Current()->IsCompiler()) {
+                           uint32_t class_def_method_index) {
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsCompiler()) {
     // The following code only applies to a non-compiler runtime.
     return;
   }
   // Method shouldn't have already been linked.
   DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
-  DCHECK(method->GetEntryPointFromPortableCompiledCode() == nullptr);
   if (oat_class != nullptr) {
     // Every kind of method should at least get an invoke stub from the oat_method.
     // non-abstract methods also get their code pointers.
-    const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
+    const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
     oat_method.LinkMethod(method.Get());
   }
 
   // Install entry point from interpreter.
   bool enter_interpreter = NeedsInterpreter(method.Get(),
-                                            method->GetEntryPointFromQuickCompiledCode(),
-                                            method->GetEntryPointFromPortableCompiledCode());
+                                            method->GetEntryPointFromQuickCompiledCode());
   if (enter_interpreter && !method->IsNative()) {
-    method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
   } else {
     method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
   }
 
   if (method->IsAbstract()) {
     method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
-    method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
     return;
   }
 
-  bool have_portable_code = false;
   if (method->IsStatic() && !method->IsConstructor()) {
     // 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());
   } 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->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+      method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
     }
-  } else if (method->GetEntryPointFromPortableCompiledCode() != nullptr) {
-    DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
-    have_portable_code = true;
-    method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
-  } else {
-    DCHECK(method->GetEntryPointFromQuickCompiledCode() != nullptr);
-    method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
   }
 
   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(),
-                                                   have_portable_code);
 }
 
 
@@ -2804,8 +2709,9 @@
 
   klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
   klass->SetDexTypeIndex(dex_class_def.class_idx_);
+  CHECK(klass->GetDexCacheStrings() != nullptr);
 
-  const byte* class_data = dex_file.GetClassData(dex_class_def);
+  const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
   if (class_data == nullptr) {
     return;  // no fields or methods - for example a marker interface
   }
@@ -2816,18 +2722,17 @@
     OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
                                                &has_oat_class);
     if (has_oat_class) {
-      LoadClassMembers(self, dex_file, class_data, klass, class_loader, &oat_class);
+      LoadClassMembers(self, dex_file, class_data, klass, &oat_class);
     }
   }
   if (!has_oat_class) {
-    LoadClassMembers(self, dex_file, class_data, klass, class_loader, nullptr);
+    LoadClassMembers(self, dex_file, class_data, klass, nullptr);
   }
 }
 
 void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file,
-                                   const byte* class_data,
+                                   const uint8_t* class_data,
                                    Handle<mirror::Class> klass,
-                                   mirror::ClassLoader* class_loader,
                                    const OatFile::OatClass* oat_class) {
   // Load fields.
   ClassDataItemIterator it(dex_file, class_data);
@@ -2904,7 +2809,7 @@
       return;
     }
     klass->SetDirectMethod(i, method.Get());
-    LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
+    LinkCode(method, oat_class, class_def_method_index);
     uint32_t it_method_index = it.GetMemberIndex();
     if (last_dex_method_index == it_method_index) {
       // duplicate case
@@ -2926,7 +2831,7 @@
     }
     klass->SetVirtualMethod(i, method.Get());
     DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
-    LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
+    LinkCode(method, oat_class, class_def_method_index);
     class_def_method_index++;
   }
   DCHECK(!it.HasNext());
@@ -2960,7 +2865,6 @@
   dst->SetDeclaringClass(klass.Get());
   dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
 
-  dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
   dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
   dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
 
@@ -3103,7 +3007,7 @@
     LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
   }
   LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
-  return nullptr;
+  UNREACHABLE();
 }
 
 void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) {
@@ -3134,7 +3038,8 @@
   primitive_class->SetPrimitiveType(type);
   primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
   const char* descriptor = Primitive::Descriptor(type);
-  mirror::Class* existing = InsertClass(descriptor, primitive_class, Hash(descriptor));
+  mirror::Class* existing = InsertClass(descriptor, primitive_class,
+                                        ComputeModifiedUtf8Hash(descriptor));
   CHECK(existing == nullptr) << "InitPrimitiveClass(" << type << ") failed";
   return primitive_class;
 }
@@ -3152,7 +3057,7 @@
 // array class; that always comes from the base element class.
 //
 // Returns nullptr with an exception raised on failure.
-mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor,
+mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor, size_t hash,
                                              Handle<mirror::ClassLoader> class_loader) {
   // Identify the underlying component type
   CHECK_EQ('[', descriptor[0]);
@@ -3162,7 +3067,8 @@
   if (component_type.Get() == nullptr) {
     DCHECK(self->IsExceptionPending());
     // We need to accept erroneous classes as component types.
-    component_type.Assign(LookupClass(self, descriptor + 1, class_loader.Get()));
+    const size_t component_hash = ComputeModifiedUtf8Hash(descriptor + 1);
+    component_type.Assign(LookupClass(self, descriptor + 1, component_hash, class_loader.Get()));
     if (component_type.Get() == nullptr) {
       DCHECK(self->IsExceptionPending());
       return nullptr;
@@ -3192,7 +3098,7 @@
   // class to the hash table --- necessary because of possible races with
   // other threads.)
   if (class_loader.Get() != component_type->GetClassLoader()) {
-    mirror::Class* new_class = LookupClass(self, descriptor, component_type->GetClassLoader());
+    mirror::Class* new_class = LookupClass(self, descriptor, hash, component_type->GetClassLoader());
     if (new_class != nullptr) {
       return new_class;
     }
@@ -3213,13 +3119,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));
@@ -3242,7 +3148,11 @@
   new_class->SetPrimitiveType(Primitive::kPrimNot);
   new_class->SetClassLoader(component_type->GetClassLoader());
   new_class->SetStatus(mirror::Class::kStatusLoaded, self);
-  new_class->PopulateEmbeddedImtAndVTable();
+  {
+    StackHandleScope<mirror::Class::kImtSize> hs2(self,
+                                                  Runtime::Current()->GetImtUnimplementedMethod());
+    new_class->PopulateEmbeddedImtAndVTable(&hs2);
+  }
   new_class->SetStatus(mirror::Class::kStatusInitialized, self);
   // don't need to set new_class->SetObjectSize(..)
   // because Object::SizeOf delegates to Array::SizeOf
@@ -3277,7 +3187,7 @@
 
   new_class->SetAccessFlags(access_flags);
 
-  mirror::Class* existing = InsertClass(descriptor, new_class.Get(), Hash(descriptor));
+  mirror::Class* existing = InsertClass(descriptor, new_class.Get(), hash);
   if (existing == nullptr) {
     return new_class.Get();
   }
@@ -3330,8 +3240,7 @@
     LOG(INFO) << "Loaded class " << descriptor << source;
   }
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  mirror::Class* existing =
-      LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
+  mirror::Class* existing = LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
   if (existing != nullptr) {
     return existing;
   }
@@ -3341,13 +3250,13 @@
     // is in the image.
     existing = LookupClassFromImage(descriptor);
     if (existing != nullptr) {
-      CHECK(klass == existing);
+      CHECK_EQ(klass, existing);
     }
   }
   VerifyObject(klass);
-  class_table_.insert(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
+  class_table_.InsertWithHash(GcRoot<mirror::Class>(klass), hash);
   if (log_new_class_table_roots_) {
-    new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
+    new_class_roots_.push_back(GcRoot<mirror::Class>(klass));
   }
   return nullptr;
 }
@@ -3355,27 +3264,18 @@
 mirror::Class* ClassLinker::UpdateClass(const char* descriptor, mirror::Class* klass,
                                         size_t hash) {
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  mirror::Class* existing =
-      LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
-
-  if (existing == nullptr) {
+  auto existing_it = class_table_.FindWithHash(std::make_pair(descriptor, klass->GetClassLoader()),
+                                               hash);
+  if (existing_it == class_table_.end()) {
     CHECK(klass->IsProxyClass());
     return nullptr;
   }
 
+  mirror::Class* existing = existing_it->Read();
   CHECK_NE(existing, klass) << descriptor;
   CHECK(!existing->IsResolved()) << descriptor;
   CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor;
 
-  for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
-       it != end && it->first == hash; ++it) {
-    mirror::Class* klass = it->second.Read();
-    if (klass == existing) {
-      class_table_.erase(it);
-      break;
-    }
-  }
-
   CHECK(!klass->IsTemp()) << descriptor;
   if (kIsDebugBuild && klass->GetClassLoader() == nullptr &&
       dex_cache_image_class_lookup_required_) {
@@ -3383,37 +3283,38 @@
     // is in the image.
     existing = LookupClassFromImage(descriptor);
     if (existing != nullptr) {
-      CHECK(klass == existing) << descriptor;
+      CHECK_EQ(klass, existing) << descriptor;
     }
   }
   VerifyObject(klass);
 
-  class_table_.insert(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
+  // Update the element in the hash set.
+  *existing_it = GcRoot<mirror::Class>(klass);
   if (log_new_class_table_roots_) {
-    new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
+    new_class_roots_.push_back(GcRoot<mirror::Class>(klass));
   }
 
   return existing;
 }
 
-bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
-  size_t hash = Hash(descriptor);
+bool ClassLinker::RemoveClass(const char* descriptor, mirror::ClassLoader* class_loader) {
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
-       it != end && it->first == hash;
-       ++it) {
-    mirror::Class* klass = it->second.Read();
-    if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
-      class_table_.erase(it);
-      return true;
-    }
+  auto pair = std::make_pair(descriptor, class_loader);
+  auto it = class_table_.Find(pair);
+  if (it != class_table_.end()) {
+    class_table_.Erase(it);
+    return true;
+  }
+  it = pre_zygote_class_table_.Find(pair);
+  if (it != pre_zygote_class_table_.end()) {
+    pre_zygote_class_table_.Erase(it);
+    return true;
   }
   return false;
 }
 
-mirror::Class* ClassLinker::LookupClass(Thread* self, const char* descriptor,
-                                        const mirror::ClassLoader* class_loader) {
-  size_t hash = Hash(descriptor);
+mirror::Class* ClassLinker::LookupClass(Thread* self, const char* descriptor, size_t hash,
+                                        mirror::ClassLoader* class_loader) {
   {
     ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
     mirror::Class* result = LookupClassFromTableLocked(descriptor, class_loader, hash);
@@ -3442,26 +3343,17 @@
 }
 
 mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor,
-                                                       const mirror::ClassLoader* class_loader,
+                                                       mirror::ClassLoader* class_loader,
                                                        size_t hash) {
-  auto end = class_table_.end();
-  for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) {
-    mirror::Class* klass = it->second.Read();
-    if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
-      if (kIsDebugBuild) {
-        // Check for duplicates in the table.
-        for (++it; it != end && it->first == hash; ++it) {
-          mirror::Class* klass2 = it->second.Read();
-          CHECK(!(klass2->GetClassLoader() == class_loader &&
-              klass2->DescriptorEquals(descriptor)))
-              << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
-              << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader();
-        }
-      }
-      return klass;
+  auto descriptor_pair = std::make_pair(descriptor, class_loader);
+  auto it = pre_zygote_class_table_.FindWithHash(descriptor_pair, hash);
+  if (it == pre_zygote_class_table_.end()) {
+    it = class_table_.FindWithHash(descriptor_pair, hash);
+    if (it == class_table_.end()) {
+      return nullptr;
     }
   }
-  return nullptr;
+  return it->Read();
 }
 
 static mirror::ObjectArray<mirror::DexCache>* GetImageDexCaches()
@@ -3489,15 +3381,15 @@
       if (klass != nullptr) {
         DCHECK(klass->GetClassLoader() == nullptr);
         const char* descriptor = klass->GetDescriptor(&temp);
-        size_t hash = Hash(descriptor);
+        size_t hash = ComputeModifiedUtf8Hash(descriptor);
         mirror::Class* existing = LookupClassFromTableLocked(descriptor, nullptr, hash);
         if (existing != nullptr) {
-          CHECK(existing == klass) << PrettyClassAndClassLoader(existing) << " != "
+          CHECK_EQ(existing, klass) << PrettyClassAndClassLoader(existing) << " != "
               << PrettyClassAndClassLoader(klass);
         } else {
-          class_table_.insert(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
+          class_table_.Insert(GcRoot<mirror::Class>(klass));
           if (log_new_class_table_roots_) {
-            new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
+            new_class_roots_.push_back(GcRoot<mirror::Class>(klass));
           }
         }
       }
@@ -3506,6 +3398,13 @@
   dex_cache_image_class_lookup_required_ = false;
 }
 
+void ClassLinker::MoveClassTableToPreZygote() {
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  DCHECK(pre_zygote_class_table_.Empty());
+  pre_zygote_class_table_ = std::move(class_table_);
+  class_table_.Clear();
+}
+
 mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) {
   ScopedAssertNoThreadSuspension ants(Thread::Current(), "Image class lookup");
   mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches();
@@ -3534,14 +3433,32 @@
   if (dex_cache_image_class_lookup_required_) {
     MoveImageClassesToClassTable();
   }
-  size_t hash = Hash(descriptor);
-  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
-      it != end && it->first == hash; ++it) {
-    mirror::Class* klass = it->second.Read();
-    if (klass->DescriptorEquals(descriptor)) {
-      result.push_back(klass);
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  while (true) {
+    auto it = class_table_.Find(descriptor);
+    if (it == class_table_.end()) {
+      break;
     }
+    result.push_back(it->Read());
+    class_table_.Erase(it);
+  }
+  for (mirror::Class* k : result) {
+    class_table_.Insert(GcRoot<mirror::Class>(k));
+  }
+  size_t pre_zygote_start = result.size();
+  // Now handle the pre zygote table.
+  // Note: This dirties the pre-zygote table but shouldn't be an issue since LookupClasses is only
+  // called from the debugger.
+  while (true) {
+    auto it = pre_zygote_class_table_.Find(descriptor);
+    if (it == pre_zygote_class_table_.end()) {
+      break;
+    }
+    result.push_back(it->Read());
+    pre_zygote_class_table_.Erase(it);
+  }
+  for (size_t i = pre_zygote_start; i < result.size(); ++i) {
+    pre_zygote_class_table_.Insert(GcRoot<mirror::Class>(result[i]));
   }
 }
 
@@ -3586,7 +3503,7 @@
   Handle<mirror::Class> super(hs.NewHandle(klass->GetSuperClass()));
   if (super.Get() != nullptr) {
     // Acquire lock to prevent races on verifying the super class.
-    ObjectLock<mirror::Class> lock(self, super);
+    ObjectLock<mirror::Class> super_lock(self, super);
 
     if (!super->IsVerified() && !super->IsErroneous()) {
       VerifyClass(self, super);
@@ -3719,6 +3636,19 @@
     return false;
   }
 
+  // We may be running with a preopted oat file but without image. In this case,
+  // we don't skip verification of preverified classes to ensure we initialize
+  // dex caches with all types resolved during verification.
+  // We need to trust image classes, as these might be coming out of a pre-opted, quickened boot
+  // image (that we just failed loading), and the verifier can't be run on quickened opcodes when
+  // the runtime isn't started. On the other hand, app classes can be re-verified even if they are
+  // already pre-opted, as then the runtime is started.
+  if (!Runtime::Current()->IsCompiler() &&
+      !Runtime::Current()->GetHeap()->HasImageSpace() &&
+      klass->GetClassLoader() != nullptr) {
+    return false;
+  }
+
   uint16_t class_def_index = klass->GetDexClassDefIndex();
   oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
   if (oat_file_class_status == mirror::Class::kStatusVerified ||
@@ -3761,8 +3691,7 @@
   LOG(FATAL) << "Unexpected class status: " << oat_file_class_status
              << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " "
              << klass->GetDescriptor(&temp);
-
-  return false;
+  UNREACHABLE();
 }
 
 void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
@@ -3785,7 +3714,7 @@
   if (code_item->tries_size_ == 0) {
     return;  // nothing to process
   }
-  const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
   uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   for (uint32_t idx = 0; idx < handlers_size; idx++) {
@@ -3891,10 +3820,10 @@
     klass->SetVirtualMethods(virtuals);
   }
   for (size_t i = 0; i < num_virtual_methods; ++i) {
-    StackHandleScope<1> hs(self);
+    StackHandleScope<1> hs2(self);
     mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
         soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
-    Handle<mirror::ArtMethod> prototype(hs.NewHandle(decoded_methods->Get(i)));
+    Handle<mirror::ArtMethod> prototype(hs2.NewHandle(decoded_methods->Get(i)));
     mirror::ArtMethod* clone = CreateProxyMethod(self, klass, prototype);
     if (UNLIKELY(clone == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
@@ -3943,11 +3872,11 @@
     CHECK(klass->GetIFields() == nullptr);
     CheckProxyConstructor(klass->GetDirectMethod(0));
     for (size_t i = 0; i < num_virtual_methods; ++i) {
-      StackHandleScope<2> hs(self);
+      StackHandleScope<2> hs2(self);
       mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
           soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
-      Handle<mirror::ArtMethod> prototype(hs.NewHandle(decoded_methods->Get(i)));
-      Handle<mirror::ArtMethod> virtual_method(hs.NewHandle(klass->GetVirtualMethod(i)));
+      Handle<mirror::ArtMethod> prototype(hs2.NewHandle(decoded_methods->Get(i)));
+      Handle<mirror::ArtMethod> virtual_method(hs2.NewHandle(klass->GetVirtualMethod(i)));
       CheckProxyMethod(virtual_method, prototype);
     }
 
@@ -3965,7 +3894,8 @@
     CHECK_EQ(klass.Get()->GetThrows(),
              soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
   }
-  mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), Hash(descriptor.c_str()));
+  mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(),
+                                        ComputeModifiedUtf8Hash(descriptor.c_str()));
   CHECK(existing == nullptr);
   return klass.Get();
 }
@@ -4058,7 +3988,6 @@
   // At runtime the method looks like a reference and argument saving method, clone the code
   // related parameters from this method.
   method->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
-  method->SetEntryPointFromPortableCompiledCode(GetPortableProxyInvokeHandler());
   method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
 
   return method;
@@ -4074,18 +4003,14 @@
 
   // The proxy method doesn't have its own dex cache or dex file and so it steals those of its
   // interface prototype. The exception to this are Constructors and the Class of the Proxy itself.
-  CHECK_EQ(prototype->GetDexCacheStrings(), method->GetDexCacheStrings());
   CHECK(prototype->HasSameDexCacheResolvedMethods(method.Get()));
   CHECK(prototype->HasSameDexCacheResolvedTypes(method.Get()));
   CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
 
-  StackHandleScope<2> hs(Thread::Current());
-  MethodHelper mh(hs.NewHandle(method.Get()));
-  MethodHelper mh2(hs.NewHandle(prototype.Get()));
   CHECK_STREQ(method->GetName(), prototype->GetName());
   CHECK_STREQ(method->GetShorty(), prototype->GetShorty());
   // More complex sanity - via dex cache
-  CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType());
+  CHECK_EQ(method->GetInterfaceMethodIfProxy()->GetReturnType(), prototype->GetReturnType());
 }
 
 static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
@@ -4151,6 +4076,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 +4089,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 +4108,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?
@@ -4234,23 +4162,38 @@
     }
   }
 
-  if (klass->NumStaticFields() > 0) {
+  const size_t num_static_fields = klass->NumStaticFields();
+  if (num_static_fields > 0) {
     const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
     CHECK(dex_class_def != nullptr);
     const DexFile& dex_file = klass->GetDexFile();
     StackHandleScope<3> hs(self);
     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+
+    // Eagerly fill in static fields so that the we don't have to do as many expensive
+    // Class::FindStaticField in ResolveField.
+    for (size_t i = 0; i < num_static_fields; ++i) {
+      mirror::ArtField* field = klass->GetStaticField(i);
+      const uint32_t field_idx = field->GetDexFieldIndex();
+      mirror::ArtField* resolved_field = dex_cache->GetResolvedField(field_idx);
+      if (resolved_field == nullptr) {
+        dex_cache->SetResolvedField(field_idx, field);
+      } else {
+        DCHECK_EQ(field, resolved_field);
+      }
+    }
+
     EncodedStaticFieldValueIterator value_it(dex_file, &dex_cache, &class_loader,
                                              this, *dex_class_def);
-    const byte* class_data = dex_file.GetClassData(*dex_class_def);
+    const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
     ClassDataItemIterator field_it(dex_file, class_data);
     if (value_it.HasNext()) {
       DCHECK(field_it.HasNextStaticField());
       CHECK(can_init_statics);
       for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) {
-        StackHandleScope<1> hs(self);
-        Handle<mirror::ArtField> field(hs.NewHandle(
+        StackHandleScope<1> hs2(self);
+        Handle<mirror::ArtField> field(hs2.NewHandle(
             ResolveField(dex_file, field_it.GetMemberIndex(), dex_cache, class_loader, true)));
         if (Runtime::Current()->IsActiveTransaction()) {
           value_it.ReadValueToField<true>(field);
@@ -4277,7 +4220,7 @@
     ObjectLock<mirror::Class> lock(self, klass);
 
     if (self->IsExceptionPending()) {
-      WrapExceptionInInitializer();
+      WrapExceptionInInitializer(klass);
       klass->SetStatus(mirror::Class::kStatusError, self);
       success = false;
     } else {
@@ -4311,9 +4254,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 +4273,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()) {
@@ -4341,25 +4285,61 @@
   UNREACHABLE();
 }
 
+static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
+                                                      Handle<mirror::ArtMethod> method1,
+                                                      Handle<mirror::ArtMethod> method2)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType()));
+    if (UNLIKELY(method2->GetReturnType() != return_type.Get())) {
+      return false;
+    }
+  }
+  const DexFile::TypeList* types1 = method1->GetParameterTypeList();
+  const DexFile::TypeList* types2 = method2->GetParameterTypeList();
+  if (types1 == nullptr) {
+    return (types2 == nullptr) || (types2->Size() == 0);
+  } else if (UNLIKELY(types2 == nullptr)) {
+    return types1->Size() == 0;
+  }
+  uint32_t num_types = types1->Size();
+  if (UNLIKELY(num_types != types2->Size())) {
+    return false;
+  }
+  for (uint32_t i = 0; i < num_types; ++i) {
+    mirror::Class* param_type =
+        method1->GetClassFromTypeIndex(types1->GetTypeItem(i).type_idx_, true);
+    mirror::Class* other_param_type =
+        method2->GetClassFromTypeIndex(types2->GetTypeItem(i).type_idx_, true);
+    if (UNLIKELY(param_type != other_param_type)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
 bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) {
   if (klass->IsInterface()) {
     return true;
   }
   // Begin with the methods local to the superclass.
-  StackHandleScope<2> hs(Thread::Current());
-  MutableMethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-  MutableMethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  Thread* self = Thread::Current();
+  StackHandleScope<2> hs(self);
+  MutableHandle<mirror::ArtMethod> h_m(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableHandle<mirror::ArtMethod> super_h_m(hs.NewHandle<mirror::ArtMethod>(nullptr));
   if (klass->HasSuperClass() &&
       klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
     for (int i = klass->GetSuperClass()->GetVTableLength() - 1; i >= 0; --i) {
-      mh.ChangeMethod(klass->GetVTableEntry(i));
-      super_mh.ChangeMethod(klass->GetSuperClass()->GetVTableEntry(i));
-      if (mh.GetMethod() != super_mh.GetMethod() &&
-          !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
+      h_m.Assign(klass->GetVTableEntry(i));
+      super_h_m.Assign(klass->GetSuperClass()->GetVTableEntry(i));
+      if (h_m.Get() != super_h_m.Get() &&
+          !HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m)) {
         ThrowLinkageError(klass.Get(),
                           "Class %s method %s resolves differently in superclass %s",
                           PrettyDescriptor(klass.Get()).c_str(),
-                          PrettyMethod(mh.GetMethod()).c_str(),
+                          PrettyMethod(h_m.Get()).c_str(),
                           PrettyDescriptor(klass->GetSuperClass()).c_str());
         return false;
       }
@@ -4369,14 +4349,14 @@
     if (klass->GetClassLoader() != klass->GetIfTable()->GetInterface(i)->GetClassLoader()) {
       uint32_t num_methods = klass->GetIfTable()->GetInterface(i)->NumVirtualMethods();
       for (uint32_t j = 0; j < num_methods; ++j) {
-        mh.ChangeMethod(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j));
-        super_mh.ChangeMethod(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
-        if (mh.GetMethod() != super_mh.GetMethod() &&
-            !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
+        h_m.Assign(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j));
+        super_h_m.Assign(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
+        if (h_m.Get() != super_h_m.Get() &&
+            !HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m)) {
           ThrowLinkageError(klass.Get(),
                             "Class %s method %s resolves differently in interface %s",
                             PrettyDescriptor(klass.Get()).c_str(),
-                            PrettyMethod(mh.GetMethod()).c_str(),
+                            PrettyMethod(h_m.Get()).c_str(),
                             PrettyDescriptor(klass->GetIfTable()->GetInterface(i)).c_str());
           return false;
         }
@@ -4450,7 +4430,9 @@
   if (!LinkSuperClass(klass)) {
     return false;
   }
-  if (!LinkMethods(self, klass, interfaces)) {
+  StackHandleScope<mirror::Class::kImtSize> imt_handle_scope(
+      self, Runtime::Current()->GetImtUnimplementedMethod());
+  if (!LinkMethods(self, klass, interfaces, &imt_handle_scope)) {
     return false;
   }
   if (!LinkInstanceFields(self, klass)) {
@@ -4469,7 +4451,7 @@
     CHECK_EQ(klass->GetClassSize(), class_size) << PrettyDescriptor(klass.Get());
 
     if (klass->ShouldHaveEmbeddedImtAndVTable()) {
-      klass->PopulateEmbeddedImtAndVTable();
+      klass->PopulateEmbeddedImtAndVTable(&imt_handle_scope);
     }
 
     // This will notify waiters on klass that saw the not yet resolved
@@ -4479,7 +4461,7 @@
   } else {
     CHECK(!klass->IsResolved());
     // Retire the temporary class and create the correctly sized resolved class.
-    *new_class = klass->CopyOf(self, class_size);
+    *new_class = klass->CopyOf(self, class_size, &imt_handle_scope);
     if (UNLIKELY(*new_class == nullptr)) {
       CHECK(self->IsExceptionPending());  // Expect an OOME.
       klass->SetStatus(mirror::Class::kStatusError, self);
@@ -4493,7 +4475,8 @@
 
     FixupTemporaryDeclaringClass(klass.Get(), new_class_h.Get());
 
-    mirror::Class* existing = UpdateClass(descriptor, new_class_h.Get(), Hash(descriptor));
+    mirror::Class* existing = UpdateClass(descriptor, new_class_h.Get(),
+                                          ComputeModifiedUtf8Hash(descriptor));
     CHECK(existing == nullptr || existing == klass.Get());
 
     // This will notify waiters on temp class that saw the not yet resolved class in the
@@ -4508,6 +4491,171 @@
   return true;
 }
 
+static void CountMethodsAndFields(ClassDataItemIterator& dex_data,
+                                  size_t* virtual_methods,
+                                  size_t* direct_methods,
+                                  size_t* static_fields,
+                                  size_t* instance_fields) {
+  *virtual_methods = *direct_methods = *static_fields = *instance_fields = 0;
+
+  while (dex_data.HasNextStaticField()) {
+    dex_data.Next();
+    (*static_fields)++;
+  }
+  while (dex_data.HasNextInstanceField()) {
+    dex_data.Next();
+    (*instance_fields)++;
+  }
+  while (dex_data.HasNextDirectMethod()) {
+    (*direct_methods)++;
+    dex_data.Next();
+  }
+  while (dex_data.HasNextVirtualMethod()) {
+    (*virtual_methods)++;
+    dex_data.Next();
+  }
+  DCHECK(!dex_data.HasNext());
+}
+
+static void DumpClass(std::ostream& os,
+                      const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
+                      const char* suffix) {
+  ClassDataItemIterator dex_data(dex_file, dex_file.GetClassData(dex_class_def));
+  os << dex_file.GetClassDescriptor(dex_class_def) << suffix << ":\n";
+  os << " Static fields:\n";
+  while (dex_data.HasNextStaticField()) {
+    const DexFile::FieldId& id = dex_file.GetFieldId(dex_data.GetMemberIndex());
+    os << "  " << dex_file.GetFieldTypeDescriptor(id) << " " << dex_file.GetFieldName(id) << "\n";
+    dex_data.Next();
+  }
+  os << " Instance fields:\n";
+  while (dex_data.HasNextInstanceField()) {
+    const DexFile::FieldId& id = dex_file.GetFieldId(dex_data.GetMemberIndex());
+    os << "  " << dex_file.GetFieldTypeDescriptor(id) << " " << dex_file.GetFieldName(id) << "\n";
+    dex_data.Next();
+  }
+  os << " Direct methods:\n";
+  while (dex_data.HasNextDirectMethod()) {
+    const DexFile::MethodId& id = dex_file.GetMethodId(dex_data.GetMemberIndex());
+    os << "  " << dex_file.GetMethodName(id) << dex_file.GetMethodSignature(id).ToString() << "\n";
+    dex_data.Next();
+  }
+  os << " Virtual methods:\n";
+  while (dex_data.HasNextVirtualMethod()) {
+    const DexFile::MethodId& id = dex_file.GetMethodId(dex_data.GetMemberIndex());
+    os << "  " << dex_file.GetMethodName(id) << dex_file.GetMethodSignature(id).ToString() << "\n";
+    dex_data.Next();
+  }
+}
+
+static std::string DumpClasses(const DexFile& dex_file1, const DexFile::ClassDef& dex_class_def1,
+                               const DexFile& dex_file2, const DexFile::ClassDef& dex_class_def2) {
+  std::ostringstream os;
+  DumpClass(os, dex_file1, dex_class_def1, " (Compile time)");
+  DumpClass(os, dex_file2, dex_class_def2, " (Runtime)");
+  return os.str();
+}
+
+
+// Very simple structural check on whether the classes match. Only compares the number of
+// methods and fields.
+static bool SimpleStructuralCheck(const DexFile& dex_file1, const DexFile::ClassDef& dex_class_def1,
+                                  const DexFile& dex_file2, const DexFile::ClassDef& dex_class_def2,
+                                  std::string* error_msg) {
+  ClassDataItemIterator dex_data1(dex_file1, dex_file1.GetClassData(dex_class_def1));
+  ClassDataItemIterator dex_data2(dex_file2, dex_file2.GetClassData(dex_class_def2));
+
+  // Counters for current dex file.
+  size_t dex_virtual_methods1, dex_direct_methods1, dex_static_fields1, dex_instance_fields1;
+  CountMethodsAndFields(dex_data1, &dex_virtual_methods1, &dex_direct_methods1, &dex_static_fields1,
+                        &dex_instance_fields1);
+  // Counters for compile-time dex file.
+  size_t dex_virtual_methods2, dex_direct_methods2, dex_static_fields2, dex_instance_fields2;
+  CountMethodsAndFields(dex_data2, &dex_virtual_methods2, &dex_direct_methods2, &dex_static_fields2,
+                        &dex_instance_fields2);
+
+  if (dex_virtual_methods1 != dex_virtual_methods2) {
+    std::string class_dump = DumpClasses(dex_file1, dex_class_def1, dex_file2, dex_class_def2);
+    *error_msg = StringPrintf("Virtual method count off: %zu vs %zu\n%s", dex_virtual_methods1,
+                              dex_virtual_methods2, class_dump.c_str());
+    return false;
+  }
+  if (dex_direct_methods1 != dex_direct_methods2) {
+    std::string class_dump = DumpClasses(dex_file1, dex_class_def1, dex_file2, dex_class_def2);
+    *error_msg = StringPrintf("Direct method count off: %zu vs %zu\n%s", dex_direct_methods1,
+                              dex_direct_methods2, class_dump.c_str());
+    return false;
+  }
+  if (dex_static_fields1 != dex_static_fields2) {
+    std::string class_dump = DumpClasses(dex_file1, dex_class_def1, dex_file2, dex_class_def2);
+    *error_msg = StringPrintf("Static field count off: %zu vs %zu\n%s", dex_static_fields1,
+                              dex_static_fields2, class_dump.c_str());
+    return false;
+  }
+  if (dex_instance_fields1 != dex_instance_fields2) {
+    std::string class_dump = DumpClasses(dex_file1, dex_class_def1, dex_file2, dex_class_def2);
+    *error_msg = StringPrintf("Instance field count off: %zu vs %zu\n%s", dex_instance_fields1,
+                              dex_instance_fields2, class_dump.c_str());
+    return false;
+  }
+
+  return true;
+}
+
+// Checks whether a the super-class changed from what we had at compile-time. This would
+// invalidate quickening.
+static bool CheckSuperClassChange(Handle<mirror::Class> klass,
+                                  const DexFile& dex_file,
+                                  const DexFile::ClassDef& class_def,
+                                  mirror::Class* super_class)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Check for unexpected changes in the superclass.
+  // Quick check 1) is the super_class class-loader the boot class loader? This always has
+  // precedence.
+  if (super_class->GetClassLoader() != nullptr &&
+      // Quick check 2) different dex cache? Breaks can only occur for different dex files,
+      // which is implied by different dex cache.
+      klass->GetDexCache() != super_class->GetDexCache()) {
+    // Now comes the expensive part: things can be broken if (a) the klass' dex file has a
+    // definition for the super-class, and (b) the files are in separate oat files. The oat files
+    // are referenced from the dex file, so do (b) first. Only relevant if we have oat files.
+    const OatFile* class_oat_file = dex_file.GetOatFile();
+    if (class_oat_file != nullptr) {
+      const OatFile* loaded_super_oat_file = super_class->GetDexFile().GetOatFile();
+      if (loaded_super_oat_file != nullptr && class_oat_file != loaded_super_oat_file) {
+        // Now check (a).
+        const DexFile::ClassDef* super_class_def = dex_file.FindClassDef(class_def.superclass_idx_);
+        if (super_class_def != nullptr) {
+          // Uh-oh, we found something. Do our check.
+          std::string error_msg;
+          if (!SimpleStructuralCheck(dex_file, *super_class_def,
+                                     super_class->GetDexFile(), *super_class->GetClassDef(),
+                                     &error_msg)) {
+            // Print a warning to the log. This exception might be caught, e.g., as common in test
+            // drivers. When the class is later tried to be used, we re-throw a new instance, as we
+            // only save the type of the exception.
+            LOG(WARNING) << "Incompatible structural change detected: " <<
+                StringPrintf(
+                    "Structural change of %s is hazardous (%s at compile time, %s at runtime): %s",
+                    PrettyType(super_class_def->class_idx_, dex_file).c_str(),
+                    class_oat_file->GetLocation().c_str(),
+                    loaded_super_oat_file->GetLocation().c_str(),
+                    error_msg.c_str());
+            ThrowIncompatibleClassChangeError(klass.Get(),
+                "Structural change of %s is hazardous (%s at compile time, %s at runtime): %s",
+                PrettyType(super_class_def->class_idx_, dex_file).c_str(),
+                class_oat_file->GetLocation().c_str(),
+                loaded_super_oat_file->GetLocation().c_str(),
+                error_msg.c_str());
+            return false;
+          }
+        }
+      }
+    }
+  }
+  return true;
+}
+
 bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
   CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
@@ -4527,6 +4675,11 @@
     }
     CHECK(super_class->IsResolved());
     klass->SetSuperClass(super_class);
+
+    if (!CheckSuperClassChange(klass, dex_file, class_def, super_class)) {
+      DCHECK(Thread::Current()->IsExceptionPending());
+      return false;
+    }
   }
   const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
   if (interfaces != nullptr) {
@@ -4613,7 +4766,8 @@
 
 // Populate the class vtable and itable. Compute return type indices.
 bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass,
-                              Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
+                              Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                              StackHandleScope<mirror::Class::kImtSize>* out_imt) {
   self->AllowThreadSuspension();
   if (klass->IsInterface()) {
     // No vtable.
@@ -4625,22 +4779,127 @@
     for (size_t i = 0; i < count; ++i) {
       klass->GetVirtualMethodDuringLinking(i)->SetMethodIndex(i);
     }
-    // Link interface method tables
-    return LinkInterfaceMethods(klass, interfaces);
-  } else {
-    // Link virtual and interface method tables
-    return LinkVirtualMethods(self, klass) && LinkInterfaceMethods(klass, interfaces);
+  } else if (!LinkVirtualMethods(self, klass)) {  // Link virtual methods first.
+    return false;
   }
-  return true;
+  return LinkInterfaceMethods(self, klass, interfaces, out_imt);  // Link interface method last.
 }
 
+// Comparator for name and signature of a method, used in finding overriding methods. Implementation
+// avoids the use of handles, if it didn't then rather than compare dex files we could compare dex
+// caches in the implementation below.
+class MethodNameAndSignatureComparator FINAL : public ValueObject {
+ public:
+  explicit MethodNameAndSignatureComparator(mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+      dex_file_(method->GetDexFile()), mid_(&dex_file_->GetMethodId(method->GetDexMethodIndex())),
+      name_(nullptr), name_len_(0) {
+    DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
+  }
+
+  const char* GetName() {
+    if (name_ == nullptr) {
+      name_ = dex_file_->StringDataAndUtf16LengthByIdx(mid_->name_idx_, &name_len_);
+    }
+    return name_;
+  }
+
+  bool HasSameNameAndSignature(mirror::ArtMethod* other)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(!other->IsProxyMethod()) << PrettyMethod(other);
+    const DexFile* other_dex_file = other->GetDexFile();
+    const DexFile::MethodId& other_mid = other_dex_file->GetMethodId(other->GetDexMethodIndex());
+    if (dex_file_ == other_dex_file) {
+      return mid_->name_idx_ == other_mid.name_idx_ && mid_->proto_idx_ == other_mid.proto_idx_;
+    }
+    GetName();  // Only used to make sure its calculated.
+    uint32_t other_name_len;
+    const char* other_name = other_dex_file->StringDataAndUtf16LengthByIdx(other_mid.name_idx_,
+                                                                           &other_name_len);
+    if (name_len_ != other_name_len || strcmp(name_, other_name) != 0) {
+      return false;
+    }
+    return dex_file_->GetMethodSignature(*mid_) == other_dex_file->GetMethodSignature(other_mid);
+  }
+
+ private:
+  // Dex file for the method to compare against.
+  const DexFile* const dex_file_;
+  // MethodId for the method to compare against.
+  const DexFile::MethodId* const mid_;
+  // Lazily computed name from the dex file's strings.
+  const char* name_;
+  // Lazily computed name length.
+  uint32_t name_len_;
+};
+
+class LinkVirtualHashTable {
+ public:
+  LinkVirtualHashTable(Handle<mirror::Class> klass, size_t hash_size, uint32_t* hash_table)
+     : klass_(klass), hash_size_(hash_size), hash_table_(hash_table) {
+    std::fill(hash_table_, hash_table_ + hash_size_, invalid_index_);
+  }
+  void Add(uint32_t virtual_method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* local_method = klass_->GetVirtualMethodDuringLinking(virtual_method_index);
+    const char* name = local_method->GetName();
+    uint32_t hash = ComputeModifiedUtf8Hash(name);
+    uint32_t index = hash % hash_size_;
+    // Linear probe until we have an empty slot.
+    while (hash_table_[index] != invalid_index_) {
+      if (++index == hash_size_) {
+        index = 0;
+      }
+    }
+    hash_table_[index] = virtual_method_index;
+  }
+  uint32_t FindAndRemove(MethodNameAndSignatureComparator* comparator)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    const char* name = comparator->GetName();
+    uint32_t hash = ComputeModifiedUtf8Hash(name);
+    size_t index = hash % hash_size_;
+    while (true) {
+      const uint32_t value = hash_table_[index];
+      // Since linear probe makes continuous blocks, hitting an invalid index means we are done
+      // the block and can safely assume not found.
+      if (value == invalid_index_) {
+        break;
+      }
+      if (value != removed_index_) {  // This signifies not already overriden.
+        mirror::ArtMethod* virtual_method =
+            klass_->GetVirtualMethodDuringLinking(value);
+        if (comparator->HasSameNameAndSignature(virtual_method->GetInterfaceMethodIfProxy())) {
+          hash_table_[index] = removed_index_;
+          return value;
+        }
+      }
+      if (++index == hash_size_) {
+        index = 0;
+      }
+    }
+    return GetNotFoundIndex();
+  }
+  static uint32_t GetNotFoundIndex() {
+    return invalid_index_;
+  }
+
+ private:
+  static const uint32_t invalid_index_;
+  static const uint32_t removed_index_;
+
+  Handle<mirror::Class> klass_;
+  const size_t hash_size_;
+  uint32_t* const hash_table_;
+};
+
+const uint32_t LinkVirtualHashTable::invalid_index_ = std::numeric_limits<uint32_t>::max();
+const uint32_t LinkVirtualHashTable::removed_index_ = std::numeric_limits<uint32_t>::max() - 1;
+
 bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) {
+  const size_t num_virtual_methods = klass->NumVirtualMethods();
   if (klass->HasSuperClass()) {
-    uint32_t max_count = klass->NumVirtualMethods() +
-        klass->GetSuperClass()->GetVTableLength();
-    size_t actual_count = klass->GetSuperClass()->GetVTableLength();
-    CHECK_LE(actual_count, max_count);
-    StackHandleScope<4> hs(self);
+    const size_t super_vtable_length = klass->GetSuperClass()->GetVTableLength();
+    const size_t max_count = num_virtual_methods + super_vtable_length;
+    StackHandleScope<2> hs(self);
     Handle<mirror::Class> super_class(hs.NewHandle(klass->GetSuperClass()));
     MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable;
     if (super_class->ShouldHaveEmbeddedImtAndVTable()) {
@@ -4649,54 +4908,90 @@
         CHECK(self->IsExceptionPending());  // OOME.
         return false;
       }
-      int len = super_class->GetVTableLength();
-      for (int i = 0; i < len; i++) {
-        vtable->Set<false>(i, super_class->GetVTableEntry(i));
+      for (size_t i = 0; i < super_vtable_length; i++) {
+        vtable->SetWithoutChecks<false>(i, super_class->GetEmbeddedVTableEntry(i));
+      }
+      if (num_virtual_methods == 0) {
+        klass->SetVTable(vtable.Get());
+        return true;
       }
     } else {
-      CHECK(super_class->GetVTable() != nullptr) << PrettyClass(super_class.Get());
-      vtable = hs.NewHandle(super_class->GetVTable()->CopyOf(self, max_count));
+      mirror::ObjectArray<mirror::ArtMethod>* super_vtable = super_class->GetVTable();
+      CHECK(super_vtable != nullptr) << PrettyClass(super_class.Get());
+      if (num_virtual_methods == 0) {
+        klass->SetVTable(super_vtable);
+        return true;
+      }
+      vtable = hs.NewHandle(super_vtable->CopyOf(self, max_count));
       if (UNLIKELY(vtable.Get() == nullptr)) {
         CHECK(self->IsExceptionPending());  // OOME.
         return false;
       }
     }
-
-    // See if any of our virtual methods override the superclass.
-    MutableMethodHelper local_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-    MutableMethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-    for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
-      mirror::ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i);
-      local_mh.ChangeMethod(local_method);
-      size_t j = 0;
-      for (; j < actual_count; ++j) {
-        mirror::ArtMethod* super_method = vtable->Get(j);
-        super_mh.ChangeMethod(super_method);
-        if (local_mh.HasSameNameAndSignature(&super_mh)) {
-          if (klass->CanAccessMember(super_method->GetDeclaringClass(),
-                                     super_method->GetAccessFlags())) {
-            if (super_method->IsFinal()) {
-              ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
-                                PrettyMethod(local_method).c_str(),
-                                super_method->GetDeclaringClassDescriptor());
-              return false;
-            }
-            vtable->Set<false>(j, local_method);
-            local_method->SetMethodIndex(j);
-            break;
-          } else {
-            LOG(WARNING) << "Before Android 4.1, method " << PrettyMethod(local_method)
-                         << " would have incorrectly overridden the package-private method in "
-                         << PrettyDescriptor(super_method->GetDeclaringClassDescriptor());
+    // How the algorithm works:
+    // 1. Populate hash table by adding num_virtual_methods from klass. The values in the hash
+    // table are: invalid_index for unused slots, index super_vtable_length + i for a virtual
+    // method which has not been matched to a vtable method, and j if the virtual method at the
+    // index overrode the super virtual method at index j.
+    // 2. Loop through super virtual methods, if they overwrite, update hash table to j
+    // (j < super_vtable_length) to avoid redundant checks. (TODO maybe use this info for reducing
+    // the need for the initial vtable which we later shrink back down).
+    // 3. Add non overridden methods to the end of the vtable.
+    static constexpr size_t kMaxStackHash = 250;
+    const size_t hash_table_size = num_virtual_methods * 3;
+    uint32_t* hash_table_ptr;
+    std::unique_ptr<uint32_t[]> hash_heap_storage;
+    if (hash_table_size <= kMaxStackHash) {
+      hash_table_ptr = reinterpret_cast<uint32_t*>(
+          alloca(hash_table_size * sizeof(*hash_table_ptr)));
+    } else {
+      hash_heap_storage.reset(new uint32_t[hash_table_size]);
+      hash_table_ptr = hash_heap_storage.get();
+    }
+    LinkVirtualHashTable hash_table(klass, hash_table_size, hash_table_ptr);
+    // Add virtual methods to the hash table.
+    for (size_t i = 0; i < num_virtual_methods; ++i) {
+      hash_table.Add(i);
+    }
+    // Loop through each super vtable method and see if they are overriden by a method we added to
+    // the hash table.
+    for (size_t j = 0; j < super_vtable_length; ++j) {
+      // Search the hash table to see if we are overidden by any method.
+      mirror::ArtMethod* super_method = vtable->GetWithoutChecks(j);
+      MethodNameAndSignatureComparator super_method_name_comparator(
+          super_method->GetInterfaceMethodIfProxy());
+      uint32_t hash_index = hash_table.FindAndRemove(&super_method_name_comparator);
+      if (hash_index != hash_table.GetNotFoundIndex()) {
+        mirror::ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(hash_index);
+        if (klass->CanAccessMember(super_method->GetDeclaringClass(),
+                                   super_method->GetAccessFlags())) {
+          if (super_method->IsFinal()) {
+            ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
+                              PrettyMethod(virtual_method).c_str(),
+                              super_method->GetDeclaringClassDescriptor());
+            return false;
           }
+          vtable->SetWithoutChecks<false>(j, virtual_method);
+          virtual_method->SetMethodIndex(j);
+        } else {
+          LOG(WARNING) << "Before Android 4.1, method " << PrettyMethod(virtual_method)
+                       << " would have incorrectly overridden the package-private method in "
+                       << PrettyDescriptor(super_method->GetDeclaringClassDescriptor());
         }
       }
-      if (j == actual_count) {
-        // Not overriding, append.
-        vtable->Set<false>(actual_count, local_method);
-        local_method->SetMethodIndex(actual_count);
-        actual_count += 1;
+    }
+    // Add the non overridden methods at the end.
+    size_t actual_count = super_vtable_length;
+    for (size_t i = 0; i < num_virtual_methods; ++i) {
+      mirror::ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i);
+      size_t method_idx = local_method->GetMethodIndexDuringLinking();
+      if (method_idx < super_vtable_length &&
+          local_method == vtable->GetWithoutChecks(method_idx)) {
+        continue;
       }
+      vtable->SetWithoutChecks<false>(actual_count, local_method);
+      local_method->SetMethodIndex(actual_count);
+      ++actual_count;
     }
     if (!IsUint(16, actual_count)) {
       ThrowClassFormatError(klass.Get(), "Too many methods defined on class: %zd", actual_count);
@@ -4714,72 +5009,72 @@
     klass->SetVTable(vtable.Get());
   } else {
     CHECK_EQ(klass.Get(), GetClassRoot(kJavaLangObject));
-    uint32_t num_virtual_methods = klass->NumVirtualMethods();
     if (!IsUint(16, num_virtual_methods)) {
-      ThrowClassFormatError(klass.Get(), "Too many methods: %d", num_virtual_methods);
+      ThrowClassFormatError(klass.Get(), "Too many methods: %d",
+                            static_cast<int>(num_virtual_methods));
       return false;
     }
-    StackHandleScope<1> hs(self);
-    Handle<mirror::ObjectArray<mirror::ArtMethod>>
-        vtable(hs.NewHandle(AllocArtMethodArray(self, num_virtual_methods)));
-    if (UNLIKELY(vtable.Get() == nullptr)) {
+    mirror::ObjectArray<mirror::ArtMethod>* vtable = AllocArtMethodArray(self, num_virtual_methods);
+    if (UNLIKELY(vtable == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
     for (size_t i = 0; i < num_virtual_methods; ++i) {
       mirror::ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i);
-      vtable->Set<false>(i, virtual_method);
+      vtable->SetWithoutChecks<false>(i, virtual_method);
       virtual_method->SetMethodIndex(i & 0xFFFF);
     }
-    klass->SetVTable(vtable.Get());
+    klass->SetVTable(vtable);
   }
   return true;
 }
 
-bool ClassLinker::LinkInterfaceMethods(Handle<mirror::Class> klass,
-                                       Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
-  Thread* const self = Thread::Current();
+bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass,
+                                       Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                                       StackHandleScope<mirror::Class::kImtSize>* out_imt) {
+  StackHandleScope<3> hs(self);
   Runtime* const runtime = Runtime::Current();
-  // Set the imt table to be all conflicts by default.
-  klass->SetImTable(runtime->GetDefaultImt());
-  size_t super_ifcount;
-  if (klass->HasSuperClass()) {
-    super_ifcount = klass->GetSuperClass()->GetIfTableCount();
-  } else {
-    super_ifcount = 0;
-  }
-  uint32_t num_interfaces =
-      interfaces.Get() == nullptr ? klass->NumDirectInterfaces() : interfaces->GetLength();
-  size_t ifcount = super_ifcount + num_interfaces;
-  for (size_t i = 0; i < num_interfaces; i++) {
-    mirror::Class* interface =
-        interfaces.Get() == nullptr ? mirror::Class::GetDirectInterface(self, klass, i) :
-            interfaces->Get(i);
-    ifcount += interface->GetIfTableCount();
-  }
-  if (ifcount == 0) {
-    // Class implements no interfaces.
-    DCHECK_EQ(klass->GetIfTableCount(), 0);
-    DCHECK(klass->GetIfTable() == nullptr);
-    return true;
-  }
-  if (ifcount == super_ifcount) {
+  const bool has_superclass = klass->HasSuperClass();
+  const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U;
+  const bool have_interfaces = interfaces.Get() != nullptr;
+  const size_t num_interfaces =
+      have_interfaces ? interfaces->GetLength() : klass->NumDirectInterfaces();
+  if (num_interfaces == 0) {
+    if (super_ifcount == 0) {
+      // Class implements no interfaces.
+      DCHECK_EQ(klass->GetIfTableCount(), 0);
+      DCHECK(klass->GetIfTable() == nullptr);
+      return true;
+    }
     // Class implements same interfaces as parent, are any of these not marker interfaces?
     bool has_non_marker_interface = false;
     mirror::IfTable* super_iftable = klass->GetSuperClass()->GetIfTable();
-    for (size_t i = 0; i < ifcount; ++i) {
+    for (size_t i = 0; i < super_ifcount; ++i) {
       if (super_iftable->GetMethodArrayCount(i) > 0) {
         has_non_marker_interface = true;
         break;
       }
     }
+    // Class just inherits marker interfaces from parent so recycle parent's iftable.
     if (!has_non_marker_interface) {
-      // Class just inherits marker interfaces from parent so recycle parent's iftable.
       klass->SetIfTable(super_iftable);
       return true;
     }
   }
-  StackHandleScope<5> hs(self);
+  size_t ifcount = super_ifcount + num_interfaces;
+  for (size_t i = 0; i < num_interfaces; i++) {
+    mirror::Class* interface = have_interfaces ?
+        interfaces->GetWithoutChecks(i) : mirror::Class::GetDirectInterface(self, klass, i);
+    DCHECK(interface != nullptr);
+    if (UNLIKELY(!interface->IsInterface())) {
+      std::string temp;
+      ThrowIncompatibleClassChangeError(klass.Get(), "Class %s implements non-interface class %s",
+                                        PrettyDescriptor(klass.Get()).c_str(),
+                                        PrettyDescriptor(interface->GetDescriptor(&temp)).c_str());
+      return false;
+    }
+    ifcount += interface->GetIfTableCount();
+  }
   MutableHandle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
   if (UNLIKELY(iftable.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
@@ -4796,17 +5091,8 @@
   // Flatten the interface inheritance hierarchy.
   size_t idx = super_ifcount;
   for (size_t i = 0; i < num_interfaces; i++) {
-    mirror::Class* interface =
-        interfaces.Get() == nullptr ? mirror::Class::GetDirectInterface(self, klass, i) :
-            interfaces->Get(i);
-    DCHECK(interface != nullptr);
-    if (!interface->IsInterface()) {
-      std::string temp;
-      ThrowIncompatibleClassChangeError(klass.Get(), "Class %s implements non-interface class %s",
-                                        PrettyDescriptor(klass.Get()).c_str(),
-                                        PrettyDescriptor(interface->GetDescriptor(&temp)).c_str());
-      return false;
-    }
+    mirror::Class* interface = have_interfaces ? interfaces->Get(i) :
+        mirror::Class::GetDirectInterface(self, klass, i);
     // Check if interface is already in iftable
     bool duplicate = false;
     for (size_t j = 0; j < idx; j++) {
@@ -4839,6 +5125,7 @@
   self->AllowThreadSuspension();
   // Shrink iftable in case duplicates were found
   if (idx < ifcount) {
+    DCHECK_NE(num_interfaces, 0U);
     iftable.Assign(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax)));
     if (UNLIKELY(iftable.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
@@ -4846,48 +5133,101 @@
     }
     ifcount = idx;
   } else {
-    CHECK_EQ(idx, ifcount);
+    DCHECK_EQ(idx, ifcount);
   }
   klass->SetIfTable(iftable.Get());
-
   // If we're an interface, we don't need the vtable pointers, so we're done.
   if (klass->IsInterface()) {
     return true;
   }
-  self->AllowThreadSuspension();
-  // Allocate imtable
-  bool imtable_changed = false;
-  Handle<mirror::ObjectArray<mirror::ArtMethod>> imtable(
-      hs.NewHandle(AllocArtMethodArray(self, mirror::Class::kImtSize)));
-  if (UNLIKELY(imtable.Get() == nullptr)) {
-    CHECK(self->IsExceptionPending());  // OOME.
-    return false;
-  }
-  MutableMethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-  MutableMethodHelper vtable_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  size_t miranda_list_size = 0;
   size_t max_miranda_methods = 0;  // The max size of miranda_list.
   for (size_t i = 0; i < ifcount; ++i) {
     max_miranda_methods += iftable->GetInterface(i)->NumVirtualMethods();
   }
-  Handle<mirror::ObjectArray<mirror::ArtMethod>>
+  MutableHandle<mirror::ObjectArray<mirror::ArtMethod>>
       miranda_list(hs.NewHandle(AllocArtMethodArray(self, max_miranda_methods)));
-  size_t miranda_list_size = 0;  // The current size of miranda_list.
+  MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
+      hs.NewHandle(klass->GetVTableDuringLinking()));
+  // Copy the IMT from the super class if possible.
+  bool extend_super_iftable = false;
+  if (has_superclass) {
+    mirror::Class* super_class = klass->GetSuperClass();
+    extend_super_iftable = true;
+    if (super_class->ShouldHaveEmbeddedImtAndVTable()) {
+      for (size_t i = 0; i < mirror::Class::kImtSize; ++i) {
+        out_imt->SetReference(i, super_class->GetEmbeddedImTableEntry(i));
+      }
+    } else {
+      // No imt in the super class, need to reconstruct from the iftable.
+      mirror::IfTable* if_table = super_class->GetIfTable();
+      mirror::ArtMethod* conflict_method = runtime->GetImtConflictMethod();
+      const size_t length = super_class->GetIfTableCount();
+      for (size_t i = 0; i < length; ++i) {
+        mirror::Class* interface = iftable->GetInterface(i);
+        const size_t num_virtuals = interface->NumVirtualMethods();
+        const size_t method_array_count = if_table->GetMethodArrayCount(i);
+        DCHECK_EQ(num_virtuals, method_array_count);
+        if (method_array_count == 0) {
+          continue;
+        }
+        mirror::ObjectArray<mirror::ArtMethod>* method_array = if_table->GetMethodArray(i);
+        for (size_t j = 0; j < num_virtuals; ++j) {
+          mirror::ArtMethod* method = method_array->GetWithoutChecks(j);
+          if (method->IsMiranda()) {
+            continue;
+          }
+          mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j);
+          uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
+          mirror::ArtMethod* imt_ref = out_imt->GetReference(imt_index)->AsArtMethod();
+          if (imt_ref == runtime->GetImtUnimplementedMethod()) {
+            out_imt->SetReference(imt_index, method);
+          } else if (imt_ref != conflict_method) {
+            out_imt->SetReference(imt_index, conflict_method);
+          }
+        }
+      }
+    }
+  }
   for (size_t i = 0; i < ifcount; ++i) {
     self->AllowThreadSuspension();
     size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
     if (num_methods > 0) {
-      StackHandleScope<2> hs(self);
-      Handle<mirror::ObjectArray<mirror::ArtMethod>>
-          method_array(hs.NewHandle(AllocArtMethodArray(self, num_methods)));
+      StackHandleScope<2> hs2(self);
+      const bool is_super = i < super_ifcount;
+      const bool super_interface = is_super && extend_super_iftable;
+      Handle<mirror::ObjectArray<mirror::ArtMethod>> method_array;
+      Handle<mirror::ObjectArray<mirror::ArtMethod>> input_array;
+      if (super_interface) {
+        mirror::IfTable* if_table = klass->GetSuperClass()->GetIfTable();
+        DCHECK(if_table != nullptr);
+        DCHECK(if_table->GetMethodArray(i) != nullptr);
+        // If we are working on a super interface, try extending the existing method array.
+        method_array = hs2.NewHandle(if_table->GetMethodArray(i)->Clone(self)->
+            AsObjectArray<mirror::ArtMethod>());
+        // We are overwriting a super class interface, try to only virtual methods instead of the
+        // whole vtable.
+        input_array = hs2.NewHandle(klass->GetVirtualMethods());
+      } else {
+        method_array = hs2.NewHandle(AllocArtMethodArray(self, num_methods));
+        // A new interface, we need the whole vtable incase a new interface method is implemented
+        // in the whole superclass.
+        input_array = vtable;
+      }
       if (UNLIKELY(method_array.Get() == nullptr)) {
         CHECK(self->IsExceptionPending());  // OOME.
         return false;
       }
       iftable->SetMethodArray(i, method_array.Get());
-      Handle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
-          hs.NewHandle(klass->GetVTableDuringLinking()));
+      if (input_array.Get() == nullptr) {
+        // If the added virtual methods is empty, do nothing.
+        DCHECK(super_interface);
+        continue;
+      }
       for (size_t j = 0; j < num_methods; ++j) {
-        interface_mh.ChangeMethod(iftable->GetInterface(i)->GetVirtualMethod(j));
+        mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j);
+        MethodNameAndSignatureComparator interface_name_comparator(
+            interface_method->GetInterfaceMethodIfProxy());
         int32_t k;
         // For each method listed in the interface's method list, find the
         // matching method in our class's method list.  We want to favor the
@@ -4897,66 +5237,66 @@
         // it -- otherwise it would use the same vtable slot.  In .dex files
         // those don't end up in the virtual method table, so it shouldn't
         // matter which direction we go.  We walk it backward anyway.)
-        for (k = vtable->GetLength() - 1; k >= 0; --k) {
-          vtable_mh.ChangeMethod(vtable->Get(k));
-          if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-            if (!vtable_mh.Get()->IsAbstract() && !vtable_mh.Get()->IsPublic()) {
+        for (k = input_array->GetLength() - 1; k >= 0; --k) {
+          mirror::ArtMethod* vtable_method = input_array->GetWithoutChecks(k);
+          mirror::ArtMethod* vtable_method_for_name_comparison =
+              vtable_method->GetInterfaceMethodIfProxy();
+          if (interface_name_comparator.HasSameNameAndSignature(
+              vtable_method_for_name_comparison)) {
+            if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
               ThrowIllegalAccessError(
                   klass.Get(),
                   "Method '%s' implementing interface method '%s' is not public",
-                  PrettyMethod(vtable_mh.Get()).c_str(),
-                  PrettyMethod(interface_mh.Get()).c_str());
+                  PrettyMethod(vtable_method).c_str(),
+                  PrettyMethod(interface_method).c_str());
               return false;
             }
-            method_array->Set<false>(j, vtable_mh.Get());
+            method_array->SetWithoutChecks<false>(j, vtable_method);
             // Place method in imt if entry is empty, place conflict otherwise.
-            uint32_t imt_index = interface_mh.Get()->GetDexMethodIndex() % mirror::Class::kImtSize;
-            if (imtable->Get(imt_index) == nullptr) {
-              imtable->Set<false>(imt_index, vtable_mh.Get());
-              imtable_changed = true;
-            } else {
-              imtable->Set<false>(imt_index, runtime->GetImtConflictMethod());
+            uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
+            mirror::ArtMethod* imt_ref = out_imt->GetReference(imt_index)->AsArtMethod();
+            mirror::ArtMethod* conflict_method = runtime->GetImtConflictMethod();
+            if (imt_ref == runtime->GetImtUnimplementedMethod()) {
+              out_imt->SetReference(imt_index, vtable_method);
+            } else if (imt_ref != conflict_method) {
+              // If we are not a conflict and we have the same signature and name as the imt entry,
+              // it must be that we overwrote a superclass vtable entry.
+              MethodNameAndSignatureComparator imt_ref_name_comparator(
+                  imt_ref->GetInterfaceMethodIfProxy());
+              if (imt_ref_name_comparator.HasSameNameAndSignature(
+                  vtable_method_for_name_comparison)) {
+                out_imt->SetReference(imt_index, vtable_method);
+              } else {
+                out_imt->SetReference(imt_index, conflict_method);
+              }
             }
             break;
           }
         }
-        if (k < 0) {
-          StackHandleScope<1> hs(self);
-          auto miranda_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
+        if (k < 0 && !super_interface) {
+          mirror::ArtMethod* miranda_method = nullptr;
           for (size_t l = 0; l < miranda_list_size; ++l) {
             mirror::ArtMethod* mir_method = miranda_list->Get(l);
-            DCHECK(mir_method != nullptr);
-            vtable_mh.ChangeMethod(mir_method);
-            if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-              miranda_method.Assign(mir_method);
+            if (interface_name_comparator.HasSameNameAndSignature(mir_method)) {
+              miranda_method = mir_method;
               break;
             }
           }
-          if (miranda_method.Get() == nullptr) {
+          if (miranda_method == nullptr) {
             // Point the interface table at a phantom slot.
-            miranda_method.Assign(down_cast<mirror::ArtMethod*>(interface_mh.Get()->Clone(self)));
-            if (UNLIKELY(miranda_method.Get() == nullptr)) {
+            miranda_method = interface_method->Clone(self)->AsArtMethod();
+            if (UNLIKELY(miranda_method == nullptr)) {
               CHECK(self->IsExceptionPending());  // OOME.
               return false;
             }
             DCHECK_LT(miranda_list_size, max_miranda_methods);
-            miranda_list->Set<false>(miranda_list_size++, miranda_method.Get());
+            miranda_list->Set<false>(miranda_list_size++, miranda_method);
           }
-          method_array->Set<false>(j, miranda_method.Get());
+          method_array->SetWithoutChecks<false>(j, miranda_method);
         }
       }
     }
   }
-  if (imtable_changed) {
-    // Fill in empty entries in interface method table with conflict.
-    mirror::ArtMethod* imt_conflict_method = runtime->GetImtConflictMethod();
-    for (size_t i = 0; i < mirror::Class::kImtSize; i++) {
-      if (imtable->Get(i) == nullptr) {
-        imtable->Set<false>(i, imt_conflict_method);
-      }
-    }
-    klass->SetImTable(imtable.Get());
-  }
   if (miranda_list_size > 0) {
     int old_method_count = klass->NumVirtualMethods();
     int new_method_count = old_method_count + miranda_list_size;
@@ -4972,10 +5312,6 @@
     }
     klass->SetVirtualMethods(virtuals);
 
-    StackHandleScope<1> hs(self);
-    MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
-        hs.NewHandle(klass->GetVTableDuringLinking()));
-    CHECK(vtable.Get() != nullptr);
     int old_vtable_count = vtable->GetLength();
     int new_vtable_count = old_vtable_count + miranda_list_size;
     vtable.Assign(vtable->CopyOf(self, new_vtable_count));
@@ -4989,19 +5325,20 @@
       method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda);
       method->SetMethodIndex(0xFFFF & (old_vtable_count + i));
       klass->SetVirtualMethod(old_method_count + i, method);
-      vtable->Set<false>(old_vtable_count + i, method);
+      vtable->SetWithoutChecks<false>(old_vtable_count + i, method);
     }
     // TODO: do not assign to the vtable field until it is fully constructed.
     klass->SetVTable(vtable.Get());
   }
 
-  mirror::ObjectArray<mirror::ArtMethod>* vtable = klass->GetVTableDuringLinking();
-  for (int i = 0; i < vtable->GetLength(); ++i) {
-    CHECK(vtable->Get(i) != nullptr);
+  if (kIsDebugBuild) {
+    mirror::ObjectArray<mirror::ArtMethod>* check_vtable = klass->GetVTableDuringLinking();
+    for (int i = 0; i < check_vtable->GetLength(); ++i) {
+      CHECK(check_vtable->GetWithoutChecks(i) != nullptr);
+    }
   }
 
   self->AllowThreadSuspension();
-
   return true;
 }
 
@@ -5025,20 +5362,27 @@
     Primitive::Type type1 = field1->GetTypeAsPrimitiveType();
     Primitive::Type type2 = field2->GetTypeAsPrimitiveType();
     if (type1 != type2) {
-      bool is_primitive1 = type1 != Primitive::kPrimNot;
-      bool is_primitive2 = type2 != Primitive::kPrimNot;
-      if (type1 != type2) {
-        if (is_primitive1 && is_primitive2) {
-          // Larger primitive types go first.
-          return Primitive::ComponentSize(type1) > Primitive::ComponentSize(type2);
-        } else {
-          // Reference always goes first.
-          return !is_primitive1;
-        }
+      if (type1 == Primitive::kPrimNot) {
+        // Reference always goes first.
+        return true;
       }
+      if (type2 == Primitive::kPrimNot) {
+        // Reference always goes first.
+        return false;
+      }
+      size_t size1 = Primitive::ComponentSize(type1);
+      size_t size2 = Primitive::ComponentSize(type2);
+      if (size1 != size2) {
+        // Larger primitive types go first.
+        return size1 > size2;
+      }
+      // Primitive types differ but sizes match. Arbitrarily order by primitive type.
+      return type1 < type2;
     }
-    // same basic group? then sort by string.
-    return strcmp(field1->GetName(), field2->GetName()) < 0;
+    // Same basic group? Then sort by dex field index. This is guaranteed to be sorted
+    // by name and for equal names by type id index.
+    // NOTE: This works also for proxies. Their static fields are assigned appropriate indexes.
+    return field1->GetDexFieldIndex() < field2->GetDexFieldIndex();
   }
 };
 
@@ -5054,13 +5398,7 @@
   // Initialize field_offset
   MemberOffset field_offset(0);
   if (is_static) {
-    uint32_t base = sizeof(mirror::Class);  // Static fields come after the class.
-    if (klass->ShouldHaveEmbeddedImtAndVTable()) {
-      // Static fields come after the embedded tables.
-      base = mirror::Class::ComputeClassSize(true, klass->GetVTableDuringLinking()->GetLength(),
-                                             0, 0, 0, 0, 0);
-    }
-    field_offset = MemberOffset(base);
+    field_offset = klass->GetFirstReferenceStaticFieldOffsetDuringLinking();
   } else {
     mirror::Class* super_class = klass->GetSuperClass();
     if (super_class != nullptr) {
@@ -5097,28 +5435,25 @@
     if (isPrimitive) {
       break;  // past last reference, move on to the next phase
     }
-    if (UNLIKELY(!IsAligned<4>(field_offset.Uint32Value()))) {
+    if (UNLIKELY(!IsAligned<sizeof(mirror::HeapReference<mirror::Object>)>(
+        field_offset.Uint32Value()))) {
       MemberOffset old_offset = field_offset;
       field_offset = MemberOffset(RoundUp(field_offset.Uint32Value(), 4));
       AddFieldGap(old_offset.Uint32Value(), field_offset.Uint32Value(), &gaps);
     }
-    DCHECK(IsAligned<4>(field_offset.Uint32Value()));
+    DCHECK(IsAligned<sizeof(mirror::HeapReference<mirror::Object>)>(field_offset.Uint32Value()));
     grouped_and_sorted_fields.pop_front();
     num_reference_fields++;
-    fields->Set<false>(current_field, field);
     field->SetOffset(field_offset);
-    field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t));
+    field_offset = MemberOffset(field_offset.Uint32Value() +
+                                sizeof(mirror::HeapReference<mirror::Object>));
   }
   // Gaps are stored as a max heap which means that we must shuffle from largest to smallest
   // otherwise we could end up with suboptimal gap fills.
-  ShuffleForward<8>(num_fields, &current_field, &field_offset,
-                    fields, &grouped_and_sorted_fields, &gaps);
-  ShuffleForward<4>(num_fields, &current_field, &field_offset,
-                    fields, &grouped_and_sorted_fields, &gaps);
-  ShuffleForward<2>(num_fields, &current_field, &field_offset,
-                    fields, &grouped_and_sorted_fields, &gaps);
-  ShuffleForward<1>(num_fields, &current_field, &field_offset,
-                    fields, &grouped_and_sorted_fields, &gaps);
+  ShuffleForward<8>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);
+  ShuffleForward<4>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);
+  ShuffleForward<2>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);
+  ShuffleForward<1>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);
   CHECK(grouped_and_sorted_fields.empty()) << "Missed " << grouped_and_sorted_fields.size() <<
       " fields.";
   self->EndAssertNoThreadSuspension(old_no_suspend_cause);
@@ -5132,39 +5467,6 @@
     --num_reference_fields;
   }
 
-  if (kIsDebugBuild) {
-    // Make sure that all reference fields appear before
-    // non-reference fields, and all double-wide fields are aligned.
-    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
-        LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
-                    << " class=" << PrettyClass(klass.Get())
-                    << " field=" << PrettyField(field)
-                    << " offset="
-                    << field->GetField32(MemberOffset(mirror::ArtField::OffsetOffset()));
-      }
-      Primitive::Type type = field->GetTypeAsPrimitiveType();
-      bool is_primitive = type != Primitive::kPrimNot;
-      if (klass->DescriptorEquals("Ljava/lang/ref/Reference;") &&
-          strcmp("referent", field->GetName()) == 0) {
-        is_primitive = true;  // We lied above, so we have to expect a lie here.
-      }
-      if (is_primitive) {
-        if (!seen_non_ref) {
-          seen_non_ref = true;
-          DCHECK_EQ(num_reference_fields, i) << PrettyField(field);
-        }
-      } else {
-        DCHECK(!seen_non_ref) << PrettyField(field);
-      }
-    }
-    if (!seen_non_ref) {
-      DCHECK_EQ(num_fields, num_reference_fields) << PrettyClass(klass.Get());
-    }
-  }
-
   size_t size = field_offset.Uint32Value();
   // Update klass
   if (is_static) {
@@ -5173,54 +5475,97 @@
   } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
     if (!klass->IsVariableSize()) {
-      std::string temp;
-      DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);
-      size_t previous_size = klass->GetObjectSize();
-      if (previous_size != 0) {
-        // Make sure that we didn't originally have an incorrect size.
-        CHECK_EQ(previous_size, size) << klass->GetDescriptor(&temp);
+      if (klass->DescriptorEquals("Ljava/lang/reflect/ArtMethod;")) {
+        klass->SetObjectSize(mirror::ArtMethod::InstanceSize(sizeof(void*)));
+      } else {
+        std::string temp;
+        DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);
+        size_t previous_size = klass->GetObjectSize();
+        if (previous_size != 0) {
+          // Make sure that we didn't originally have an incorrect size.
+          CHECK_EQ(previous_size, size) << klass->GetDescriptor(&temp);
+        }
+        klass->SetObjectSize(size);
       }
-      klass->SetObjectSize(size);
     }
   }
+
+  if (kIsDebugBuild) {
+    // Make sure that the fields array is ordered by name but all reference
+    // offsets are at the beginning as far as alignment allows.
+    MemberOffset start_ref_offset = is_static
+        ? klass->GetFirstReferenceStaticFieldOffsetDuringLinking()
+        : klass->GetFirstReferenceInstanceFieldOffset();
+    MemberOffset end_ref_offset(start_ref_offset.Uint32Value() +
+                                num_reference_fields *
+                                    sizeof(mirror::HeapReference<mirror::Object>));
+    MemberOffset current_ref_offset = start_ref_offset;
+    for (size_t i = 0; i < num_fields; i++) {
+      mirror::ArtField* field = fields->Get(i);
+      if ((false)) {  // enable to debug field layout
+        LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
+                    << " class=" << PrettyClass(klass.Get())
+                    << " field=" << PrettyField(field)
+                    << " offset="
+                    << field->GetField32(mirror::ArtField::OffsetOffset());
+      }
+      if (i != 0) {
+        mirror::ArtField* prev_field = fields->Get(i - 1u);
+        // NOTE: The field names can be the same. This is not possible in the Java language
+        // but it's valid Java/dex bytecode and for example proguard can generate such bytecode.
+        CHECK_LE(strcmp(prev_field->GetName(), field->GetName()), 0);
+      }
+      Primitive::Type type = field->GetTypeAsPrimitiveType();
+      bool is_primitive = type != Primitive::kPrimNot;
+      if (klass->DescriptorEquals("Ljava/lang/ref/Reference;") &&
+          strcmp("referent", field->GetName()) == 0) {
+        is_primitive = true;  // We lied above, so we have to expect a lie here.
+      }
+      MemberOffset offset = field->GetOffsetDuringLinking();
+      if (is_primitive) {
+        if (offset.Uint32Value() < end_ref_offset.Uint32Value()) {
+          // Shuffled before references.
+          size_t type_size = Primitive::ComponentSize(type);
+          CHECK_LT(type_size, sizeof(mirror::HeapReference<mirror::Object>));
+          CHECK_LT(offset.Uint32Value(), start_ref_offset.Uint32Value());
+          CHECK_LE(offset.Uint32Value() + type_size, start_ref_offset.Uint32Value());
+          CHECK(!IsAligned<sizeof(mirror::HeapReference<mirror::Object>)>(offset.Uint32Value()));
+        }
+      } else {
+        CHECK_EQ(current_ref_offset.Uint32Value(), offset.Uint32Value());
+        current_ref_offset = MemberOffset(current_ref_offset.Uint32Value() +
+                                          sizeof(mirror::HeapReference<mirror::Object>));
+      }
+    }
+    CHECK_EQ(current_ref_offset.Uint32Value(), end_ref_offset.Uint32Value());
+  }
   return true;
 }
 
-//  Set the bitmap of reference offsets, refOffsets, from the ifields
-//  list.
+//  Set the bitmap of reference instance field offsets.
 void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) {
   uint32_t reference_offsets = 0;
   mirror::Class* super_class = klass->GetSuperClass();
+  // Leave the reference offsets as 0 for mirror::Object (the class field is handled specially).
   if (super_class != nullptr) {
     reference_offsets = super_class->GetReferenceInstanceOffsets();
-    // If our superclass overflowed, we don't stand a chance.
-    if (reference_offsets == CLASS_WALK_SUPER) {
-      klass->SetReferenceInstanceOffsets(reference_offsets);
-      return;
-    }
-  }
-  CreateReferenceOffsets(klass, reference_offsets);
-}
-
-void ClassLinker::CreateReferenceOffsets(Handle<mirror::Class> klass,
-                                         uint32_t reference_offsets) {
-  size_t num_reference_fields = klass->NumReferenceInstanceFieldsDuringLinking();
-  mirror::ObjectArray<mirror::ArtField>* fields = klass->GetIFields();
-  // All of the fields that contain object references are guaranteed
-  // to be at the beginning of the fields list.
-  for (size_t i = 0; i < num_reference_fields; ++i) {
-    // Note that byte_offset is the offset from the beginning of
-    // object, not the offset into instance data
-    mirror::ArtField* field = fields->Get(i);
-    MemberOffset byte_offset = field->GetOffsetDuringLinking();
-    CHECK_EQ(byte_offset.Uint32Value() & (CLASS_OFFSET_ALIGNMENT - 1), 0U);
-    if (CLASS_CAN_ENCODE_OFFSET(byte_offset.Uint32Value())) {
-      uint32_t new_bit = CLASS_BIT_FROM_OFFSET(byte_offset.Uint32Value());
-      CHECK_NE(new_bit, 0U);
-      reference_offsets |= new_bit;
-    } else {
-      reference_offsets = CLASS_WALK_SUPER;
-      break;
+    // Compute reference offsets unless our superclass overflowed.
+    if (reference_offsets != mirror::Class::kClassWalkSuper) {
+      size_t num_reference_fields = klass->NumReferenceInstanceFieldsDuringLinking();
+      if (num_reference_fields != 0u) {
+        // All of the fields that contain object references are guaranteed be grouped in memory
+        // starting at an appropriately aligned address after super class object data.
+        uint32_t start_offset = RoundUp(super_class->GetObjectSize(),
+                                        sizeof(mirror::HeapReference<mirror::Object>));
+        uint32_t start_bit = (start_offset - mirror::kObjectHeaderSize) /
+            sizeof(mirror::HeapReference<mirror::Object>);
+        if (start_bit + num_reference_fields > 32) {
+          reference_offsets = mirror::Class::kClassWalkSuper;
+        } else {
+          reference_offsets |= (0xffffffffu << start_bit) &
+                               (0xffffffffu >> (32 - (start_bit + num_reference_fields)));
+        }
+      }
     }
   }
   klass->SetReferenceInstanceOffsets(reference_offsets);
@@ -5316,6 +5661,7 @@
       break;
     default:
       LOG(FATAL) << "Unreachable - invocation type: " << type;
+      UNREACHABLE();
   }
   if (resolved == nullptr) {
     // Search by name, which works across dex files.
@@ -5365,71 +5711,73 @@
       }
 
       // If we found something, check that it can be accessed by the referrer.
+      bool exception_generated = false;
       if (resolved != nullptr && referrer.Get() != nullptr) {
         mirror::Class* methods_class = resolved->GetDeclaringClass();
         mirror::Class* referring_class = referrer->GetDeclaringClass();
         if (!referring_class->CanAccess(methods_class)) {
           ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class,
                                                         resolved, type);
-          return nullptr;
+          exception_generated = true;
         } else if (!referring_class->CanAccessMember(methods_class,
                                                      resolved->GetAccessFlags())) {
           ThrowIllegalAccessErrorMethod(referring_class, resolved);
-          return nullptr;
+          exception_generated = true;
         }
       }
-
-      // Otherwise, throw an IncompatibleClassChangeError if we found something, and check interface
-      // methods and throw if we find the method there. If we find nothing, throw a
-      // NoSuchMethodError.
-      switch (type) {
-        case kDirect:
-        case kStatic:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
-          } else {
-            resolved = klass->FindInterfaceMethod(name, signature);
-            if (resolved != nullptr) {
-              ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
-            } else {
-              ThrowNoSuchMethodError(type, klass, name, signature);
-            }
-          }
-          break;
-        case kInterface:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
-          } else {
-            resolved = klass->FindVirtualMethod(name, signature);
+      if (!exception_generated) {
+        // Otherwise, throw an IncompatibleClassChangeError if we found something, and check
+        // interface methods and throw if we find the method there. If we find nothing, throw a
+        // NoSuchMethodError.
+        switch (type) {
+          case kDirect:
+          case kStatic:
             if (resolved != nullptr) {
               ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
             } else {
-              ThrowNoSuchMethodError(type, klass, name, signature);
+              resolved = klass->FindInterfaceMethod(name, signature);
+              if (resolved != nullptr) {
+                ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+              } else {
+                ThrowNoSuchMethodError(type, klass, name, signature);
+              }
             }
-          }
-          break;
-        case kSuper:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
-          } else {
-            ThrowNoSuchMethodError(type, klass, name, signature);
-          }
-          break;
-        case kVirtual:
-          if (resolved != nullptr) {
-            ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
-          } else {
-            resolved = klass->FindInterfaceMethod(name, signature);
+            break;
+          case kInterface:
             if (resolved != nullptr) {
-              ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
+            } else {
+              resolved = klass->FindVirtualMethod(name, signature);
+              if (resolved != nullptr) {
+                ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
+              } else {
+                ThrowNoSuchMethodError(type, klass, name, signature);
+              }
+            }
+            break;
+          case kSuper:
+            if (resolved != nullptr) {
+              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
             } else {
               ThrowNoSuchMethodError(type, klass, name, signature);
             }
-          }
-          break;
+            break;
+          case kVirtual:
+            if (resolved != nullptr) {
+              ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
+            } else {
+              resolved = klass->FindInterfaceMethod(name, signature);
+              if (resolved != nullptr) {
+                ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
+              } else {
+                ThrowNoSuchMethodError(type, klass, name, signature);
+              }
+            }
+            break;
+        }
       }
     }
-    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->AssertPendingException();
     return nullptr;
   }
 }
@@ -5525,9 +5873,8 @@
   std::vector<mirror::Class*> all_classes;
   {
     ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-    for (std::pair<const size_t, GcRoot<mirror::Class> >& it : class_table_) {
-      mirror::Class* klass = it.second.Read();
-      all_classes.push_back(klass);
+    for (GcRoot<mirror::Class>& it : class_table_) {
+      all_classes.push_back(it.Read());
     }
   }
 
@@ -5536,6 +5883,52 @@
   }
 }
 
+static OatFile::OatMethod CreateOatMethod(const void* code) {
+  CHECK(code != nullptr);
+  const uint8_t* base = reinterpret_cast<const uint8_t*>(code);  // Base of data points at code.
+  base -= sizeof(void*);  // Move backward so that code_offset != 0.
+  const uint32_t code_offset = sizeof(void*);
+  return OatFile::OatMethod(base, code_offset);
+}
+
+bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const {
+  return (entry_point == GetQuickResolutionStub()) ||
+      (quick_resolution_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) const {
+  OatFile::OatMethod oat_method = CreateOatMethod(method_code);
+  oat_method.LinkMethod(method);
+  method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+}
+
+void ClassLinker::SetEntryPointsToInterpreter(mirror::ArtMethod* method) const {
+  if (!method->IsNative()) {
+    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
+    method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+  } else {
+    const void* quick_method_code = GetQuickGenericJniStub();
+    OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code);
+    oat_method.LinkMethod(method);
+    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+  }
+}
+
 void ClassLinker::DumpForSigQuit(std::ostream& os) {
   Thread* self = Thread::Current();
   if (dex_cache_image_class_lookup_required_) {
@@ -5543,7 +5936,8 @@
     MoveImageClassesToClassTable();
   }
   ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
-  os << "Loaded classes: " << class_table_.size() << " allocated classes\n";
+  os << "Zygote loaded classes=" << pre_zygote_class_table_.Size() << " post zygote classes="
+     << class_table_.Size() << "\n";
 }
 
 size_t ClassLinker::NumLoadedClasses() {
@@ -5551,7 +5945,8 @@
     MoveImageClassesToClassTable();
   }
   ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  return class_table_.size();
+  // Only return non zygote classes since these are the ones which apps which care about.
+  return class_table_.Size();
 }
 
 pid_t ClassLinker::GetClassesLockOwner() {
@@ -5574,4 +5969,117 @@
   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;",
+  };
+  static_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;
+}
+
+std::size_t ClassLinker::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& root)
+    const {
+  std::string temp;
+  return ComputeModifiedUtf8Hash(root.Read()->GetDescriptor(&temp));
+}
+
+bool ClassLinker::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a,
+                                                        const GcRoot<mirror::Class>& b) {
+  if (a.Read()->GetClassLoader() != b.Read()->GetClassLoader()) {
+    return false;
+  }
+  std::string temp;
+  return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp));
+}
+
+std::size_t ClassLinker::ClassDescriptorHashEquals::operator()(
+    const std::pair<const char*, mirror::ClassLoader*>& element) const {
+  return ComputeModifiedUtf8Hash(element.first);
+}
+
+bool ClassLinker::ClassDescriptorHashEquals::operator()(
+    const GcRoot<mirror::Class>& a, const std::pair<const char*, mirror::ClassLoader*>& b) {
+  if (a.Read()->GetClassLoader() != b.second) {
+    return false;
+  }
+  return a.Read()->DescriptorEquals(b.first);
+}
+
+bool ClassLinker::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a,
+                                                        const char* descriptor) {
+  return a.Read()->DescriptorEquals(descriptor);
+}
+
+std::size_t ClassLinker::ClassDescriptorHashEquals::operator()(const char* descriptor) const {
+  return ComputeModifiedUtf8Hash(descriptor);
+}
+
+bool ClassLinker::MayBeCalledWithDirectCodePointer(mirror::ArtMethod* m) {
+  // Non-image methods don't use direct code pointer.
+  if (!m->GetDeclaringClass()->IsBootStrapClassLoaded()) {
+    return false;
+  }
+  if (m->IsPrivate()) {
+    // The method can only be called inside its own oat file. Therefore it won't be called using
+    // its direct code if the oat file has been compiled in PIC mode.
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+    const DexFile& dex_file = m->GetDeclaringClass()->GetDexFile();
+    const OatFile::OatDexFile* oat_dex_file = class_linker->FindOpenedOatDexFileForDexFile(dex_file);
+    if (oat_dex_file == nullptr) {
+      // No oat file: the method has not been compiled.
+      return false;
+    }
+    const OatFile* oat_file = oat_dex_file->GetOatFile();
+    return oat_file != nullptr && !oat_file->IsPic();
+  } else {
+    // The method can be called outside its own oat file. Therefore it won't be called using its
+    // direct code pointer only if all loaded oat files have been compiled in PIC mode.
+    ReaderMutexLock mu(Thread::Current(), dex_lock_);
+    for (const OatFile* oat_file : oat_files_) {
+      if (!oat_file->IsPic()) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
 }  // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 111dd63..6570c5f 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -23,11 +23,11 @@
 #include <vector>
 
 #include "base/allocator.h"
+#include "base/hash_set.h"
 #include "base/macros.h"
 #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"
@@ -51,8 +51,9 @@
 template<class T> class Handle;
 class InternTable;
 template<class T> class ObjectLock;
+class Runtime;
 class ScopedObjectAccessAlreadyRunnable;
-template<class T> class Handle;
+template<size_t kNumReferences> class PACKED(4) StackHandleScope;
 
 typedef bool (ClassVisitor)(mirror::Class* c, void* arg);
 
@@ -60,11 +61,51 @@
 
 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();
 
   // Initialize class linker by bootstraping from dex files.
-  void InitWithoutImage(const std::vector<const DexFile*>& boot_class_path)
+  void InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Initialize class linker from one or more images.
@@ -76,9 +117,10 @@
                            Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Find a class in the path class loader, loading it if necessary.
+  // Find a class in the path class loader, loading it if necessary without using JNI. Hash
+  // function is supposed to be ComputeModifiedUtf8Hash(descriptor).
   mirror::Class* FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
-                                            Thread* self, const char* descriptor,
+                                            Thread* self, const char* descriptor, size_t hash,
                                             Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -97,15 +139,15 @@
   }
 
   // Define a new a class based on a ClassDef from a DexFile
-  mirror::Class* DefineClass(Thread* self, const char* descriptor,
+  mirror::Class* DefineClass(Thread* self, const char* descriptor, size_t hash,
                              Handle<mirror::ClassLoader> class_loader,
                              const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
   // by the given 'class_loader'.
-  mirror::Class* LookupClass(Thread* self, const char* descriptor,
-                             const mirror::ClassLoader* class_loader)
+  mirror::Class* LookupClass(Thread* self, const char* descriptor, size_t hash,
+                             mirror::ClassLoader* class_loader)
       LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -118,7 +160,7 @@
 
   // General class unloading is not supported, this is used to prune
   // unwanted classes during image writing.
-  bool RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader)
+  bool RemoveClass(const char* descriptor, mirror::ClassLoader* class_loader)
       LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -182,8 +224,7 @@
                                    InvokeType type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ArtMethod* GetResolvedMethod(uint32_t method_idx, mirror::ArtMethod* referrer,
-                                       InvokeType type)
+  mirror::ArtMethod* GetResolvedMethod(uint32_t method_idx, mirror::ArtMethod* referrer)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, mirror::ArtMethod** referrer,
                                    InvokeType type)
@@ -283,7 +324,7 @@
   // (if multidex) into the given vector.
   bool OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
                            std::vector<std::string>* error_msgs,
-                           std::vector<const DexFile*>* dex_files)
+                           std::vector<std::unique_ptr<const DexFile>>* dex_files)
       LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
 
   // Returns true if the given oat file has the same image checksum as the image it is paired with.
@@ -351,54 +392,45 @@
   // Get the oat code for a method when its class isn't yet initialized
   const void* GetQuickOatCodeFor(mirror::ArtMethod* method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const void* GetPortableOatCodeFor(mirror::ArtMethod* method, bool* have_portable_code)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get the oat code for a method from a method index.
   const void* GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const void* GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get compiled code for a method, return null if no code
   // exists. This is unlike Get..OatCodeFor which will return a bridge
   // or interpreter entrypoint.
   const void* GetOatMethodQuickCodeFor(mirror::ArtMethod* method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const void* GetOatMethodPortableCodeFor(mirror::ArtMethod* method)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   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 quick code to run the resolution stub?
+  bool IsQuickResolutionStub(const void* entry_point) const;
 
-  const void* GetPortableImtConflictTrampoline() const {
-    return portable_imt_conflict_trampoline_;
-  }
+  // Is the given entry point quick code to bridge into the interpreter?
+  bool IsQuickToInterpreterBridge(const void* entry_point) const;
 
-  const void* GetQuickImtConflictTrampoline() const {
-    return quick_imt_conflict_trampoline_;
-  }
-
-  const void* GetQuickToInterpreterBridgeTrampoline() const {
-    return quick_to_interpreter_bridge_trampoline_;
-  }
+  // 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) 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.
@@ -415,7 +447,25 @@
     return class_roots;
   }
 
+  // Move all of the image classes into the class table for faster lookups.
+  void MoveImageClassesToClassTable()
+      LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Move the class table to the pre-zygote table to reduce memory usage. This works by ensuring
+  // that no more classes are ever added to the pre zygote table which makes it that the pages
+  // always remain shared dirty instead of private dirty.
+  void MoveClassTableToPreZygote()
+      LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Returns true if the method can be called with its direct code pointer, false otherwise.
+  bool MayBeCalledWithDirectCodePointer(mirror::ArtMethod* m)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
+  static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const OatFile::OatMethod FindOatMethodFor(mirror::ArtMethod* method, bool* found)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -444,7 +494,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
-  mirror::Class* CreateArrayClass(Thread* self, const char* descriptor,
+  mirror::Class* CreateArrayClass(Thread* self, const char* descriptor, size_t hash,
                                   Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -461,9 +511,8 @@
   void LoadClass(Thread* self, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
                  Handle<mirror::Class> klass, mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void LoadClassMembers(Thread* self, const DexFile& dex_file, const byte* class_data,
-                        Handle<mirror::Class> klass, mirror::ClassLoader* class_loader,
-                        const OatFile::OatClass* oat_class)
+  void LoadClassMembers(Thread* self, const DexFile& dex_file, const uint8_t* class_data,
+                        Handle<mirror::Class> klass, const OatFile::OatClass* oat_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
@@ -518,14 +567,16 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool LinkMethods(Thread* self, Handle<mirror::Class> klass,
-                   Handle<mirror::ObjectArray<mirror::Class>> interfaces)
+                   Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                   StackHandleScope<mirror::Class::kImtSize>* out_imt)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkInterfaceMethods(Handle<mirror::Class> klass,
-                            Handle<mirror::ObjectArray<mirror::Class>> interfaces)
+  bool LinkInterfaceMethods(Thread* const self, Handle<mirror::Class> klass,
+                            Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                            StackHandleScope<mirror::Class::kImtSize>* out_imt)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size)
@@ -535,12 +586,10 @@
   bool LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_static, size_t* class_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
-                const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
+                uint32_t class_def_method_index)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void CreateReferenceInstanceOffsets(Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceOffsets(Handle<mirror::Class> klass, uint32_t reference_offsets)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // For use by ImageWriter to find DexCaches for its roots
   ReaderWriterMutex* DexLock()
@@ -587,9 +636,8 @@
                                      std::string* error_msg)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  bool CheckOatFile(const OatFile* oat_file, InstructionSet isa,
+  bool CheckOatFile(const Runtime* runtime, const OatFile* oat_file, InstructionSet isa,
                     bool* checksum_verified, std::string* error_msg);
-  int32_t GetRequiredDelta(const OatFile* oat_file, InstructionSet isa);
 
   // Note: will not register the oat file.
   const OatFile* FindOatFileInOatLocationForDexFile(const char* dex_location,
@@ -644,7 +692,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::Class* LookupClassFromTableLocked(const char* descriptor,
-                                            const mirror::ClassLoader* class_loader,
+                                            mirror::ClassLoader* class_loader,
                                             size_t hash)
       SHARED_LOCKS_REQUIRED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
 
@@ -652,9 +700,6 @@
       LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void MoveImageClassesToClassTable() LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
-      LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* LookupClassFromImage(const char* descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -670,22 +715,57 @@
   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_;
+  std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
 
   mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::vector<size_t> new_dex_cache_roots_ GUARDED_BY(dex_lock_);
   std::vector<GcRoot<mirror::DexCache>> dex_caches_ GUARDED_BY(dex_lock_);
   std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
 
+  class ClassDescriptorHashEquals {
+   public:
+    // Same class loader and descriptor.
+    std::size_t operator()(const GcRoot<mirror::Class>& root) const NO_THREAD_SAFETY_ANALYSIS;
+    bool operator()(const GcRoot<mirror::Class>& a, const GcRoot<mirror::Class>& b)
+        NO_THREAD_SAFETY_ANALYSIS;
+    // Same class loader and descriptor.
+    std::size_t operator()(const std::pair<const char*, mirror::ClassLoader*>& element) const
+        NO_THREAD_SAFETY_ANALYSIS;
+    bool operator()(const GcRoot<mirror::Class>& a,
+                    const std::pair<const char*, mirror::ClassLoader*>& b)
+        NO_THREAD_SAFETY_ANALYSIS;
+    // Same descriptor.
+    bool operator()(const GcRoot<mirror::Class>& a, const char* descriptor)
+        NO_THREAD_SAFETY_ANALYSIS;
+    std::size_t operator()(const char* descriptor) const NO_THREAD_SAFETY_ANALYSIS;
+  };
+  class GcRootEmptyFn {
+   public:
+    void MakeEmpty(GcRoot<mirror::Class>& item) const {
+      item = GcRoot<mirror::Class>();
+    }
+    bool IsEmpty(const GcRoot<mirror::Class>& item) const {
+      return item.IsNull();
+    }
+  };
 
-  // multimap from a string hash code of a class descriptor to
-  // mirror::Class* instances. Results should be compared for a matching
-  // Class::descriptor_ and Class::class_loader_.
-  typedef AllocationTrackingMultiMap<size_t, GcRoot<mirror::Class>, kAllocatorTagClassTable> Table;
+  // hash set which hashes class descriptor, and compares descriptors nad class loaders. Results
+  // should be compared for a matching Class descriptor and class loader.
+  typedef HashSet<GcRoot<mirror::Class>, GcRootEmptyFn, ClassDescriptorHashEquals,
+      ClassDescriptorHashEquals, TrackingAllocator<GcRoot<mirror::Class>, kAllocatorTagClassTable>>
+      Table;
   // This contains strong roots. To enable concurrent root scanning of
   // the class table, be careful to use a read barrier when accessing this.
   Table class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
-  std::vector<std::pair<size_t, GcRoot<mirror::Class>>> new_class_roots_;
+  Table pre_zygote_class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
+  std::vector<GcRoot<mirror::Class>> new_class_roots_;
 
   // Do we need to search dex caches to find image classes?
   bool dex_cache_image_class_lookup_required_;
@@ -693,61 +773,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_;
 
@@ -765,22 +793,22 @@
 
   // Trampolines within the image the bounce to runtime entrypoints. Done so that there is a single
   // patch point within the image. TODO: make these proper relocations.
-  const void* portable_resolution_trampoline_;
   const void* quick_resolution_trampoline_;
-  const void* portable_imt_conflict_trampoline_;
   const void* quick_imt_conflict_trampoline_;
   const void* quick_generic_jni_trampoline_;
   const void* quick_to_interpreter_bridge_trampoline_;
 
+  // Image pointer size.
+  size_t image_pointer_size_;
+
   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/class_linker_test.cc b/runtime/class_linker_test.cc
index 613ac66..64e129c 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -23,7 +23,6 @@
 #include "common_runtime_test.h"
 #include "dex_file.h"
 #include "entrypoints/entrypoint_utils-inl.h"
-#include "field_helper.h"
 #include "gc/heap.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method.h"
@@ -47,9 +46,9 @@
   void AssertNonExistentClass(const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     Thread* self = Thread::Current();
-    EXPECT_TRUE(class_linker_->FindSystemClass(self, descriptor.c_str()) == NULL);
+    EXPECT_TRUE(class_linker_->FindSystemClass(self, descriptor.c_str()) == nullptr);
     EXPECT_TRUE(self->IsExceptionPending());
-    mirror::Object* exception = self->GetException(NULL);
+    mirror::Object* exception = self->GetException(nullptr);
     self->ClearException();
     mirror::Class* exception_class =
         class_linker_->FindSystemClass(self, "Ljava/lang/NoClassDefFoundError;");
@@ -64,15 +63,15 @@
 
   void AssertPrimitiveClass(const std::string& descriptor, mirror::Class* primitive)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ASSERT_TRUE(primitive != NULL);
-    ASSERT_TRUE(primitive->GetClass() != NULL);
+    ASSERT_TRUE(primitive != nullptr);
+    ASSERT_TRUE(primitive->GetClass() != nullptr);
     ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
-    EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != NULL);
+    EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != nullptr);
     std::string temp;
     ASSERT_STREQ(descriptor.c_str(), primitive->GetDescriptor(&temp));
-    EXPECT_TRUE(primitive->GetSuperClass() == NULL);
+    EXPECT_TRUE(primitive->GetSuperClass() == nullptr);
     EXPECT_FALSE(primitive->HasSuperClass());
-    EXPECT_TRUE(primitive->GetClassLoader() == NULL);
+    EXPECT_TRUE(primitive->GetClassLoader() == nullptr);
     EXPECT_EQ(mirror::Class::kStatusInitialized, primitive->GetStatus());
     EXPECT_FALSE(primitive->IsErroneous());
     EXPECT_TRUE(primitive->IsLoaded());
@@ -81,7 +80,7 @@
     EXPECT_TRUE(primitive->IsInitialized());
     EXPECT_FALSE(primitive->IsArrayInstance());
     EXPECT_FALSE(primitive->IsArrayClass());
-    EXPECT_TRUE(primitive->GetComponentType() == NULL);
+    EXPECT_TRUE(primitive->GetComponentType() == nullptr);
     EXPECT_FALSE(primitive->IsInterface());
     EXPECT_TRUE(primitive->IsPublic());
     EXPECT_TRUE(primitive->IsFinal());
@@ -94,7 +93,7 @@
     EXPECT_EQ(0U, primitive->NumDirectInterfaces());
     EXPECT_FALSE(primitive->HasVTable());
     EXPECT_EQ(0, primitive->GetIfTableCount());
-    EXPECT_TRUE(primitive->GetIfTable() == NULL);
+    EXPECT_TRUE(primitive->GetIfTable() == nullptr);
     EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
   }
 
@@ -116,17 +115,17 @@
 
   void AssertArrayClass(const std::string& array_descriptor, Handle<mirror::Class> array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ASSERT_TRUE(array.Get() != NULL);
-    ASSERT_TRUE(array->GetClass() != NULL);
+    ASSERT_TRUE(array.Get() != nullptr);
+    ASSERT_TRUE(array->GetClass() != nullptr);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
-    EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
+    EXPECT_TRUE(array->GetClass()->GetSuperClass() != nullptr);
     std::string temp;
     ASSERT_STREQ(array_descriptor.c_str(), array->GetDescriptor(&temp));
-    EXPECT_TRUE(array->GetSuperClass() != NULL);
+    EXPECT_TRUE(array->GetSuperClass() != nullptr);
     Thread* self = Thread::Current();
     EXPECT_EQ(class_linker_->FindSystemClass(self, "Ljava/lang/Object;"), array->GetSuperClass());
     EXPECT_TRUE(array->HasSuperClass());
-    ASSERT_TRUE(array->GetComponentType() != NULL);
+    ASSERT_TRUE(array->GetComponentType() != nullptr);
     ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U);
     EXPECT_EQ(mirror::Class::kStatusInitialized, array->GetStatus());
     EXPECT_FALSE(array->IsErroneous());
@@ -148,7 +147,7 @@
     EXPECT_EQ(2U, array->NumDirectInterfaces());
     EXPECT_TRUE(array->ShouldHaveEmbeddedImtAndVTable());
     EXPECT_EQ(2, array->GetIfTableCount());
-    ASSERT_TRUE(array->GetIfTable() != NULL);
+    ASSERT_TRUE(array->GetIfTable() != nullptr);
     mirror::Class* direct_interface0 = mirror::Class::GetDirectInterface(self, array, 0);
     EXPECT_TRUE(direct_interface0 != nullptr);
     EXPECT_STREQ(direct_interface0->GetDescriptor(&temp), "Ljava/lang/Cloneable;");
@@ -164,11 +163,8 @@
     EXPECT_TRUE(method->GetName() != nullptr);
     EXPECT_TRUE(method->GetSignature() != Signature::NoSignature());
 
-    EXPECT_TRUE(method->GetDexCacheStrings() != nullptr);
     EXPECT_TRUE(method->HasDexCacheResolvedMethods());
     EXPECT_TRUE(method->HasDexCacheResolvedTypes());
-    EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetStrings(),
-              method->GetDexCacheStrings());
     EXPECT_TRUE(method->HasSameDexCacheResolvedMethods(
         method->GetDeclaringClass()->GetDexCache()->GetResolvedMethods()));
     EXPECT_TRUE(method->HasSameDexCacheResolvedTypes(
@@ -177,13 +173,11 @@
 
   void AssertField(mirror::Class* klass, mirror::ArtField* field)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    EXPECT_TRUE(field != NULL);
-    EXPECT_TRUE(field->GetClass() != NULL);
+    EXPECT_TRUE(field != nullptr);
+    EXPECT_TRUE(field->GetClass() != nullptr);
     EXPECT_EQ(klass, field->GetDeclaringClass());
-    EXPECT_TRUE(field->GetName() != NULL);
-    StackHandleScope<1> hs(Thread::Current());
-    FieldHelper fh(hs.NewHandle(field));
-    EXPECT_TRUE(fh.GetType() != NULL);
+    EXPECT_TRUE(field->GetName() != nullptr);
+    EXPECT_TRUE(field->GetType(true) != nullptr);
   }
 
   void AssertClass(const std::string& descriptor, Handle<mirror::Class> klass)
@@ -194,17 +188,19 @@
       EXPECT_FALSE(klass->HasSuperClass());
     } else {
       EXPECT_TRUE(klass->HasSuperClass());
-      EXPECT_TRUE(klass->GetSuperClass() != NULL);
+      EXPECT_TRUE(klass->GetSuperClass() != nullptr);
     }
-    EXPECT_TRUE(klass->GetClass() != NULL);
+    EXPECT_TRUE(klass->GetClass() != nullptr);
     EXPECT_EQ(klass->GetClass(), klass->GetClass()->GetClass());
-    EXPECT_TRUE(klass->GetDexCache() != NULL);
+    EXPECT_TRUE(klass->GetDexCache() != nullptr);
     EXPECT_TRUE(klass->IsLoaded());
     EXPECT_TRUE(klass->IsResolved());
     EXPECT_FALSE(klass->IsErroneous());
     EXPECT_FALSE(klass->IsArrayClass());
-    EXPECT_TRUE(klass->GetComponentType() == NULL);
+    EXPECT_TRUE(klass->GetComponentType() == nullptr);
     EXPECT_TRUE(klass->IsInSamePackage(klass.Get()));
+    EXPECT_TRUE(klass->GetDexCacheStrings() != nullptr);
+    EXPECT_EQ(klass->GetDexCacheStrings(), klass->GetDexCache()->GetStrings());
     std::string temp2;
     EXPECT_TRUE(mirror::Class::IsInSamePackage(klass->GetDescriptor(&temp),
                                                klass->GetDescriptor(&temp2)));
@@ -225,7 +221,7 @@
     mirror::IfTable* iftable = klass->GetIfTable();
     for (int i = 0; i < klass->GetIfTableCount(); i++) {
       mirror::Class* interface = iftable->GetInterface(i);
-      ASSERT_TRUE(interface != NULL);
+      ASSERT_TRUE(interface != nullptr);
       if (klass->IsInterface()) {
         EXPECT_EQ(0U, iftable->GetMethodArrayCount(i));
       } else {
@@ -275,44 +271,60 @@
       EXPECT_TRUE(field->IsStatic());
     }
 
-    // Confirm that all instances fields are packed together at the start
+    // Confirm that all instances field offsets are packed together at the start.
     EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
     StackHandleScope<1> hs(Thread::Current());
     MutableHandle<mirror::ArtField> fhandle = hs.NewHandle<mirror::ArtField>(nullptr);
-    for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
+    MemberOffset start_ref_offset = klass->GetFirstReferenceInstanceFieldOffset();
+    MemberOffset end_ref_offset(start_ref_offset.Uint32Value() +
+                                klass->NumReferenceInstanceFields() *
+                                    sizeof(mirror::HeapReference<mirror::Object>));
+    MemberOffset current_ref_offset = start_ref_offset;
+    for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
       mirror::ArtField* field = klass->GetInstanceField(i);
       fhandle.Assign(field);
-      FieldHelper fh(fhandle);
-      ASSERT_TRUE(!field->IsPrimitiveType());
-      mirror::Class* field_type = fh.GetType();
-      ASSERT_TRUE(field_type != NULL);
-      ASSERT_TRUE(!field_type->IsPrimitive());
-    }
-    for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
-      mirror::ArtField* field = klass->GetInstanceField(i);
-      fhandle.Assign(field);
-      FieldHelper fh(fhandle);
-      mirror::Class* field_type = fh.GetType();
-      ASSERT_TRUE(field_type != NULL);
-      if (!fh.GetField()->IsPrimitiveType() || !field_type->IsPrimitive()) {
-        // While Reference.referent is not primitive, the ClassLinker
-        // treats it as such so that the garbage collector won't scan it.
-        EXPECT_EQ(PrettyField(fh.GetField()), "java.lang.Object java.lang.ref.Reference.referent");
+      mirror::Class* field_type = fhandle->GetType(true);
+      ASSERT_TRUE(field_type != nullptr);
+      if (!field->IsPrimitiveType()) {
+        ASSERT_TRUE(!field_type->IsPrimitive());
+        ASSERT_EQ(current_ref_offset.Uint32Value(), field->GetOffset().Uint32Value());
+        if (current_ref_offset.Uint32Value() == end_ref_offset.Uint32Value()) {
+          // While Reference.referent is not primitive, the ClassLinker
+          // treats it as such so that the garbage collector won't scan it.
+          EXPECT_EQ(PrettyField(fhandle.Get()),
+                    "java.lang.Object java.lang.ref.Reference.referent");
+        } else {
+          current_ref_offset = MemberOffset(current_ref_offset.Uint32Value() +
+                                            sizeof(mirror::HeapReference<mirror::Object>));
+        }
+      } else {
+        if (field->GetOffset().Uint32Value() < end_ref_offset.Uint32Value()) {
+          // Shuffled before references.
+          ASSERT_LT(field->GetOffset().Uint32Value(), start_ref_offset.Uint32Value());
+          CHECK(!IsAligned<4>(field->GetOffset().Uint32Value()));
+        }
       }
     }
+    ASSERT_EQ(end_ref_offset.Uint32Value(), current_ref_offset.Uint32Value());
 
-    size_t total_num_reference_instance_fields = 0;
+    uint32_t total_num_reference_instance_fields = 0;
     mirror::Class* k = klass.Get();
-    while (k != NULL) {
+    while (k != nullptr) {
       total_num_reference_instance_fields += k->NumReferenceInstanceFields();
       k = k->GetSuperClass();
     }
-    EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0, total_num_reference_instance_fields == 0);
+    EXPECT_GE(total_num_reference_instance_fields, 1U);  // Should always have Object's class.
+    if (klass->GetReferenceInstanceOffsets() != mirror::Class::kClassWalkSuper) {
+      // The reference instance offsets have a bit set for each reference offset.
+      // +1 for Object's class.
+      EXPECT_EQ(static_cast<uint32_t>(POPCOUNT(klass->GetReferenceInstanceOffsets())) + 1,
+                total_num_reference_instance_fields);
+    }
   }
 
   void AssertDexFileClass(mirror::ClassLoader* class_loader, const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ASSERT_TRUE(descriptor != NULL);
+    ASSERT_TRUE(descriptor != nullptr);
     Thread* self = Thread::Current();
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> klass(
@@ -330,33 +342,31 @@
     }
   }
 
-  void AssertDexFile(const DexFile* dex, mirror::ClassLoader* class_loader)
+  void AssertDexFile(const DexFile& dex, mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ASSERT_TRUE(dex != NULL);
-
     // Verify all the classes defined in this file
-    for (size_t i = 0; i < dex->NumClassDefs(); i++) {
-      const DexFile::ClassDef& class_def = dex->GetClassDef(i);
-      const char* descriptor = dex->GetClassDescriptor(class_def);
+    for (size_t i = 0; i < dex.NumClassDefs(); i++) {
+      const DexFile::ClassDef& class_def = dex.GetClassDef(i);
+      const char* descriptor = dex.GetClassDescriptor(class_def);
       AssertDexFileClass(class_loader, descriptor);
     }
     // Verify all the types referenced by this file
-    for (size_t i = 0; i < dex->NumTypeIds(); i++) {
-      const DexFile::TypeId& type_id = dex->GetTypeId(i);
-      const char* descriptor = dex->GetTypeDescriptor(type_id);
+    for (size_t i = 0; i < dex.NumTypeIds(); i++) {
+      const DexFile::TypeId& type_id = dex.GetTypeId(i);
+      const char* descriptor = dex.GetTypeDescriptor(type_id);
       AssertDexFileClass(class_loader, descriptor);
     }
-    class_linker_->VisitRoots(TestRootVisitor, NULL, kVisitRootFlagAllRoots);
+    class_linker_->VisitRoots(TestRootVisitor, nullptr, kVisitRootFlagAllRoots);
     // Verify the dex cache has resolution methods in all resolved method slots
-    mirror::DexCache* dex_cache = class_linker_->FindDexCache(*dex);
+    mirror::DexCache* dex_cache = class_linker_->FindDexCache(dex);
     mirror::ObjectArray<mirror::ArtMethod>* resolved_methods = dex_cache->GetResolvedMethods();
     for (size_t i = 0; i < static_cast<size_t>(resolved_methods->GetLength()); i++) {
-      EXPECT_TRUE(resolved_methods->Get(i) != NULL) << dex->GetLocation() << " i=" << i;
+      EXPECT_TRUE(resolved_methods->Get(i) != nullptr) << dex.GetLocation() << " i=" << i;
     }
   }
 
-  static void TestRootVisitor(mirror::Object** root, void*, uint32_t, RootType) {
-    EXPECT_TRUE(*root != NULL);
+  static void TestRootVisitor(mirror::Object** root, void*, const RootInfo&) {
+    EXPECT_TRUE(*root != nullptr);
   }
 };
 
@@ -368,8 +378,8 @@
 
 template <typename T>
 struct CheckOffsets {
-  CheckOffsets(bool is_static, const char* class_descriptor)
-      : is_static(is_static), class_descriptor(class_descriptor) {}
+  CheckOffsets(bool is_static_in, const char* class_descriptor_in)
+      : is_static(is_static_in), class_descriptor(class_descriptor_in) {}
   bool is_static;
   std::string class_descriptor;
   std::vector<CheckOffset> offsets;
@@ -378,11 +388,12 @@
     Thread* self = Thread::Current();
     mirror::Class* klass =
         Runtime::Current()->GetClassLinker()->FindSystemClass(self, class_descriptor.c_str());
-    CHECK(klass != NULL) << class_descriptor;
+    CHECK(klass != nullptr) << class_descriptor;
 
     bool error = false;
 
-    if (!klass->IsClassClass() && !is_static) {
+    // Art method have a different size due to the padding field.
+    if (!klass->IsArtMethodClass() && !klass->IsClassClass() && !is_static) {
       size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize();
       if (sizeof(T) != expected_size) {
         LOG(ERROR) << "Class size mismatch:"
@@ -455,10 +466,7 @@
 
 struct ObjectOffsets : public CheckOffsets<mirror::Object> {
   ObjectOffsets() : CheckOffsets<mirror::Object>(false, "Ljava/lang/Object;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, klass_),   "shadow$_klass_"));
-
-    // alphabetical 32-bit
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, monitor_), "shadow$_monitor_"));
 #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, x_rb_ptr_), "shadow$_x_rb_ptr_"));
@@ -469,11 +477,8 @@
 
 struct ArtFieldOffsets : public CheckOffsets<mirror::ArtField> {
   ArtFieldOffsets() : CheckOffsets<mirror::ArtField>(false, "Ljava/lang/reflect/ArtField;") {
-    // alphabetical references
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtField, declaring_class_), "declaringClass"));
-
-    // alphabetical 32-bit
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtField, access_flags_),    "accessFlags"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtField, declaring_class_), "declaringClass"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtField, field_dex_idx_),   "fieldDexIndex"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtField, offset_),          "offset"));
   };
@@ -481,21 +486,10 @@
 
 struct ArtMethodOffsets : public CheckOffsets<mirror::ArtMethod> {
   ArtMethodOffsets() : CheckOffsets<mirror::ArtMethod>(false, "Ljava/lang/reflect/ArtMethod;") {
-    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_),                   "accessFlags"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, declaring_class_),                      "declaringClass"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_methods_),           "dexCacheResolvedMethods"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_),             "dexCacheResolvedTypes"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_strings_),                    "dexCacheStrings"));
-
-    // alphabetical 64-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_interpreter_),            "entryPointFromInterpreter"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_jni_),                    "entryPointFromJni"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_portable_compiled_code_), "entryPointFromPortableCompiledCode"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_quick_compiled_code_),    "entryPointFromQuickCompiledCode"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, gc_map_),                                  "gcMap"));
-
-    // alphabetical 32-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_),                   "accessFlags"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_),           "dexCodeItemOffset"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_),               "dexMethodIndex"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_),                   "methodIndex"));
@@ -504,51 +498,44 @@
 
 struct ClassOffsets : public CheckOffsets<mirror::Class> {
   ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") {
-    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_),                  "accessFlags"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_),                  "classLoader"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_),                    "classSize"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_),              "clinitThreadId"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, component_type_),                "componentType"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_),                     "dexCache"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_),             "dexCacheStrings"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_),             "dexClassDefIndex"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_),                  "dexTypeIndex"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_),                "directMethods"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_),                       "iFields"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_),                       "ifTable"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, imtable_),                       "imTable"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_),                          "name"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_),                       "sFields"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_),                   "superClass"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_class_),            "verifyErrorClass"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_),               "virtualMethods"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, vtable_),                        "vtable"));
-
-    // alphabetical 32-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_),                  "accessFlags"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_),                    "classSize"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_),              "clinitThreadId"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_),             "dexClassDefIndex"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_),                  "dexTypeIndex"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_),   "numReferenceStaticFields"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, object_size_),                   "objectSize"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_),                "primitiveType"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_),    "referenceInstanceOffsets"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_),                       "sFields"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, status_),                        "status"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_),                   "superClass"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_class_),            "verifyErrorClass"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_),               "virtualMethods"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, vtable_),                        "vtable"));
   };
 };
 
 struct StringOffsets : public CheckOffsets<mirror::String> {
   StringOffsets() : CheckOffsets<mirror::String>(false, "Ljava/lang/String;") {
-    // alphabetical references
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, array_),     "value"));
-
-    // alphabetical 32-bit
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, count_),     "count"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hashCode"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, offset_),    "offset"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, array_),     "value"));
   };
 };
 
 struct ThrowableOffsets : public CheckOffsets<mirror::Throwable> {
   ThrowableOffsets() : CheckOffsets<mirror::Throwable>(false, "Ljava/lang/Throwable;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_),                 "cause"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_),        "detailMessage"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_state_),           "stackState"));
@@ -559,17 +546,15 @@
 
 struct StackTraceElementOffsets : public CheckOffsets<mirror::StackTraceElement> {
   StackTraceElementOffsets() : CheckOffsets<mirror::StackTraceElement>(false, "Ljava/lang/StackTraceElement;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, declaring_class_), "declaringClass"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, file_name_),       "fileName"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_),     "methodName"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, line_number_),     "lineNumber"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_),     "methodName"));
   };
 };
 
 struct ClassLoaderOffsets : public CheckOffsets<mirror::ClassLoader> {
   ClassLoaderOffsets() : CheckOffsets<mirror::ClassLoader>(false, "Ljava/lang/ClassLoader;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_),   "packages"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_),     "parent"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache"));
@@ -578,27 +563,24 @@
 
 struct ProxyOffsets : public CheckOffsets<mirror::Proxy> {
   ProxyOffsets() : CheckOffsets<mirror::Proxy>(false, "Ljava/lang/reflect/Proxy;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Proxy, h_), "h"));
   };
 };
 
 struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> {
   DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_),                        "dex"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_),                   "dexFile"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, location_),                   "location"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_),            "resolvedFields"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_),           "resolvedMethods"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_),             "resolvedTypes"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_),                    "strings"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_),                   "dexFile"));
   };
 };
 
 struct ReferenceOffsets : public CheckOffsets<mirror::Reference> {
   ReferenceOffsets() : CheckOffsets<mirror::Reference>(false, "Ljava/lang/ref/Reference;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, pending_next_),  "pendingNext"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, queue_),         "queue"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, queue_next_),    "queueNext"));
@@ -608,7 +590,6 @@
 
 struct FinalizerReferenceOffsets : public CheckOffsets<mirror::FinalizerReference> {
   FinalizerReferenceOffsets() : CheckOffsets<mirror::FinalizerReference>(false, "Ljava/lang/ref/FinalizerReference;") {
-    // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, next_),   "next"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, prev_),   "prev"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, zombie_), "zombie"));
@@ -647,12 +628,12 @@
       hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Nested"))));
 
   mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader);
-  ASSERT_TRUE(outer != NULL);
+  ASSERT_TRUE(outer != nullptr);
   EXPECT_EQ(0U, outer->NumVirtualMethods());
   EXPECT_EQ(1U, outer->NumDirectMethods());
 
   mirror::Class* inner = class_linker_->FindClass(soa.Self(), "LNested$Inner;", class_loader);
-  ASSERT_TRUE(inner != NULL);
+  ASSERT_TRUE(inner != nullptr);
   EXPECT_EQ(0U, inner->NumVirtualMethods());
   EXPECT_EQ(1U, inner->NumDirectMethods());
 }
@@ -674,15 +655,15 @@
 TEST_F(ClassLinkerTest, FindClass) {
   ScopedObjectAccess soa(Thread::Current());
   mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
-  ASSERT_TRUE(JavaLangObject != NULL);
-  ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
+  ASSERT_TRUE(JavaLangObject != nullptr);
+  ASSERT_TRUE(JavaLangObject->GetClass() != nullptr);
   ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
   std::string temp;
   ASSERT_STREQ(JavaLangObject->GetDescriptor(&temp), "Ljava/lang/Object;");
-  EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
+  EXPECT_TRUE(JavaLangObject->GetSuperClass() == nullptr);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
-  EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
+  EXPECT_TRUE(JavaLangObject->GetClassLoader() == nullptr);
   EXPECT_EQ(mirror::Class::kStatusInitialized, JavaLangObject->GetStatus());
   EXPECT_FALSE(JavaLangObject->IsErroneous());
   EXPECT_TRUE(JavaLangObject->IsLoaded());
@@ -691,7 +672,7 @@
   EXPECT_TRUE(JavaLangObject->IsInitialized());
   EXPECT_FALSE(JavaLangObject->IsArrayInstance());
   EXPECT_FALSE(JavaLangObject->IsArrayClass());
-  EXPECT_TRUE(JavaLangObject->GetComponentType() == NULL);
+  EXPECT_TRUE(JavaLangObject->GetComponentType() == nullptr);
   EXPECT_FALSE(JavaLangObject->IsInterface());
   EXPECT_TRUE(JavaLangObject->IsPublic());
   EXPECT_FALSE(JavaLangObject->IsFinal());
@@ -719,8 +700,8 @@
       hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
   AssertNonExistentClass("LMyClass;");
   mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
-  ASSERT_TRUE(MyClass != NULL);
-  ASSERT_TRUE(MyClass->GetClass() != NULL);
+  ASSERT_TRUE(MyClass != nullptr);
+  ASSERT_TRUE(MyClass->GetClass() != nullptr);
   ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
   ASSERT_STREQ(MyClass->GetDescriptor(&temp), "LMyClass;");
@@ -735,7 +716,7 @@
   EXPECT_FALSE(MyClass->IsInitialized());
   EXPECT_FALSE(MyClass->IsArrayInstance());
   EXPECT_FALSE(MyClass->IsArrayClass());
-  EXPECT_TRUE(MyClass->GetComponentType() == NULL);
+  EXPECT_TRUE(MyClass->GetComponentType() == nullptr);
   EXPECT_FALSE(MyClass->IsInterface());
   EXPECT_FALSE(MyClass->IsPublic());
   EXPECT_FALSE(MyClass->IsFinal());
@@ -750,10 +731,10 @@
   EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
 
   // created by class_linker
-  AssertArrayClass("[C", "C", NULL);
-  AssertArrayClass("[Ljava/lang/Object;", "Ljava/lang/Object;", NULL);
+  AssertArrayClass("[C", "C", nullptr);
+  AssertArrayClass("[Ljava/lang/Object;", "Ljava/lang/Object;", nullptr);
   // synthesized on the fly
-  AssertArrayClass("[[C", "[C", NULL);
+  AssertArrayClass("[[C", "[C", nullptr);
   AssertArrayClass("[[[LMyClass;", "[[LMyClass;", class_loader.Get());
   // or not available at all
   AssertNonExistentClass("[[[[LNonExistentClass;");
@@ -761,7 +742,8 @@
 
 TEST_F(ClassLinkerTest, LibCore) {
   ScopedObjectAccess soa(Thread::Current());
-  AssertDexFile(java_lang_dex_file_, NULL);
+  ASSERT_TRUE(java_lang_dex_file_ != nullptr);
+  AssertDexFile(*java_lang_dex_file_, nullptr);
 }
 
 // The first reference array element must be a multiple of 4 bytes from the
@@ -863,7 +845,7 @@
   // expression resolve to a copy of a constant value from the constant pool.
   // So <clinit> should be null.
   mirror::ArtMethod* clinit = statics->FindDirectMethod("<clinit>", "()V");
-  EXPECT_TRUE(clinit == NULL);
+  EXPECT_TRUE(clinit == nullptr);
 
   EXPECT_EQ(9U, statics->NumStaticFields());
 
@@ -901,12 +883,12 @@
 
   mirror::ArtField* s6 = mirror::Class::FindStaticField(soa.Self(), statics, "s6", "F");
   EXPECT_EQ(s6->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
-  EXPECT_EQ(0.5, s6->GetFloat(statics.Get()));
+  EXPECT_DOUBLE_EQ(0.5, s6->GetFloat(statics.Get()));
   s6->SetFloat<false>(statics.Get(), 0.75);
 
   mirror::ArtField* s7 = mirror::Class::FindStaticField(soa.Self(), statics, "s7", "D");
   EXPECT_EQ(s7->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
-  EXPECT_EQ(16777217, s7->GetDouble(statics.Get()));
+  EXPECT_DOUBLE_EQ(16777217.0, s7->GetDouble(statics.Get()));
   s7->SetDouble<false>(statics.Get(), 16777219);
 
   mirror::ArtField* s8 = mirror::Class::FindStaticField(soa.Self(), statics, "s8",
@@ -924,8 +906,8 @@
   EXPECT_EQ(-535, s3->GetShort(statics.Get()));
   EXPECT_EQ(2000000001, s4->GetInt(statics.Get()));
   EXPECT_EQ(INT64_C(0x34567890abcdef12), s5->GetLong(statics.Get()));
-  EXPECT_EQ(0.75, s6->GetFloat(statics.Get()));
-  EXPECT_EQ(16777219, s7->GetDouble(statics.Get()));
+  EXPECT_FLOAT_EQ(0.75, s6->GetFloat(statics.Get()));
+  EXPECT_DOUBLE_EQ(16777219.0, s7->GetDouble(statics.Get()));
   EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("robot"));
 }
 
@@ -960,15 +942,15 @@
   mirror::ArtMethod* Ai = A->FindVirtualMethod("i", void_sig);
   mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", void_sig);
   mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", void_sig);
-  ASSERT_TRUE(Ii != NULL);
-  ASSERT_TRUE(Jj1 != NULL);
-  ASSERT_TRUE(Jj2 != NULL);
-  ASSERT_TRUE(Kj1 != NULL);
-  ASSERT_TRUE(Kj2 != NULL);
-  ASSERT_TRUE(Kk != NULL);
-  ASSERT_TRUE(Ai != NULL);
-  ASSERT_TRUE(Aj1 != NULL);
-  ASSERT_TRUE(Aj2 != NULL);
+  ASSERT_TRUE(Ii != nullptr);
+  ASSERT_TRUE(Jj1 != nullptr);
+  ASSERT_TRUE(Jj2 != nullptr);
+  ASSERT_TRUE(Kj1 != nullptr);
+  ASSERT_TRUE(Kj2 != nullptr);
+  ASSERT_TRUE(Kk != nullptr);
+  ASSERT_TRUE(Ai != nullptr);
+  ASSERT_TRUE(Aj1 != nullptr);
+  ASSERT_TRUE(Aj2 != nullptr);
   EXPECT_NE(Ii, Ai);
   EXPECT_NE(Jj1, Aj1);
   EXPECT_NE(Jj2, Aj2);
@@ -989,7 +971,7 @@
                                                           "Ljava/lang/String;");
   mirror::ArtField* Kfoo = mirror::Class::FindStaticField(soa.Self(), K, "foo",
                                                           "Ljava/lang/String;");
-  ASSERT_TRUE(Afoo != NULL);
+  ASSERT_TRUE(Afoo != nullptr);
   EXPECT_EQ(Afoo, Bfoo);
   EXPECT_EQ(Afoo, Jfoo);
   EXPECT_EQ(Afoo, Kfoo);
@@ -1007,20 +989,20 @@
   Handle<mirror::ClassLoader> class_loader(
       hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
   const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(jclass_loader)[0];
-  CHECK(dex_file != NULL);
+  CHECK(dex_file != nullptr);
   mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
   mirror::ArtMethod* clinit = klass->FindClassInitializer();
   mirror::ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;");
   const DexFile::StringId* string_id = dex_file->FindStringId("LStaticsFromCode;");
-  ASSERT_TRUE(string_id != NULL);
+  ASSERT_TRUE(string_id != nullptr);
   const DexFile::TypeId* type_id = dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
-  ASSERT_TRUE(type_id != NULL);
+  ASSERT_TRUE(type_id != nullptr);
   uint32_t type_idx = dex_file->GetIndexForTypeId(*type_id);
   mirror::Class* uninit = ResolveVerifyAndClinit(type_idx, clinit, Thread::Current(), true, false);
-  EXPECT_TRUE(uninit != NULL);
+  EXPECT_TRUE(uninit != nullptr);
   EXPECT_FALSE(uninit->IsInitialized());
   mirror::Class* init = ResolveVerifyAndClinit(type_idx, getS0, Thread::Current(), true, false);
-  EXPECT_TRUE(init != NULL);
+  EXPECT_TRUE(init != nullptr);
   EXPECT_TRUE(init->IsInitialized());
 }
 
@@ -1117,7 +1099,7 @@
   ScopedObjectAccess soa(Thread::Current());
 
   mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
-  ASSERT_TRUE(JavaLangObject != NULL);
+  ASSERT_TRUE(JavaLangObject != nullptr);
   EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the "
                                                   "core";
   CheckPreverified(JavaLangObject, true);
@@ -1154,4 +1136,24 @@
   CheckPreverified(statics.Get(), true);
 }
 
+TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+
+  // java.lang.Object is a bootstrap class.
+  Handle<mirror::Class> jlo_class(
+      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
+  ASSERT_TRUE(jlo_class.Get() != nullptr);
+  EXPECT_TRUE(jlo_class.Get()->IsBootStrapClassLoaded());
+
+  // Statics is not a bootstrap class.
+  Handle<mirror::Class> statics(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
+  ASSERT_TRUE(statics.Get() != nullptr);
+  EXPECT_FALSE(statics.Get()->IsBootStrapClassLoaded());
+}
+
 }  // namespace art
diff --git a/runtime/closure.h b/runtime/closure.h
deleted file mode 100644
index 9bea28f..0000000
--- a/runtime/closure.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_CLOSURE_H_
-#define ART_RUNTIME_CLOSURE_H_
-
-namespace art {
-
-class Thread;
-
-class Closure {
- public:
-  virtual ~Closure() { }
-  virtual void Run(Thread* self) = 0;
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_CLOSURE_H_
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index eed6f71..d48ac9d 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -20,6 +20,7 @@
 #include <dlfcn.h>
 #include <fcntl.h>
 #include <ScopedLocalRef.h>
+#include <stdlib.h>
 
 #include "../../external/icu/icu4c/source/common/unicode/uvernum.h"
 #include "base/macros.h"
@@ -43,8 +44,13 @@
 #include "well_known_classes.h"
 
 int main(int argc, char **argv) {
+  // Gtests can be very noisy. For example, an executable with multiple tests will trigger native
+  // bridge warnings. The following line reduces the minimum log severity to ERROR and suppresses
+  // everything else. In case you want to see all messages, comment out the line.
+  setenv("ANDROID_LOG_TAGS", "*:e", 1);
+
   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();
 }
@@ -59,7 +65,7 @@
   filename_ += "/TmpFile-XXXXXX";
   int fd = mkstemp(&filename_[0]);
   CHECK_NE(-1, fd);
-  file_.reset(new File(fd, GetFilename()));
+  file_.reset(new File(fd, GetFilename(), true));
 }
 
 ScratchFile::ScratchFile(const ScratchFile& other, const char* suffix) {
@@ -67,7 +73,7 @@
   filename_ += suffix;
   int fd = open(filename_.c_str(), O_RDWR | O_CREAT, 0666);
   CHECK_NE(-1, fd);
-  file_.reset(new File(fd, GetFilename()));
+  file_.reset(new File(fd, GetFilename(), true));
 }
 
 ScratchFile::ScratchFile(File* file) {
@@ -84,16 +90,29 @@
   return file_->Fd();
 }
 
+void ScratchFile::Close() {
+  if (file_.get() != nullptr) {
+    if (file_->FlushCloseOrErase() != 0) {
+      PLOG(WARNING) << "Error closing scratch file.";
+    }
+  }
+}
+
 void ScratchFile::Unlink() {
   if (!OS::FileExists(filename_.c_str())) {
     return;
   }
+  Close();
   int unlink_result = unlink(filename_.c_str());
   CHECK_EQ(0, unlink_result);
 }
 
 CommonRuntimeTest::CommonRuntimeTest() {}
-CommonRuntimeTest::~CommonRuntimeTest() {}
+CommonRuntimeTest::~CommonRuntimeTest() {
+  // Ensure the dex files are cleaned up before the runtime.
+  loaded_dex_files_.clear();
+  runtime_.reset();
+}
 
 void CommonRuntimeTest::SetUpAndroidRoot() {
   if (IsHost()) {
@@ -164,16 +183,23 @@
   }
 }
 
+std::string CommonRuntimeTest::GetCoreArtLocation() {
+  return GetCoreFileLocation("art");
+}
 
-const DexFile* CommonRuntimeTest::LoadExpectSingleDexFile(const char* location) {
-  std::vector<const DexFile*> dex_files;
+std::string CommonRuntimeTest::GetCoreOatLocation() {
+  return GetCoreFileLocation("oat");
+}
+
+std::unique_ptr<const DexFile> CommonRuntimeTest::LoadExpectSingleDexFile(const char* location) {
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
   std::string error_msg;
   if (!DexFile::Open(location, location, &error_msg, &dex_files)) {
     LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
-    return nullptr;
+    UNREACHABLE();
   } else {
     CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location;
-    return dex_files[0];
+    return std::move(dex_files[0]);
   }
 }
 
@@ -185,20 +211,17 @@
   int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
   ASSERT_EQ(mkdir_result, 0);
 
-  std::string error_msg;
-  java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
-  boot_class_path_.push_back(java_lang_dex_file_);
-
   std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
   std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
 
   callbacks_.reset(new NoopCompilerCallbacks());
 
   RuntimeOptions options;
-  options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
+  std::string boot_class_path_string = "-Xbootclasspath:" + GetLibCoreDexFileName();
+  options.push_back(std::make_pair(boot_class_path_string, nullptr));
   options.push_back(std::make_pair("-Xcheck:jni", nullptr));
-  options.push_back(std::make_pair(min_heap_string.c_str(), nullptr));
-  options.push_back(std::make_pair(max_heap_string.c_str(), nullptr));
+  options.push_back(std::make_pair(min_heap_string, nullptr));
+  options.push_back(std::make_pair(max_heap_string, nullptr));
   options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
   SetUpRuntimeOptions(&options);
   if (!Runtime::Create(options, false)) {
@@ -209,6 +232,9 @@
   class_linker_ = runtime_->GetClassLinker();
   class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
   class_linker_->RunRootClinits();
+  boot_class_path_ = class_linker_->GetBootClassPath();
+  java_lang_dex_file_ = boot_class_path_[0];
+
 
   // Runtime::Create acquired the mutator_lock_ that is normally given away when we
   // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
@@ -221,6 +247,11 @@
   // pool is created by the runtime.
   runtime_->GetHeap()->CreateThreadPool();
   runtime_->GetHeap()->VerifyHeap();  // Check for heap corruption before the test
+
+  // Get the boot class path from the runtime so it can be used in tests.
+  boot_class_path_ = class_linker_->GetBootClassPath();
+  ASSERT_FALSE(boot_class_path_.empty());
+  java_lang_dex_file_ = boot_class_path_[0];
 }
 
 void CommonRuntimeTest::ClearDirectory(const char* dirpath) {
@@ -267,8 +298,6 @@
   IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym);
   (*icu_cleanup_fn)();
 
-  STLDeleteElements(&opened_dex_files_);
-
   Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
 }
 
@@ -305,7 +334,7 @@
 #define ART_TARGET_NATIVETEST_DIR_STRING ""
 #endif
 
-std::vector<const DexFile*> CommonRuntimeTest::OpenTestDexFiles(const char* name) {
+std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTest::OpenTestDexFiles(const char* name) {
   CHECK(name != nullptr);
   std::string filename;
   if (IsHost()) {
@@ -318,28 +347,30 @@
   filename += name;
   filename += ".jar";
   std::string error_msg;
-  std::vector<const DexFile*> dex_files;
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
   bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files);
   CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
-  for (const DexFile* dex_file : dex_files) {
+  for (auto& dex_file : dex_files) {
     CHECK_EQ(PROT_READ, dex_file->GetPermissions());
     CHECK(dex_file->IsReadOnly());
   }
-  opened_dex_files_.insert(opened_dex_files_.end(), dex_files.begin(), dex_files.end());
   return dex_files;
 }
 
-const DexFile* CommonRuntimeTest::OpenTestDexFile(const char* name) {
-  std::vector<const DexFile*> vector = OpenTestDexFiles(name);
+std::unique_ptr<const DexFile> CommonRuntimeTest::OpenTestDexFile(const char* name) {
+  std::vector<std::unique_ptr<const DexFile>> vector = OpenTestDexFiles(name);
   EXPECT_EQ(1U, vector.size());
-  return vector[0];
+  return std::move(vector[0]);
 }
 
 jobject CommonRuntimeTest::LoadDex(const char* dex_name) {
-  std::vector<const DexFile*> dex_files = OpenTestDexFiles(dex_name);
+  std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name);
+  std::vector<const DexFile*> class_path;
   CHECK_NE(0U, dex_files.size());
-  for (const DexFile* dex_file : dex_files) {
+  for (auto& dex_file : dex_files) {
+    class_path.push_back(dex_file.get());
     class_linker_->RegisterDexFile(*dex_file);
+    loaded_dex_files_.push_back(std::move(dex_file));
   }
   Thread* self = Thread::Current();
   JNIEnvExt* env = self->GetJniEnv();
@@ -347,10 +378,25 @@
       env->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
   jobject class_loader = env->NewGlobalRef(class_loader_local.get());
   self->SetClassLoaderOverride(class_loader_local.get());
-  Runtime::Current()->SetCompileTimeClassPath(class_loader, dex_files);
+  Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path);
   return class_loader;
 }
 
+std::string CommonRuntimeTest::GetCoreFileLocation(const char* suffix) {
+  CHECK(suffix != nullptr);
+
+  std::string location;
+  if (IsHost()) {
+    const char* host_dir = getenv("ANDROID_HOST_OUT");
+    CHECK(host_dir != NULL);
+    location = StringPrintf("%s/framework/core.%s", host_dir, suffix);
+  } else {
+    location = StringPrintf("/data/art-test/core.%s", suffix);
+  }
+
+  return location;
+}
+
 CheckJniAbortCatcher::CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) {
   vm_->SetCheckJniAbortHook(Hook, &actual_);
 }
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 1ca6eb3..38a9733 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -55,6 +55,7 @@
 
   int GetFd() const;
 
+  void Close();
   void Unlink();
 
  private:
@@ -80,12 +81,18 @@
     return !kIsTargetBuild;
   }
 
-  const DexFile* LoadExpectSingleDexFile(const char* location);
+  // File location to core.art, e.g. $ANDROID_HOST_OUT/system/framework/core.art
+  static std::string GetCoreArtLocation();
+
+  // File location to core.oat, e.g. $ANDROID_HOST_OUT/system/framework/core.oat
+  static std::string GetCoreOatLocation();
+
+  std::unique_ptr<const DexFile> LoadExpectSingleDexFile(const char* location);
 
   virtual void SetUp();
 
   // Allow subclases such as CommonCompilerTest to add extra options.
-  virtual void SetUpRuntimeOptions(RuntimeOptions* options) {}
+  virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {}
 
   void ClearDirectory(const char* dirpath);
 
@@ -99,24 +106,30 @@
 
   std::string GetTestAndroidRoot();
 
-  std::vector<const DexFile*> OpenTestDexFiles(const char* name)
+  std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  std::unique_ptr<const DexFile> OpenTestDexFile(const char* name)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   std::string android_data_;
   std::string dalvik_cache_;
-  const DexFile* java_lang_dex_file_;  // owned by runtime_
-  std::vector<const DexFile*> boot_class_path_;
+
   std::unique_ptr<Runtime> runtime_;
-  // Owned by the runtime
+
+  // The class_linker_, java_lang_dex_file_, and boot_class_path_ are all
+  // owned by the runtime.
   ClassLinker* class_linker_;
+  const DexFile* java_lang_dex_file_;
+  std::vector<const DexFile*> boot_class_path_;
 
  private:
+  static std::string GetCoreFileLocation(const char* suffix);
+
   std::unique_ptr<CompilerCallbacks> callbacks_;
-  std::vector<const DexFile*> opened_dex_files_;
+  std::vector<std::unique_ptr<const DexFile>> loaded_dex_files_;
 };
 
 // Sets a CheckJni abort hook to catch failures. Note that this will cause CheckJNI to carry on
@@ -138,16 +151,6 @@
   DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher);
 };
 
-// TODO: These tests were disabled for portable when we went to having
-// MCLinker link LLVM ELF output because we no longer just have code
-// blobs in memory. We'll need to dlopen to load and relocate
-// temporary output to resurrect these tests.
-#define TEST_DISABLED_FOR_PORTABLE() \
-  if (kUsePortableCompiler) { \
-    printf("WARNING: TEST DISABLED FOR PORTABLE\n"); \
-    return; \
-  }
-
 // TODO: When heap reference poisoning works with the compiler, get rid of this.
 #define TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING() \
   if (kPoisonHeapReferences) { \
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 846216c..f5b4354 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -418,6 +418,10 @@
       break;
     }
     case Instruction::IGET_QUICK:
+    case Instruction::IGET_BOOLEAN_QUICK:
+    case Instruction::IGET_BYTE_QUICK:
+    case Instruction::IGET_CHAR_QUICK:
+    case Instruction::IGET_SHORT_QUICK:
     case Instruction::IGET_WIDE_QUICK:
     case Instruction::IGET_OBJECT_QUICK: {
       // Since we replaced the field index, we ask the verifier to tell us which
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 96b44bf..c63e2d7 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -25,13 +25,11 @@
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
-#include "field_helper.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
 #include "handle_scope.h"
 #include "jdwp/object_registry.h"
-#include "method_helper.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class.h"
@@ -183,16 +181,20 @@
 
 class Breakpoint {
  public:
-  Breakpoint(mirror::ArtMethod* method, uint32_t dex_pc, bool need_full_deoptimization)
+  Breakpoint(mirror::ArtMethod* method, uint32_t dex_pc,
+             DeoptimizationRequest::Kind deoptimization_kind)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-    : method_(nullptr), dex_pc_(dex_pc), need_full_deoptimization_(need_full_deoptimization) {
+    : method_(nullptr), dex_pc_(dex_pc), deoptimization_kind_(deoptimization_kind) {
+    CHECK(deoptimization_kind_ == DeoptimizationRequest::kNothing ||
+          deoptimization_kind_ == DeoptimizationRequest::kSelectiveDeoptimization ||
+          deoptimization_kind_ == DeoptimizationRequest::kFullDeoptimization);
     ScopedObjectAccessUnchecked soa(Thread::Current());
     method_ = soa.EncodeMethod(method);
   }
 
   Breakpoint(const Breakpoint& other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     : method_(nullptr), dex_pc_(other.dex_pc_),
-      need_full_deoptimization_(other.need_full_deoptimization_) {
+      deoptimization_kind_(other.deoptimization_kind_) {
     ScopedObjectAccessUnchecked soa(Thread::Current());
     method_ = soa.EncodeMethod(other.Method());
   }
@@ -206,8 +208,8 @@
     return dex_pc_;
   }
 
-  bool NeedFullDeoptimization() const {
-    return need_full_deoptimization_;
+  DeoptimizationRequest::Kind GetDeoptimizationKind() const {
+    return deoptimization_kind_;
   }
 
  private:
@@ -216,7 +218,7 @@
   uint32_t dex_pc_;
 
   // Indicates whether breakpoint needs full deoptimization or selective deoptimization.
-  bool need_full_deoptimization_;
+  DeoptimizationRequest::Kind deoptimization_kind_;
 };
 
 static std::ostream& operator<<(std::ostream& os, const Breakpoint& rhs)
@@ -231,7 +233,7 @@
   virtual ~DebugInstrumentationListener() {}
 
   void MethodEntered(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method,
-                     uint32_t dex_pc)
+                     uint32_t dex_pc ATTRIBUTE_UNUSED)
       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (method->IsNative()) {
       // TODO: post location events is a suspension point and native method entry stubs aren't.
@@ -254,6 +256,7 @@
                     uint32_t dex_pc)
       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // We're not recorded to listen to this kind of event, so complain.
+    UNUSED(thread, this_object, method, dex_pc);
     LOG(ERROR) << "Unexpected method unwind event in debugger " << PrettyMethod(method)
                << " " << dex_pc;
   }
@@ -267,16 +270,18 @@
   void FieldRead(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method,
                  uint32_t dex_pc, mirror::ArtField* field)
       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    UNUSED(thread);
     Dbg::PostFieldAccessEvent(method, dex_pc, this_object, field);
   }
 
-  void FieldWritten(Thread* thread, mirror::Object* this_object, mirror::ArtMethod* method,
-                    uint32_t dex_pc, mirror::ArtField* field, const JValue& field_value)
+  void FieldWritten(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object,
+                    mirror::ArtMethod* method, uint32_t dex_pc, mirror::ArtField* field,
+                    const JValue& field_value)
       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     Dbg::PostFieldModificationEvent(method, dex_pc, this_object, field, &field_value);
   }
 
-  void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location,
+  void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, const ThrowLocation& throw_location,
                        mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
                        mirror::Throwable* exception_object)
       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -337,19 +342,18 @@
 // Breakpoints.
 static std::vector<Breakpoint> gBreakpoints GUARDED_BY(Locks::breakpoint_lock_);
 
-void DebugInvokeReq::VisitRoots(RootCallback* callback, void* arg, uint32_t tid,
-                                RootType root_type) {
+void DebugInvokeReq::VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info) {
   if (receiver != nullptr) {
-    callback(&receiver, arg, tid, root_type);
+    callback(&receiver, arg, root_info);
   }
   if (thread != nullptr) {
-    callback(&thread, arg, tid, root_type);
+    callback(&thread, arg, root_info);
   }
   if (klass != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&klass), arg, tid, root_type);
+    callback(reinterpret_cast<mirror::Object**>(&klass), arg, root_info);
   }
   if (method != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&method), arg, tid, root_type);
+    callback(reinterpret_cast<mirror::Object**>(&method), arg, root_info);
   }
 }
 
@@ -361,10 +365,9 @@
   method = nullptr;
 }
 
-void SingleStepControl::VisitRoots(RootCallback* callback, void* arg, uint32_t tid,
-                                   RootType root_type) {
+void SingleStepControl::VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info) {
   if (method != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&method), arg, tid, root_type);
+    callback(reinterpret_cast<mirror::Object**>(&method), arg, root_info);
   }
 }
 
@@ -617,7 +620,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('=');
@@ -664,9 +667,7 @@
   // This may cause us to suspend all threads.
   if (gJdwpState->IsActive()) {
     ScopedObjectAccess soa(Thread::Current());
-    if (!gJdwpState->PostVMStart()) {
-      LOG(WARNING) << "Failed to post 'start' message to debugger";
-    }
+    gJdwpState->PostVMStart();
   }
 }
 
@@ -733,6 +734,12 @@
   return gDisposed;
 }
 
+bool Dbg::RequiresDeoptimization() {
+  // We don't need deoptimization if everything runs with interpreter after
+  // enabling -Xint mode.
+  return !Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly();
+}
+
 void Dbg::GoActive() {
   // Enable all debugging features, including scans for breakpoints.
   // This is a no-op if we're already active.
@@ -765,7 +772,9 @@
   Thread* self = Thread::Current();
   ThreadState old_state = self->SetStateUnsafe(kRunnable);
   CHECK_NE(old_state, kRunnable);
-  runtime->GetInstrumentation()->EnableDeoptimization();
+  if (RequiresDeoptimization()) {
+    runtime->GetInstrumentation()->EnableDeoptimization();
+  }
   instrumentation_events_ = 0;
   gDebuggerActive = true;
   CHECK_EQ(self->SetStateUnsafe(old_state), kRunnable);
@@ -803,13 +812,20 @@
                                                     instrumentation_events_);
       instrumentation_events_ = 0;
     }
-    runtime->GetInstrumentation()->DisableDeoptimization();
+    if (RequiresDeoptimization()) {
+      runtime->GetInstrumentation()->DisableDeoptimization();
+    }
     gDebuggerActive = false;
   }
-  gRegistry->Clear();
-  gDebuggerConnected = false;
   CHECK_EQ(self->SetStateUnsafe(old_state), kRunnable);
   runtime->GetThreadList()->ResumeAll();
+
+  {
+    ScopedObjectAccess soa(self);
+    gRegistry->Clear();
+  }
+
+  gDebuggerConnected = false;
 }
 
 bool Dbg::IsDebuggerActive() {
@@ -1143,7 +1159,7 @@
   // the primitive types).
   // Returns a newly-allocated buffer full of RefTypeId values.
   struct ClassListCreator {
-    explicit ClassListCreator(std::vector<JDWP::RefTypeId>* classes) : classes(classes) {
+    explicit ClassListCreator(std::vector<JDWP::RefTypeId>* classes_in) : classes(classes_in) {
     }
 
     static bool Visit(mirror::Class* c, void* arg) {
@@ -1383,7 +1399,6 @@
     mirror::ObjectArray<mirror::Object>* oa = dst->AsObjectArray<mirror::Object>();
     for (int i = 0; i < count; ++i) {
       JDWP::ObjectId id = request->ReadObjectId();
-      JDWP::JdwpError error;
       mirror::Object* o = gRegistry->Get<mirror::Object*>(id, &error);
       if (error != JDWP::ERR_NONE) {
         return error;
@@ -1908,7 +1923,7 @@
         HandleWrapper<mirror::Object> h_v(hs.NewHandleWrapper(&v));
         HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
         HandleWrapper<mirror::Object> h_o(hs.NewHandleWrapper(&o));
-        field_type = FieldHelper(h_f).GetType();
+        field_type = h_f->GetType(true);
       }
       if (!field_type->IsAssignableFrom(v->GetClass())) {
         return JDWP::ERR_INVALID_OBJECT;
@@ -2017,7 +2032,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 +2073,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 +2092,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 +2107,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);
@@ -2174,6 +2194,7 @@
     case kWaitingForJniOnLoad:
     case kWaitingForMethodTracingStart:
     case kWaitingForSignalCatcherOutput:
+    case kWaitingForVisitObjects:
     case kWaitingInMainDebuggerLoop:
     case kWaitingInMainSignalCatcherLoop:
     case kWaitingPerformingGc:
@@ -2283,8 +2304,8 @@
 
 static int GetStackDepth(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   struct CountStackDepthVisitor : public StackVisitor {
-    explicit CountStackDepthVisitor(Thread* thread)
-        : StackVisitor(thread, nullptr), depth(0) {}
+    explicit CountStackDepthVisitor(Thread* thread_in)
+        : StackVisitor(thread_in, nullptr), depth(0) {}
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
@@ -2322,10 +2343,11 @@
                                      size_t frame_count, JDWP::ExpandBuf* buf) {
   class GetFrameVisitor : public StackVisitor {
    public:
-    GetFrameVisitor(Thread* thread, size_t start_frame, size_t frame_count, JDWP::ExpandBuf* buf)
+    GetFrameVisitor(Thread* thread, size_t start_frame_in, size_t frame_count_in,
+                    JDWP::ExpandBuf* buf_in)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
         : StackVisitor(thread, nullptr), depth_(0),
-          start_frame_(start_frame), frame_count_(frame_count), buf_(buf) {
+          start_frame_(start_frame_in), frame_count_(frame_count_in), buf_(buf_in) {
       expandBufAdd4BE(buf_, frame_count_);
     }
 
@@ -2386,7 +2408,7 @@
 }
 
 void Dbg::ResumeVM() {
-  Runtime::Current()->GetThreadList()->UndoDebuggerSuspensions();
+  Runtime::Current()->GetThreadList()->ResumeAllForDebugger();
 }
 
 JDWP::JdwpError Dbg::SuspendThread(JDWP::ObjectId thread_id, bool request_suspension) {
@@ -2400,9 +2422,7 @@
   if (peer.get() == nullptr) {
     return JDWP::ERR_THREAD_NOT_ALIVE;
   }
-  // Suspend thread to build stack trace. Take suspend thread lock to avoid races with threads
-  // trying to suspend this one.
-  MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_);
+  // Suspend thread to build stack trace.
   bool timed_out;
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   Thread* thread = thread_list->SuspendThreadByPeer(peer.get(), request_suspension, true,
@@ -2445,9 +2465,9 @@
 }
 
 struct GetThisVisitor : public StackVisitor {
-  GetThisVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id)
+  GetThisVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id_in)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, context), this_object(nullptr), frame_id(frame_id) {}
+      : StackVisitor(thread, context), this_object(nullptr), frame_id(frame_id_in) {}
 
   // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
   // annotalysis.
@@ -2551,7 +2571,7 @@
     VLOG(jdwp) << "    --> slot " << slot << " " << reqSigByte;
 
     size_t width = Dbg::GetTagWidth(reqSigByte);
-    uint8_t* ptr = expandBufAddSpace(pReply, width+1);
+    uint8_t* ptr = expandBufAddSpace(pReply, width + 1);
     JDWP::JdwpError error = Dbg::GetLocalValue(visitor, soa, slot, reqSigByte, ptr, width);
     if (error != JDWP::ERR_NONE) {
       return error;
@@ -3029,9 +3049,11 @@
 }
 
 void Dbg::DelayFullUndeoptimization() {
-  MutexLock mu(Thread::Current(), *Locks::deoptimization_lock_);
-  ++delayed_full_undeoptimization_count_;
-  DCHECK_LE(delayed_full_undeoptimization_count_, full_deoptimization_event_count_);
+  if (RequiresDeoptimization()) {
+    MutexLock mu(Thread::Current(), *Locks::deoptimization_lock_);
+    ++delayed_full_undeoptimization_count_;
+    DCHECK_LE(delayed_full_undeoptimization_count_, full_deoptimization_event_count_);
+  }
 }
 
 void Dbg::ProcessDelayedFullUndeoptimizations() {
@@ -3174,7 +3196,7 @@
   Handle<mirror::ArtMethod> method(hs.NewHandle(m));
   verifier::MethodVerifier verifier(self, dex_cache->GetDexFile(), dex_cache, class_loader,
                                     &m->GetClassDef(), code_item, m->GetDexMethodIndex(), method,
-                                    m->GetAccessFlags(), false, true, false);
+                                    m->GetAccessFlags(), false, true, false, true);
   // Note: we don't need to verify the method.
   return InlineMethodAnalyser::AnalyseMethodCode(&verifier, nullptr);
 }
@@ -3190,20 +3212,92 @@
 }
 
 // Sanity checks all existing breakpoints on the same method.
-static void SanityCheckExistingBreakpoints(mirror::ArtMethod* m, bool need_full_deoptimization)
+static void SanityCheckExistingBreakpoints(mirror::ArtMethod* m,
+                                           DeoptimizationRequest::Kind deoptimization_kind)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::breakpoint_lock_) {
   for (const Breakpoint& breakpoint : gBreakpoints) {
-    CHECK_EQ(need_full_deoptimization, breakpoint.NeedFullDeoptimization());
+    if (breakpoint.Method() == m) {
+      CHECK_EQ(deoptimization_kind, breakpoint.GetDeoptimizationKind());
+    }
   }
-  if (need_full_deoptimization) {
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (deoptimization_kind == DeoptimizationRequest::kFullDeoptimization) {
     // We should have deoptimized everything but not "selectively" deoptimized this method.
-    CHECK(Runtime::Current()->GetInstrumentation()->AreAllMethodsDeoptimized());
-    CHECK(!Runtime::Current()->GetInstrumentation()->IsDeoptimized(m));
-  } else {
+    CHECK(instrumentation->AreAllMethodsDeoptimized());
+    CHECK(!instrumentation->IsDeoptimized(m));
+  } else if (deoptimization_kind == DeoptimizationRequest::kSelectiveDeoptimization) {
     // We should have "selectively" deoptimized this method.
     // Note: while we have not deoptimized everything for this method, we may have done it for
     // another event.
-    CHECK(Runtime::Current()->GetInstrumentation()->IsDeoptimized(m));
+    CHECK(instrumentation->IsDeoptimized(m));
+  } else {
+    // This method does not require deoptimization.
+    CHECK_EQ(deoptimization_kind, DeoptimizationRequest::kNothing);
+    CHECK(!instrumentation->IsDeoptimized(m));
+  }
+}
+
+// Returns the deoptimization kind required to set a breakpoint in a method.
+// If a breakpoint has already been set, we also return the first breakpoint
+// through the given 'existing_brkpt' pointer.
+static DeoptimizationRequest::Kind GetRequiredDeoptimizationKind(Thread* self,
+                                                                 mirror::ArtMethod* m,
+                                                                 const Breakpoint** existing_brkpt)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (!Dbg::RequiresDeoptimization()) {
+    // We already run in interpreter-only mode so we don't need to deoptimize anything.
+    VLOG(jdwp) << "No need for deoptimization when fully running with interpreter for method "
+               << PrettyMethod(m);
+    return DeoptimizationRequest::kNothing;
+  }
+  const Breakpoint* first_breakpoint;
+  {
+    ReaderMutexLock mu(self, *Locks::breakpoint_lock_);
+    first_breakpoint = FindFirstBreakpointForMethod(m);
+    *existing_brkpt = first_breakpoint;
+  }
+
+  if (first_breakpoint == nullptr) {
+    // There is no breakpoint on this method yet: we need to deoptimize. If this method may be
+    // inlined, we deoptimize everything; otherwise we deoptimize only this method.
+    // Note: IsMethodPossiblyInlined goes into the method verifier and may cause thread suspension.
+    // Therefore we must not hold any lock when we call it.
+    bool need_full_deoptimization = IsMethodPossiblyInlined(self, m);
+    if (need_full_deoptimization) {
+      VLOG(jdwp) << "Need full deoptimization because of possible inlining of method "
+                 << PrettyMethod(m);
+      return DeoptimizationRequest::kFullDeoptimization;
+    } else {
+      // We don't need to deoptimize if the method has not been compiled.
+      ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+      const bool is_compiled = class_linker->GetOatMethodQuickCodeFor(m) != nullptr;
+      if (is_compiled) {
+        // If the method may be called through its direct code pointer (without loading
+        // its updated entrypoint), we need full deoptimization to not miss the breakpoint.
+        if (class_linker->MayBeCalledWithDirectCodePointer(m)) {
+          VLOG(jdwp) << "Need full deoptimization because of possible direct code call "
+                     << "into image for compiled method " << PrettyMethod(m);
+          return DeoptimizationRequest::kFullDeoptimization;
+        } else {
+          VLOG(jdwp) << "Need selective deoptimization for compiled method " << PrettyMethod(m);
+          return DeoptimizationRequest::kSelectiveDeoptimization;
+        }
+      } else {
+        // Method is not compiled: we don't need to deoptimize.
+        VLOG(jdwp) << "No need for deoptimization for non-compiled method " << PrettyMethod(m);
+        return DeoptimizationRequest::kNothing;
+      }
+    }
+  } else {
+    // There is at least one breakpoint for this method: we don't need to deoptimize.
+    // Let's check that all breakpoints are configured the same way for deoptimization.
+    VLOG(jdwp) << "Breakpoint already set: no deoptimization is required";
+    DeoptimizationRequest::Kind deoptimization_kind = first_breakpoint->GetDeoptimizationKind();
+    if (kIsDebugBuild) {
+      ReaderMutexLock mu(self, *Locks::breakpoint_lock_);
+      SanityCheckExistingBreakpoints(m, deoptimization_kind);
+    }
+    return DeoptimizationRequest::kNothing;
   }
 }
 
@@ -3214,40 +3308,29 @@
   mirror::ArtMethod* m = FromMethodId(location->method_id);
   DCHECK(m != nullptr) << "No method for method id " << location->method_id;
 
-  const Breakpoint* existing_breakpoint;
-  {
-    ReaderMutexLock mu(self, *Locks::breakpoint_lock_);
-    existing_breakpoint = FindFirstBreakpointForMethod(m);
-  }
-  bool need_full_deoptimization;
-  if (existing_breakpoint == nullptr) {
-    // There is no breakpoint on this method yet: we need to deoptimize. If this method may be
-    // inlined, we deoptimize everything; otherwise we deoptimize only this method.
-    // Note: IsMethodPossiblyInlined goes into the method verifier and may cause thread suspension.
-    // Therefore we must not hold any lock when we call it.
-    need_full_deoptimization = IsMethodPossiblyInlined(self, m);
-    if (need_full_deoptimization) {
-      req->SetKind(DeoptimizationRequest::kFullDeoptimization);
-      req->SetMethod(nullptr);
-    } else {
-      req->SetKind(DeoptimizationRequest::kSelectiveDeoptimization);
-      req->SetMethod(m);
-    }
+  const Breakpoint* existing_breakpoint = nullptr;
+  const DeoptimizationRequest::Kind deoptimization_kind =
+      GetRequiredDeoptimizationKind(self, m, &existing_breakpoint);
+  req->SetKind(deoptimization_kind);
+  if (deoptimization_kind == DeoptimizationRequest::kSelectiveDeoptimization) {
+    req->SetMethod(m);
   } else {
-    // There is at least one breakpoint for this method: we don't need to deoptimize.
-    req->SetKind(DeoptimizationRequest::kNothing);
+    CHECK(deoptimization_kind == DeoptimizationRequest::kNothing ||
+          deoptimization_kind == DeoptimizationRequest::kFullDeoptimization);
     req->SetMethod(nullptr);
-
-    need_full_deoptimization = existing_breakpoint->NeedFullDeoptimization();
-    if (kIsDebugBuild) {
-      ReaderMutexLock mu(self, *Locks::breakpoint_lock_);
-      SanityCheckExistingBreakpoints(m, need_full_deoptimization);
-    }
   }
 
   {
     WriterMutexLock mu(self, *Locks::breakpoint_lock_);
-    gBreakpoints.push_back(Breakpoint(m, location->dex_pc, need_full_deoptimization));
+    // If there is at least one existing breakpoint on the same method, the new breakpoint
+    // must have the same deoptimization kind than the existing breakpoint(s).
+    DeoptimizationRequest::Kind breakpoint_deoptimization_kind;
+    if (existing_breakpoint != nullptr) {
+      breakpoint_deoptimization_kind = existing_breakpoint->GetDeoptimizationKind();
+    } else {
+      breakpoint_deoptimization_kind = deoptimization_kind;
+    }
+    gBreakpoints.push_back(Breakpoint(m, location->dex_pc, breakpoint_deoptimization_kind));
     VLOG(jdwp) << "Set breakpoint #" << (gBreakpoints.size() - 1) << ": "
                << gBreakpoints[gBreakpoints.size() - 1];
   }
@@ -3259,12 +3342,13 @@
   WriterMutexLock mu(Thread::Current(), *Locks::breakpoint_lock_);
   mirror::ArtMethod* m = FromMethodId(location->method_id);
   DCHECK(m != nullptr) << "No method for method id " << location->method_id;
-  bool need_full_deoptimization = false;
+  DeoptimizationRequest::Kind deoptimization_kind = DeoptimizationRequest::kNothing;
   for (size_t i = 0, e = gBreakpoints.size(); i < e; ++i) {
     if (gBreakpoints[i].DexPc() == location->dex_pc && gBreakpoints[i].Method() == m) {
       VLOG(jdwp) << "Removed breakpoint #" << i << ": " << gBreakpoints[i];
-      need_full_deoptimization = gBreakpoints[i].NeedFullDeoptimization();
-      DCHECK_NE(need_full_deoptimization, Runtime::Current()->GetInstrumentation()->IsDeoptimized(m));
+      deoptimization_kind = gBreakpoints[i].GetDeoptimizationKind();
+      DCHECK_EQ(deoptimization_kind == DeoptimizationRequest::kSelectiveDeoptimization,
+                Runtime::Current()->GetInstrumentation()->IsDeoptimized(m));
       gBreakpoints.erase(gBreakpoints.begin() + i);
       break;
     }
@@ -3272,21 +3356,26 @@
   const Breakpoint* const existing_breakpoint = FindFirstBreakpointForMethod(m);
   if (existing_breakpoint == nullptr) {
     // There is no more breakpoint on this method: we need to undeoptimize.
-    if (need_full_deoptimization) {
+    if (deoptimization_kind == DeoptimizationRequest::kFullDeoptimization) {
       // This method required full deoptimization: we need to undeoptimize everything.
       req->SetKind(DeoptimizationRequest::kFullUndeoptimization);
       req->SetMethod(nullptr);
-    } else {
+    } else if (deoptimization_kind == DeoptimizationRequest::kSelectiveDeoptimization) {
       // This method required selective deoptimization: we need to undeoptimize only that method.
       req->SetKind(DeoptimizationRequest::kSelectiveUndeoptimization);
       req->SetMethod(m);
+    } else {
+      // This method had no need for deoptimization: do nothing.
+      CHECK_EQ(deoptimization_kind, DeoptimizationRequest::kNothing);
+      req->SetKind(DeoptimizationRequest::kNothing);
+      req->SetMethod(nullptr);
     }
   } else {
     // There is at least one breakpoint for this method: we don't need to undeoptimize.
     req->SetKind(DeoptimizationRequest::kNothing);
     req->SetMethod(nullptr);
     if (kIsDebugBuild) {
-      SanityCheckExistingBreakpoints(m, need_full_deoptimization);
+      SanityCheckExistingBreakpoints(m, deoptimization_kind);
     }
   }
 }
@@ -3314,13 +3403,9 @@
         soa.Self()->TransitionFromRunnableToSuspended(kWaitingForDebuggerSuspension);
         jobject thread_peer = Dbg::GetObjectRegistry()->GetJObject(thread_id);
         bool timed_out;
-        Thread* suspended_thread;
-        {
-          // Take suspend thread lock to avoid races with threads trying to suspend this one.
-          MutexLock mu(soa.Self(), *Locks::thread_list_suspend_thread_lock_);
-          ThreadList* thread_list = Runtime::Current()->GetThreadList();
-          suspended_thread = thread_list->SuspendThreadByPeer(thread_peer, true, true, &timed_out);
-        }
+        ThreadList* thread_list = Runtime::Current()->GetThreadList();
+        Thread* suspended_thread = thread_list->SuspendThreadByPeer(thread_peer, true, true,
+                                                                    &timed_out);
         CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kWaitingForDebuggerSuspension);
         if (suspended_thread == nullptr) {
           // Thread terminated from under us while suspending.
@@ -3413,15 +3498,15 @@
   //
 
   struct DebugCallbackContext {
-    explicit DebugCallbackContext(SingleStepControl* single_step_control, int32_t line_number,
+    explicit DebugCallbackContext(SingleStepControl* single_step_control_cb, int32_t line_number_cb,
                                   const DexFile::CodeItem* code_item)
-      : single_step_control_(single_step_control), line_number_(line_number), code_item_(code_item),
-        last_pc_valid(false), last_pc(0) {
+      : single_step_control_(single_step_control_cb), line_number_(line_number_cb),
+        code_item_(code_item), last_pc_valid(false), last_pc(0) {
     }
 
-    static bool Callback(void* raw_context, uint32_t address, uint32_t line_number) {
+    static bool Callback(void* raw_context, uint32_t address, uint32_t line_number_cb) {
       DebugCallbackContext* context = reinterpret_cast<DebugCallbackContext*>(raw_context);
-      if (static_cast<int32_t>(line_number) == context->line_number_) {
+      if (static_cast<int32_t>(line_number_cb) == context->line_number_) {
         if (!context->last_pc_valid) {
           // Everything from this address until the next line change is ours.
           context->last_pc = address;
@@ -3504,6 +3589,7 @@
   switch (tag) {
     default:
       LOG(FATAL) << "unknown JDWP tag: " << PrintableChar(tag);
+      UNREACHABLE();
 
     // Primitives.
     case JDWP::JT_BYTE:    return 'B';
@@ -3617,7 +3703,7 @@
 
     {
       StackHandleScope<3> hs(soa.Self());
-      MethodHelper mh(hs.NewHandle(m));
+      HandleWrapper<mirror::ArtMethod> h_m(hs.NewHandleWrapper(&m));
       HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&receiver));
       HandleWrapper<mirror::Class> h_klass(hs.NewHandleWrapper(&c));
       const DexFile::TypeList* types = m->GetParameterTypeList();
@@ -3628,7 +3714,8 @@
 
         if (shorty[i + 1] == 'L') {
           // Did we really get an argument of an appropriate reference type?
-          mirror::Class* parameter_type = mh.GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
+          mirror::Class* parameter_type =
+              h_m->GetClassFromTypeIndex(types->GetTypeItem(i).type_idx_, true);
           mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i], &error);
           if (error != JDWP::ERR_NONE) {
             return JDWP::ERR_INVALID_OBJECT;
@@ -3642,8 +3729,6 @@
           v.l = gRegistry->GetJObject(arg_values[i]);
         }
       }
-      // Update in case it moved.
-      m = mh.GetMethod();
     }
 
     req->receiver = receiver;
@@ -4008,6 +4093,10 @@
   }
 }
 
+JDWP::JdwpState* Dbg::GetJdwpState() {
+  return gJdwpState;
+}
+
 int Dbg::DdmHandleHpifChunk(HpifWhen when) {
   if (when == HPIF_WHEN_NOW) {
     DdmSendHeapInfo(when);
@@ -4115,7 +4204,6 @@
   HeapChunkContext(bool merge, bool native)
       : buf_(16384 - 16),
         type_(0),
-        merge_(merge),
         chunk_overhead_(0) {
     Reset();
     if (native) {
@@ -4172,10 +4260,15 @@
     Reset();
   }
 
-  static void HeapChunkCallback(void* start, void* end, size_t used_bytes, void* arg)
+  static void HeapChunkJavaCallback(void* start, void* end, size_t used_bytes, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
                             Locks::mutator_lock_) {
-    reinterpret_cast<HeapChunkContext*>(arg)->HeapChunkCallback(start, end, used_bytes);
+    reinterpret_cast<HeapChunkContext*>(arg)->HeapChunkJavaCallback(start, end, used_bytes);
+  }
+
+  static void HeapChunkNativeCallback(void* start, void* end, size_t used_bytes, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    reinterpret_cast<HeapChunkContext*>(arg)->HeapChunkNativeCallback(start, end, used_bytes);
   }
 
  private:
@@ -4189,72 +4282,85 @@
     pieceLenField_ = nullptr;
   }
 
-  void HeapChunkCallback(void* start, void* /*end*/, size_t used_bytes)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
-                            Locks::mutator_lock_) {
+  bool IsNative() const {
+    return type_ == CHUNK_TYPE("NHSG");
+  }
+
+  // Returns true if the object is not an empty chunk.
+  bool ProcessRecord(void* start, size_t used_bytes) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Note: heap call backs cannot manipulate the heap upon which they are crawling, care is taken
     // in the following code not to allocate memory, by ensuring buf_ is of the correct size
     if (used_bytes == 0) {
-        if (start == nullptr) {
-            // Reset for start of new heap.
-            startOfNextMemoryChunk_ = nullptr;
-            Flush();
-        }
-        // Only process in use memory so that free region information
-        // also includes dlmalloc book keeping.
-        return;
+      if (start == nullptr) {
+        // Reset for start of new heap.
+        startOfNextMemoryChunk_ = nullptr;
+        Flush();
+      }
+      // Only process in use memory so that free region information
+      // also includes dlmalloc book keeping.
+      return false;
     }
-
-    /* If we're looking at the native heap, we'll just return
-     * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks
-     */
-    bool native = type_ == CHUNK_TYPE("NHSG");
-
-    // TODO: I'm not sure using start of next chunk works well with multiple spaces. We shouldn't
-    // count gaps inbetween spaces as free memory.
     if (startOfNextMemoryChunk_ != nullptr) {
-        // Transmit any pending free memory. Native free memory of
-        // over kMaxFreeLen could be because of the use of mmaps, so
-        // don't report. If not free memory then start a new segment.
-        bool flush = true;
-        if (start > startOfNextMemoryChunk_) {
-            const size_t kMaxFreeLen = 2 * kPageSize;
-            void* freeStart = startOfNextMemoryChunk_;
-            void* freeEnd = start;
-            size_t freeLen = reinterpret_cast<char*>(freeEnd) - reinterpret_cast<char*>(freeStart);
-            if (!native || freeLen < kMaxFreeLen) {
-                AppendChunk(HPSG_STATE(SOLIDITY_FREE, 0), freeStart, freeLen);
-                flush = false;
-            }
+      // Transmit any pending free memory. Native free memory of over kMaxFreeLen could be because
+      // of the use of mmaps, so don't report. If not free memory then start a new segment.
+      bool flush = true;
+      if (start > startOfNextMemoryChunk_) {
+        const size_t kMaxFreeLen = 2 * kPageSize;
+        void* free_start = startOfNextMemoryChunk_;
+        void* free_end = start;
+        const size_t free_len =
+            reinterpret_cast<uintptr_t>(free_end) - reinterpret_cast<uintptr_t>(free_start);
+        if (!IsNative() || free_len < kMaxFreeLen) {
+          AppendChunk(HPSG_STATE(SOLIDITY_FREE, 0), free_start, free_len, IsNative());
+          flush = false;
         }
-        if (flush) {
-            startOfNextMemoryChunk_ = nullptr;
-            Flush();
-        }
+      }
+      if (flush) {
+        startOfNextMemoryChunk_ = nullptr;
+        Flush();
+      }
     }
-    mirror::Object* obj = reinterpret_cast<mirror::Object*>(start);
-
-    // Determine the type of this chunk.
-    // OLD-TODO: if context.merge, see if this chunk is different from the last chunk.
-    // If it's the same, we should combine them.
-    uint8_t state = ExamineObject(obj, native);
-    AppendChunk(state, start, used_bytes + chunk_overhead_);
-    startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + chunk_overhead_;
+    return true;
   }
 
-  void AppendChunk(uint8_t state, void* ptr, size_t length)
+  void HeapChunkNativeCallback(void* start, void* /*end*/, size_t used_bytes)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (ProcessRecord(start, used_bytes)) {
+      uint8_t state = ExamineNativeObject(start);
+      AppendChunk(state, start, used_bytes + chunk_overhead_, true /*is_native*/);
+      startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + chunk_overhead_;
+    }
+  }
+
+  void HeapChunkJavaCallback(void* start, void* /*end*/, size_t used_bytes)
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
+    if (ProcessRecord(start, used_bytes)) {
+      // Determine the type of this chunk.
+      // OLD-TODO: if context.merge, see if this chunk is different from the last chunk.
+      // If it's the same, we should combine them.
+      uint8_t state = ExamineJavaObject(reinterpret_cast<mirror::Object*>(start));
+      AppendChunk(state, start, used_bytes + chunk_overhead_, false /*is_native*/);
+      startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + chunk_overhead_;
+    }
+  }
+
+  void AppendChunk(uint8_t state, void* ptr, size_t length, bool is_native)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Make sure there's enough room left in the buffer.
     // We need to use two bytes for every fractional 256 allocation units used by the chunk plus
     // 17 bytes for any header.
-    size_t needed = (((length/ALLOCATION_UNIT_SIZE + 255) / 256) * 2) + 17;
-    size_t bytesLeft = buf_.size() - (size_t)(p_ - &buf_[0]);
-    if (bytesLeft < needed) {
+    const size_t needed = ((RoundUp(length / ALLOCATION_UNIT_SIZE, 256) / 256) * 2) + 17;
+    size_t byte_left = &buf_.back() - p_;
+    if (byte_left < needed) {
+      if (is_native) {
+      // Cannot trigger memory allocation while walking native heap.
+        return;
+      }
       Flush();
     }
 
-    bytesLeft = buf_.size() - (size_t)(p_ - &buf_[0]);
-    if (bytesLeft < needed) {
+    byte_left = &buf_.back() - p_;
+    if (byte_left < needed) {
       LOG(WARNING) << "Chunk is too big to transmit (chunk_len=" << length << ", "
           << needed << " bytes)";
       return;
@@ -4272,43 +4378,34 @@
     *p_++ = length - 1;
   }
 
-  uint8_t ExamineObject(mirror::Object* o, bool is_native_heap)
+  uint8_t ExamineNativeObject(const void* p) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return p == nullptr ? HPSG_STATE(SOLIDITY_FREE, 0) : HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
+  }
+
+  uint8_t ExamineJavaObject(mirror::Object* o)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
     if (o == nullptr) {
       return HPSG_STATE(SOLIDITY_FREE, 0);
     }
-
     // It's an allocated chunk. Figure out what it is.
-
-    // If we're looking at the native heap, we'll just return
-    // (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks.
-    if (is_native_heap) {
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    if (!heap->IsLiveObjectLocked(o)) {
+      LOG(ERROR) << "Invalid object in managed heap: " << o;
       return HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
     }
-
-    if (!Runtime::Current()->GetHeap()->IsLiveObjectLocked(o)) {
-      return HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE);
-    }
-
     mirror::Class* c = o->GetClass();
     if (c == nullptr) {
       // The object was probably just created but hasn't been initialized yet.
       return HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
     }
-
-    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) {
+    if (!heap->IsValidObjectAddress(c)) {
       LOG(ERROR) << "Invalid class for managed heap object: " << o << " " << c;
       return HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN);
     }
-
     if (c->IsClassClass()) {
       return HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT);
     }
-
     if (c->IsArrayClass()) {
-      if (o->IsObjectArray()) {
-        return HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4);
-      }
       switch (c->GetComponentSize()) {
       case 1: return HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1);
       case 2: return HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2);
@@ -4316,7 +4413,6 @@
       case 8: return HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8);
       }
     }
-
     return HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT);
   }
 
@@ -4326,7 +4422,6 @@
   void* startOfNextMemoryChunk_;
   size_t totalAllocationUnits_;
   uint32_t type_;
-  bool merge_;
   bool needHeader_;
   size_t chunk_overhead_;
 
@@ -4336,45 +4431,33 @@
 static void BumpPointerSpaceCallback(mirror::Object* obj, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
   const size_t size = RoundUp(obj->SizeOf(), kObjectAlignment);
-  HeapChunkContext::HeapChunkCallback(
+  HeapChunkContext::HeapChunkJavaCallback(
       obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + size), size, arg);
 }
 
 void Dbg::DdmSendHeapSegments(bool native) {
-  Dbg::HpsgWhen when;
-  Dbg::HpsgWhat what;
-  if (!native) {
-    when = gDdmHpsgWhen;
-    what = gDdmHpsgWhat;
-  } else {
-    when = gDdmNhsgWhen;
-    what = gDdmNhsgWhat;
-  }
+  Dbg::HpsgWhen when = native ? gDdmNhsgWhen : gDdmHpsgWhen;
+  Dbg::HpsgWhat what = native ? gDdmNhsgWhat : gDdmHpsgWhat;
   if (when == HPSG_WHEN_NEVER) {
     return;
   }
-
   // Figure out what kind of chunks we'll be sending.
-  CHECK(what == HPSG_WHAT_MERGED_OBJECTS || what == HPSG_WHAT_DISTINCT_OBJECTS) << static_cast<int>(what);
+  CHECK(what == HPSG_WHAT_MERGED_OBJECTS || what == HPSG_WHAT_DISTINCT_OBJECTS)
+      << static_cast<int>(what);
 
   // First, send a heap start chunk.
   uint8_t heap_id[4];
   JDWP::Set4BE(&heap_id[0], 1);  // Heap id (bogus; we only have one heap).
   Dbg::DdmSendChunk(native ? CHUNK_TYPE("NHST") : CHUNK_TYPE("HPST"), sizeof(heap_id), heap_id);
-
   Thread* self = Thread::Current();
-
-  // To allow the Walk/InspectAll() below to exclusively-lock the
-  // mutator lock, temporarily release the shared access to the
-  // mutator lock here by transitioning to the suspended state.
   Locks::mutator_lock_->AssertSharedHeld(self);
-  self->TransitionFromRunnableToSuspended(kSuspended);
 
   // Send a series of heap segment chunks.
-  HeapChunkContext context((what == HPSG_WHAT_MERGED_OBJECTS), native);
+  HeapChunkContext context(what == HPSG_WHAT_MERGED_OBJECTS, native);
   if (native) {
-#ifdef USE_DLMALLOC
-    dlmalloc_inspect_all(HeapChunkContext::HeapChunkCallback, &context);
+#if defined(HAVE_ANDROID_OS) && defined(USE_DLMALLOC)
+    dlmalloc_inspect_all(HeapChunkContext::HeapChunkNativeCallback, &context);
+    HeapChunkContext::HeapChunkNativeCallback(nullptr, nullptr, 0, &context);  // Indicate end of a space.
 #else
     UNIMPLEMENTED(WARNING) << "Native heap inspection is only supported with dlmalloc";
 #endif
@@ -4382,32 +4465,40 @@
     gc::Heap* heap = Runtime::Current()->GetHeap();
     for (const auto& space : heap->GetContinuousSpaces()) {
       if (space->IsDlMallocSpace()) {
+        ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
         // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an
         // allocation then the first sizeof(size_t) may belong to it.
         context.SetChunkOverhead(sizeof(size_t));
-        space->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+        space->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkJavaCallback, &context);
       } else if (space->IsRosAllocSpace()) {
         context.SetChunkOverhead(0);
-        space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+        // Need to acquire the mutator lock before the heap bitmap lock with exclusive access since
+        // RosAlloc's internal logic doesn't know to release and reacquire the heap bitmap lock.
+        self->TransitionFromRunnableToSuspended(kSuspended);
+        ThreadList* tl = Runtime::Current()->GetThreadList();
+        tl->SuspendAll();
+        {
+          ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+          space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkJavaCallback, &context);
+        }
+        tl->ResumeAll();
+        self->TransitionFromSuspendedToRunnable();
       } else if (space->IsBumpPointerSpace()) {
+        ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
         context.SetChunkOverhead(0);
-        ReaderMutexLock mu(self, *Locks::mutator_lock_);
-        WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_);
         space->AsBumpPointerSpace()->Walk(BumpPointerSpaceCallback, &context);
+        HeapChunkContext::HeapChunkJavaCallback(nullptr, nullptr, 0, &context);
       } else {
         UNIMPLEMENTED(WARNING) << "Not counting objects in space " << *space;
       }
       context.ResetStartOfNextChunk();
     }
+    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
     // Walk the large objects, these are not in the AllocSpace.
     context.SetChunkOverhead(0);
-    heap->GetLargeObjectsSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+    heap->GetLargeObjectsSpace()->Walk(HeapChunkContext::HeapChunkJavaCallback, &context);
   }
 
-  // Shared-lock the mutator lock back.
-  self->TransitionFromSuspendedToRunnable();
-  Locks::mutator_lock_->AssertSharedHeld(self);
-
   // Finally, send a heap end chunk.
   Dbg::DdmSendChunk(native ? CHUNK_TYPE("NHEN") : CHUNK_TYPE("HPEN"), sizeof(heap_id), heap_id);
 }
@@ -4474,9 +4565,9 @@
 }
 
 struct AllocRecordStackVisitor : public StackVisitor {
-  AllocRecordStackVisitor(Thread* thread, AllocRecord* record)
+  AllocRecordStackVisitor(Thread* thread, AllocRecord* record_in)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, nullptr), record(record), depth(0) {}
+      : StackVisitor(thread, nullptr), record(record_in), depth(0) {}
 
   // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
   // annotalysis.
@@ -4674,7 +4765,7 @@
  * between the contents of these tables.
  */
 jbyteArray Dbg::GetRecentAllocations() {
-  if (false) {
+  if ((false)) {
     DumpRecentAllocations();
   }
 
diff --git a/runtime/debugger.h b/runtime/debugger.h
index cb7adae..e79e8e4 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -28,6 +28,7 @@
 #include <string>
 #include <vector>
 
+#include "gc_root.h"
 #include "jdwp/jdwp.h"
 #include "jni.h"
 #include "jvalue.h"
@@ -87,7 +88,7 @@
   Mutex lock DEFAULT_MUTEX_ACQUIRED_AFTER;
   ConditionVariable cond GUARDED_BY(lock);
 
-  void VisitRoots(RootCallback* callback, void* arg, uint32_t tid, RootType root_type)
+  void VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void Clear();
@@ -122,7 +123,7 @@
   // single-step depth.
   int stack_depth;
 
-  void VisitRoots(RootCallback* callback, void* arg, uint32_t tid, RootType root_type)
+  void VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool ContainsDexPc(uint32_t dex_pc) const;
@@ -189,6 +190,7 @@
   // Method for selective deoptimization.
   jmethodID method_;
 };
+std::ostream& operator<<(std::ostream& os, const DeoptimizationRequest::Kind& rhs);
 
 class Dbg {
  public:
@@ -246,7 +248,9 @@
    */
   static int64_t LastDebuggerActivity();
 
-  static void UndoDebuggerSuspensions();
+  static void UndoDebuggerSuspensions()
+    LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                   Locks::thread_suspend_count_lock_);
 
   /*
    * Class, Object, Array
@@ -459,7 +463,9 @@
   static void SuspendVM()
       LOCKS_EXCLUDED(Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
-  static void ResumeVM();
+  static void ResumeVM()
+      LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                     Locks::thread_suspend_count_lock_);
   static JDWP::JdwpError SuspendThread(JDWP::ObjectId thread_id, bool request_suspension = true)
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
@@ -489,7 +495,7 @@
   /*
    * Debugger notification
    */
-  enum {
+  enum EventFlag {
     kBreakpoint     = 0x01,
     kSingleStep     = 0x02,
     kMethodEntry    = 0x04,
@@ -518,6 +524,9 @@
       LOCKS_EXCLUDED(Locks::breakpoint_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Indicates whether we need deoptimization for debugging.
+  static bool RequiresDeoptimization();
+
   // Records deoptimization request in the queue.
   static void RequestDeoptimization(const DeoptimizationRequest& req)
       LOCKS_EXCLUDED(Locks::deoptimization_lock_)
@@ -639,6 +648,8 @@
   static void SetJdwpLocation(JDWP::JdwpLocation* location, mirror::ArtMethod* m, uint32_t dex_pc)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  static JDWP::JdwpState* GetJdwpState();
+
  private:
   static JDWP::JdwpError GetLocalValue(const StackVisitor& visitor,
                                        ScopedObjectAccessUnchecked& soa, int slot,
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index e095c48..c68fdca 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -26,14 +26,14 @@
 namespace art {
 
 inline int32_t DexFile::GetStringLength(const StringId& string_id) const {
-  const byte* ptr = begin_ + string_id.string_data_off_;
+  const uint8_t* ptr = begin_ + string_id.string_data_off_;
   return DecodeUnsignedLeb128(&ptr);
 }
 
 inline const char* DexFile::GetStringDataAndUtf16Length(const StringId& string_id,
                                                         uint32_t* utf16_length) const {
   DCHECK(utf16_length != NULL) << GetLocation();
-  const byte* ptr = begin_ + string_id.string_data_off_;
+  const uint8_t* ptr = begin_ + string_id.string_data_off_;
   *utf16_length = DecodeUnsignedLeb128(&ptr);
   return reinterpret_cast<const char*>(ptr);
 }
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 6ef62c5..dc85f6c 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"
@@ -37,7 +39,6 @@
 #include "mirror/string.h"
 #include "os.h"
 #include "safe_map.h"
-#include "ScopedFd.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
 #include "utf-inl.h"
@@ -45,10 +46,15 @@
 #include "well_known_classes.h"
 #include "zip_archive.h"
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "ScopedFd.h"
+#pragma GCC diagnostic pop
+
 namespace art {
 
-const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
-const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' };
+const uint8_t DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
+const uint8_t DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' };
 
 static int OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) {
   CHECK(magic != NULL);
@@ -119,7 +125,8 @@
 }
 
 bool DexFile::Open(const char* filename, const char* location, std::string* error_msg,
-                   std::vector<const DexFile*>* dex_files) {
+                   std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is NULL";
   uint32_t magic;
   ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
   if (fd.get() == -1) {
@@ -133,7 +140,7 @@
     std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.release(), location, true,
                                                               error_msg));
     if (dex_file.get() != nullptr) {
-      dex_files->push_back(dex_file.release());
+      dex_files->push_back(std::move(dex_file));
       return true;
     } else {
       return false;
@@ -173,8 +180,8 @@
   }
 }
 
-const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify,
-                                 std::string* error_msg) {
+std::unique_ptr<const DexFile> DexFile::OpenFile(int fd, const char* location, bool verify,
+                                                 std::string* error_msg) {
   CHECK(location != nullptr);
   std::unique_ptr<MemMap> map;
   {
@@ -218,13 +225,14 @@
     return nullptr;
   }
 
-  return dex_file.release();
+  return dex_file;
 }
 
 const char* DexFile::kClassesDex = "classes.dex";
 
 bool DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg,
-                      std::vector<const  DexFile*>* dex_files) {
+                      std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is NULL";
   std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
   if (zip_archive.get() == nullptr) {
     DCHECK(!error_msg->empty());
@@ -233,21 +241,22 @@
   return DexFile::OpenFromZip(*zip_archive, location, error_msg, dex_files);
 }
 
-const DexFile* DexFile::OpenMemory(const std::string& location,
-                                   uint32_t location_checksum,
-                                   MemMap* mem_map,
-                                   std::string* error_msg) {
+std::unique_ptr<const DexFile> DexFile::OpenMemory(const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   MemMap* mem_map,
+                                                   std::string* error_msg) {
   return OpenMemory(mem_map->Begin(),
                     mem_map->Size(),
                     location,
                     location_checksum,
                     mem_map,
+                    nullptr,
                     error_msg);
 }
 
-const DexFile* DexFile::Open(const ZipArchive& zip_archive, const char* entry_name,
-                             const std::string& location, std::string* error_msg,
-                             ZipOpenErrorCode* error_code) {
+std::unique_ptr<const DexFile> DexFile::Open(const ZipArchive& zip_archive, const char* entry_name,
+                                             const std::string& location, std::string* error_msg,
+                                             ZipOpenErrorCode* error_code) {
   CHECK(!location.empty());
   std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
   if (zip_entry.get() == NULL) {
@@ -281,11 +290,13 @@
     return nullptr;
   }
   *error_code = ZipOpenErrorCode::kNoError;
-  return dex_file.release();
+  return dex_file;
 }
 
 bool DexFile::OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
-                          std::string* error_msg, std::vector<const DexFile*>* dex_files) {
+                          std::string* error_msg,
+                          std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is NULL";
   ZipOpenErrorCode error_code;
   std::unique_ptr<const DexFile> dex_file(Open(zip_archive, kClassesDex, location, error_msg,
                                                &error_code));
@@ -293,7 +304,7 @@
     return false;
   } else {
     // Had at least classes.dex.
-    dex_files->push_back(dex_file.release());
+    dex_files->push_back(std::move(dex_file));
 
     // Now try some more.
     size_t i = 2;
@@ -312,7 +323,7 @@
         }
         break;
       } else {
-        dex_files->push_back(next_dex_file.release());
+        dex_files->push_back(std::move(next_dex_file));
       }
 
       i++;
@@ -323,24 +334,27 @@
 }
 
 
-const DexFile* DexFile::OpenMemory(const byte* base,
-                                   size_t size,
-                                   const std::string& location,
-                                   uint32_t location_checksum,
-                                   MemMap* mem_map, std::string* error_msg) {
+std::unique_ptr<const DexFile> DexFile::OpenMemory(const uint8_t* base,
+                                                   size_t size,
+                                                   const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   MemMap* mem_map,
+                                                   const OatFile* oat_file,
+                                                   std::string* error_msg) {
   CHECK_ALIGNED(base, 4);  // various dex file structures must be word aligned
-  std::unique_ptr<DexFile> dex_file(new DexFile(base, size, location, location_checksum, mem_map));
+  std::unique_ptr<DexFile> dex_file(
+      new DexFile(base, size, location, location_checksum, mem_map, oat_file));
   if (!dex_file->Init(error_msg)) {
-    return nullptr;
-  } else {
-    return dex_file.release();
+    dex_file.reset();
   }
+  return std::unique_ptr<const DexFile>(dex_file.release());
 }
 
-DexFile::DexFile(const byte* base, size_t size,
+DexFile::DexFile(const uint8_t* base, size_t size,
                  const std::string& location,
                  uint32_t location_checksum,
-                 MemMap* mem_map)
+                 MemMap* mem_map,
+                 const OatFile* oat_file)
     : begin_(base),
       size_(size),
       location_(location),
@@ -354,7 +368,8 @@
       proto_ids_(reinterpret_cast<const ProtoId*>(base + header_->proto_ids_off_)),
       class_defs_(reinterpret_cast<const ClassDef*>(base + header_->class_defs_off_)),
       find_class_def_misses_(0),
-      class_def_index_(nullptr) {
+      class_def_index_(nullptr),
+      oat_file_(oat_file) {
   CHECK(begin_ != NULL) << GetLocation();
   CHECK_GT(size_, 0U) << GetLocation();
 }
@@ -399,12 +414,12 @@
   return true;
 }
 
-bool DexFile::IsMagicValid(const byte* magic) {
+bool DexFile::IsMagicValid(const uint8_t* magic) {
   return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
 }
 
-bool DexFile::IsVersionValid(const byte* magic) {
-  const byte* version = &magic[sizeof(kDexMagic)];
+bool DexFile::IsVersionValid(const uint8_t* magic) {
+  const uint8_t* version = &magic[sizeof(kDexMagic)];
   return (memcmp(version, kDexMagicVersion, sizeof(kDexMagicVersion)) == 0);
 }
 
@@ -413,11 +428,12 @@
   return atoi(version);
 }
 
-const DexFile::ClassDef* DexFile::FindClassDef(const char* descriptor) const {
+const DexFile::ClassDef* DexFile::FindClassDef(const char* descriptor, size_t hash) const {
+  DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash);
   // If we have an index lookup the descriptor via that as its constant time to search.
   Index* index = class_def_index_.LoadSequentiallyConsistent();
   if (index != nullptr) {
-    auto it = index->find(descriptor);
+    auto it = index->FindWithHash(descriptor, hash);
     return (it == index->end()) ? nullptr : it->second;
   }
   // Fast path for rate no class defs case.
@@ -449,11 +465,11 @@
     // Are we the ones moving the miss count past the max? Sanity check the index doesn't exist.
     CHECK(class_def_index_.LoadSequentiallyConsistent() == nullptr);
     // Build the index.
-    index = new Index(num_class_defs);
+    index = new Index();
     for (uint32_t i = 0; i < num_class_defs;  ++i) {
       const ClassDef& class_def = GetClassDef(i);
-      const char* descriptor = GetClassDescriptor(class_def);
-      index->insert(std::make_pair(descriptor, &class_def));
+      const char* class_descriptor = GetClassDescriptor(class_def);
+      index->Insert(std::make_pair(class_descriptor, &class_def));
     }
     // Sanity check the index still doesn't exist, only 1 thread should build it.
     CHECK(class_def_index_.LoadSequentiallyConsistent() == nullptr);
@@ -754,7 +770,7 @@
 
 void DexFile::DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx,
                                DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
-                               void* context, const byte* stream, LocalInfo* local_in_reg) const {
+                               void* context, const uint8_t* stream, LocalInfo* local_in_reg) const {
   uint32_t line = DecodeUnsignedLeb128(&stream);
   uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
   uint16_t arg_reg = code_item->registers_size_ - code_item->ins_size_;
@@ -919,7 +935,7 @@
                               DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
                               void* context) const {
   DCHECK(code_item != nullptr);
-  const byte* stream = GetDebugInfoStream(code_item);
+  const uint8_t* stream = GetDebugInfoStream(code_item);
   std::unique_ptr<LocalInfo[]> local_in_reg(local_cb != NULL ?
                                       new LocalInfo[code_item->registers_size_] :
                                       NULL);
@@ -1059,7 +1075,7 @@
 }
 
 // Read a signed integer.  "zwidth" is the zero-based byte count.
-static int32_t ReadSignedInt(const byte* ptr, int zwidth) {
+static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth) {
   int32_t val = 0;
   for (int i = zwidth; i >= 0; --i) {
     val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
@@ -1070,7 +1086,7 @@
 
 // Read an unsigned integer.  "zwidth" is the zero-based byte count,
 // "fill_on_right" indicates which side we want to zero-fill from.
-static uint32_t ReadUnsignedInt(const byte* ptr, int zwidth, bool fill_on_right) {
+static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
   uint32_t val = 0;
   if (!fill_on_right) {
     for (int i = zwidth; i >= 0; --i) {
@@ -1086,7 +1102,7 @@
 }
 
 // Read a signed long.  "zwidth" is the zero-based byte count.
-static int64_t ReadSignedLong(const byte* ptr, int zwidth) {
+static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth) {
   int64_t val = 0;
   for (int i = zwidth; i >= 0; --i) {
     val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
@@ -1097,7 +1113,7 @@
 
 // Read an unsigned long.  "zwidth" is the zero-based byte count,
 // "fill_on_right" indicates which side we want to zero-fill from.
-static uint64_t ReadUnsignedLong(const byte* ptr, int zwidth, bool fill_on_right) {
+static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
   uint64_t val = 0;
   if (!fill_on_right) {
     for (int i = zwidth; i >= 0; --i) {
@@ -1137,8 +1153,8 @@
   if (pos_ >= array_size_) {
     return;
   }
-  byte value_type = *ptr_++;
-  byte value_arg = value_type >> kEncodedValueArgShift;
+  uint8_t value_type = *ptr_++;
+  uint8_t value_arg = value_type >> kEncodedValueArgShift;
   size_t width = value_arg + 1;  // assume and correct later
   type_ = static_cast<ValueType>(value_type & kEncodedValueTypeMask);
   switch (type_) {
@@ -1180,13 +1196,14 @@
   case kArray:
   case kAnnotation:
     UNIMPLEMENTED(FATAL) << ": type " << type_;
-    break;
+    UNREACHABLE();
   case kNull:
     jval_.l = NULL;
     width = 0;
     break;
   default:
     LOG(FATAL) << "Unreached";
+    UNREACHABLE();
   }
   ptr_ += width;
 }
@@ -1266,7 +1283,7 @@
   }
 }
 
-void CatchHandlerIterator::Init(const byte* handler_data) {
+void CatchHandlerIterator::Init(const uint8_t* handler_data) {
   current_data_ = handler_data;
   remaining_count_ = DecodeSignedLeb128(&current_data_);
 
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index c160253..9b8f254 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -22,8 +22,10 @@
 #include <unordered_map>
 #include <vector>
 
+#include "base/hash_map.h"
 #include "base/logging.h"
 #include "base/mutex.h"  // For Locks::mutator_lock_.
+#include "base/value_object.h"
 #include "globals.h"
 #include "invoke_type.h"
 #include "jni.h"
@@ -42,6 +44,7 @@
 }  // namespace mirror
 class ClassLinker;
 class MemMap;
+class OatFile;
 class Signature;
 template<class T> class Handle;
 class StringPiece;
@@ -50,10 +53,10 @@
 // TODO: move all of the macro functionality into the DexCache class.
 class DexFile {
  public:
-  static const byte kDexMagic[];
-  static const byte kDexMagicVersion[];
-  static const size_t kSha1DigestSize = 20;
-  static const uint32_t kDexEndianConstant = 0x12345678;
+  static const uint8_t kDexMagic[];
+  static const uint8_t kDexMagicVersion[];
+  static constexpr size_t kSha1DigestSize = 20;
+  static constexpr uint32_t kDexEndianConstant = 0x12345678;
 
   // name of the DexFile entry within a zip archive
   static const char* kClassesDex;
@@ -205,10 +208,10 @@
     // (class or interface). These are all in the lower 16b and do not contain runtime flags.
     uint32_t GetJavaAccessFlags() const {
       // Make sure that none of our runtime-only flags are set.
-      COMPILE_ASSERT((kAccValidClassFlags & kAccJavaFlagsMask) == kAccValidClassFlags,
-                     valid_class_flags_not_subset_of_java_flags);
-      COMPILE_ASSERT((kAccValidInterfaceFlags & kAccJavaFlagsMask) == kAccValidInterfaceFlags,
-                     valid_interface_flags_not_subset_of_java_flags);
+      static_assert((kAccValidClassFlags & kAccJavaFlagsMask) == kAccValidClassFlags,
+                    "Valid class flags not a subset of Java flags");
+      static_assert((kAccValidInterfaceFlags & kAccJavaFlagsMask) == kAccValidInterfaceFlags,
+                    "Valid interface flags not a subset of Java flags");
 
       if ((access_flags_ & kAccInterface) != 0) {
         // Interface.
@@ -383,19 +386,21 @@
 
   // Opens .dex files found in the container, guessing the container format based on file extension.
   static bool Open(const char* filename, const char* location, std::string* error_msg,
-                   std::vector<const DexFile*>* dex_files);
+                   std::vector<std::unique_ptr<const DexFile>>* dex_files);
 
   // Opens .dex file, backed by existing memory
-  static const DexFile* Open(const uint8_t* base, size_t size,
-                             const std::string& location,
-                             uint32_t location_checksum,
-                             std::string* error_msg) {
-    return OpenMemory(base, size, location, location_checksum, NULL, error_msg);
+  static std::unique_ptr<const DexFile> Open(const uint8_t* base, size_t size,
+                                             const std::string& location,
+                                             uint32_t location_checksum,
+                                             const OatFile* oat_file,
+                                             std::string* error_msg) {
+    return OpenMemory(base, size, location, location_checksum, NULL, oat_file, error_msg);
   }
 
   // Open all classesXXX.dex files from a zip archive.
   static bool OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
-                          std::string* error_msg, std::vector<const DexFile*>* dex_files);
+                          std::string* error_msg,
+                          std::vector<std::unique_ptr<const DexFile>>* dex_files);
 
   // Closes a .dex file.
   virtual ~DexFile();
@@ -440,10 +445,10 @@
   uint32_t GetVersion() const;
 
   // Returns true if the byte string points to the magic value.
-  static bool IsMagicValid(const byte* magic);
+  static bool IsMagicValid(const uint8_t* magic);
 
   // Returns true if the byte string after the magic is the correct value.
-  static bool IsVersionValid(const byte* magic);
+  static bool IsVersionValid(const uint8_t* magic);
 
   // Returns the number of string identifiers in the .dex file.
   size_t NumStringIds() const {
@@ -648,8 +653,9 @@
     return StringByTypeIdx(class_def.class_idx_);
   }
 
-  // Looks up a class definition by its class descriptor.
-  const ClassDef* FindClassDef(const char* descriptor) const;
+  // Looks up a class definition by its class descriptor. Hash must be
+  // ComputeModifiedUtf8Hash(descriptor).
+  const ClassDef* FindClassDef(const char* descriptor, size_t hash) const;
 
   // Looks up a class definition by its type index.
   const ClassDef* FindClassDef(uint16_t type_idx) const;
@@ -658,13 +664,13 @@
     if (class_def.interfaces_off_ == 0) {
         return NULL;
     } else {
-      const byte* addr = begin_ + class_def.interfaces_off_;
+      const uint8_t* addr = begin_ + class_def.interfaces_off_;
       return reinterpret_cast<const TypeList*>(addr);
     }
   }
 
   // Returns a pointer to the raw memory mapped class_data_item
-  const byte* GetClassData(const ClassDef& class_def) const {
+  const uint8_t* GetClassData(const ClassDef& class_def) const {
     if (class_def.class_data_off_ == 0) {
       return NULL;
     } else {
@@ -677,7 +683,7 @@
     if (code_off == 0) {
       return NULL;  // native or abstract method
     } else {
-      const byte* addr = begin_ + code_off;
+      const uint8_t* addr = begin_ + code_off;
       return reinterpret_cast<const CodeItem*>(addr);
     }
   }
@@ -730,12 +736,12 @@
     if (proto_id.parameters_off_ == 0) {
       return NULL;
     } else {
-      const byte* addr = begin_ + proto_id.parameters_off_;
+      const uint8_t* addr = begin_ + proto_id.parameters_off_;
       return reinterpret_cast<const TypeList*>(addr);
     }
   }
 
-  const byte* GetEncodedStaticFieldValuesArray(const ClassDef& class_def) const {
+  const uint8_t* GetEncodedStaticFieldValuesArray(const ClassDef& class_def) const {
     if (class_def.static_values_off_ == 0) {
       return 0;
     } else {
@@ -746,9 +752,9 @@
   static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset);
 
   // Get the base of the encoded data for the given DexCode.
-  static const byte* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
-    const byte* handler_data =
-        reinterpret_cast<const byte*>(GetTryItems(code_item, code_item.tries_size_));
+  static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+    const uint8_t* handler_data =
+        reinterpret_cast<const uint8_t*>(GetTryItems(code_item, code_item.tries_size_));
     return handler_data + offset;
   }
 
@@ -759,7 +765,7 @@
   static int32_t FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address);
 
   // Get the pointer to the start of the debugging data
-  const byte* GetDebugInfoStream(const CodeItem* code_item) const {
+  const uint8_t* GetDebugInfoStream(const CodeItem* code_item) const {
     if (code_item->debug_info_off_ == 0) {
       return NULL;
     } else {
@@ -862,7 +868,7 @@
 
   bool DisableWrite() const;
 
-  const byte* Begin() const {
+  const uint8_t* Begin() const {
     return begin_;
   }
 
@@ -887,13 +893,18 @@
   //     the dex_location where it's file name part has been made canonical.
   static std::string GetDexCanonicalLocation(const char* dex_location);
 
+  const OatFile* GetOatFile() const {
+    return oat_file_;
+  }
+
  private:
   // Opens a .dex file
-  static const DexFile* OpenFile(int fd, const char* location, bool verify, std::string* error_msg);
+  static std::unique_ptr<const DexFile> OpenFile(int fd, const char* location,
+                                                 bool verify, std::string* error_msg);
 
   // Opens dex files from within a .jar, .zip, or .apk file
   static bool OpenZip(int fd, const std::string& location, std::string* error_msg,
-                      std::vector<const DexFile*>* dex_files);
+                      std::vector<std::unique_ptr<const DexFile>>* dex_files);
 
   enum class ZipOpenErrorCode {  // private
     kNoError,
@@ -906,28 +917,30 @@
 
   // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-nullptr
   // return.
-  static const DexFile* Open(const ZipArchive& zip_archive, const char* entry_name,
-                             const std::string& location, std::string* error_msg,
-                             ZipOpenErrorCode* error_code);
+  static std::unique_ptr<const DexFile> Open(const ZipArchive& zip_archive, const char* entry_name,
+                                             const std::string& location, std::string* error_msg,
+                                             ZipOpenErrorCode* error_code);
 
   // Opens a .dex file at the given address backed by a MemMap
-  static const DexFile* OpenMemory(const std::string& location,
-                                   uint32_t location_checksum,
-                                   MemMap* mem_map,
-                                   std::string* error_msg);
+  static std::unique_ptr<const DexFile> OpenMemory(const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   MemMap* mem_map,
+                                                   std::string* error_msg);
 
   // Opens a .dex file at the given address, optionally backed by a MemMap
-  static const DexFile* OpenMemory(const byte* dex_file,
-                                   size_t size,
-                                   const std::string& location,
-                                   uint32_t location_checksum,
-                                   MemMap* mem_map,
-                                   std::string* error_msg);
+  static std::unique_ptr<const DexFile> OpenMemory(const uint8_t* dex_file,
+                                                   size_t size,
+                                                   const std::string& location,
+                                                   uint32_t location_checksum,
+                                                   MemMap* mem_map,
+                                                   const OatFile* oat_file,
+                                                   std::string* error_msg);
 
-  DexFile(const byte* base, size_t size,
+  DexFile(const uint8_t* base, size_t size,
           const std::string& location,
           uint32_t location_checksum,
-          MemMap* mem_map);
+          MemMap* mem_map,
+          const OatFile* oat_file);
 
   // Top-level initializer that calls other Init methods.
   bool Init(std::string* error_msg);
@@ -937,7 +950,7 @@
 
   void DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx,
       DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
-      void* context, const byte* stream, LocalInfo* local_in_reg) const;
+      void* context, const uint8_t* stream, LocalInfo* local_in_reg) const;
 
   // Check whether a location denotes a multidex dex file. This is a very simple check: returns
   // whether the string contains the separator character.
@@ -945,7 +958,7 @@
 
 
   // The base address of the memory mapping.
-  const byte* const begin_;
+  const uint8_t* const begin_;
 
   // The size of the underlying memory allocation in bytes.
   const size_t size_;
@@ -985,18 +998,35 @@
   // Number of misses finding a class def from a descriptor.
   mutable Atomic<uint32_t> find_class_def_misses_;
 
+  struct UTF16EmptyFn {
+    void MakeEmpty(std::pair<const char*, const ClassDef*>& pair) const {
+      pair.first = nullptr;
+      pair.second = nullptr;
+    }
+    bool IsEmpty(const std::pair<const char*, const ClassDef*>& pair) const {
+      if (pair.first == nullptr) {
+        DCHECK(pair.second == nullptr);
+        return true;
+      }
+      return false;
+    }
+  };
   struct UTF16HashCmp {
     // Hash function.
     size_t operator()(const char* key) const {
-      return ComputeUtf8Hash(key);
+      return ComputeModifiedUtf8Hash(key);
     }
     // std::equal function.
     bool operator()(const char* a, const char* b) const {
       return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(a, b) == 0;
     }
   };
-  typedef std::unordered_map<const char*, const ClassDef*, UTF16HashCmp, UTF16HashCmp> Index;
+  typedef HashMap<const char*, const ClassDef*, UTF16EmptyFn, UTF16HashCmp, UTF16HashCmp> Index;
   mutable Atomic<Index*> class_def_index_;
+
+  // The oat file this dex file was loaded from. May be null in case the dex file is not coming
+  // from an oat file, e.g., directly from an apk.
+  const OatFile* oat_file_;
 };
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file);
 
@@ -1027,7 +1057,7 @@
 };
 
 // Abstract the signature of a method.
-class Signature {
+class Signature : public ValueObject {
  public:
   std::string ToString() const;
 
@@ -1059,7 +1089,7 @@
 // Iterate and decode class_data_item
 class ClassDataItemIterator {
  public:
-  ClassDataItemIterator(const DexFile& dex_file, const byte* raw_class_data_item)
+  ClassDataItemIterator(const DexFile& dex_file, const uint8_t* raw_class_data_item)
       : dex_file_(dex_file), pos_(0), ptr_pos_(raw_class_data_item), last_idx_(0) {
     ReadClassDataHeader();
     if (EndOfInstanceFieldsPos() > 0) {
@@ -1174,7 +1204,7 @@
   uint32_t GetMethodCodeItemOffset() const {
     return method_.code_off_;
   }
-  const byte* EndDataPointer() const {
+  const uint8_t* EndDataPointer() const {
     CHECK(!HasNext());
     return ptr_pos_;
   }
@@ -1236,7 +1266,7 @@
 
   const DexFile& dex_file_;
   size_t pos_;  // integral number of items passed
-  const byte* ptr_pos_;  // pointer into stream of class_data_item
+  const uint8_t* ptr_pos_;  // pointer into stream of class_data_item
   uint32_t last_idx_;  // last read field or method index to apply delta to
   DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator);
 };
@@ -1251,7 +1281,7 @@
   template<bool kTransactionActive>
   void ReadValueToField(Handle<mirror::ArtField> field) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool HasNext() { return pos_ < array_size_; }
+  bool HasNext() const { return pos_ < array_size_; }
 
   void Next();
 
@@ -1275,8 +1305,8 @@
   };
 
  private:
-  static const byte kEncodedValueTypeMask = 0x1f;  // 0b11111
-  static const byte kEncodedValueArgShift = 5;
+  static constexpr uint8_t kEncodedValueTypeMask = 0x1f;  // 0b11111
+  static constexpr uint8_t kEncodedValueArgShift = 5;
 
   const DexFile& dex_file_;
   Handle<mirror::DexCache>* const dex_cache_;  // Dex cache to resolve literal objects.
@@ -1284,7 +1314,7 @@
   ClassLinker* linker_;  // Linker to resolve literal objects.
   size_t array_size_;  // Size of array.
   size_t pos_;  // Current position.
-  const byte* ptr_;  // Pointer into encoded data array.
+  const uint8_t* ptr_;  // Pointer into encoded data array.
   ValueType type_;  // Type of current encoded value.
   jvalue jval_;  // Value of current encoded value.
   DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedStaticFieldValueIterator);
@@ -1298,7 +1328,7 @@
     CatchHandlerIterator(const DexFile::CodeItem& code_item,
                          const DexFile::TryItem& try_item);
 
-    explicit CatchHandlerIterator(const byte* handler_data) {
+    explicit CatchHandlerIterator(const uint8_t* handler_data) {
       Init(handler_data);
     }
 
@@ -1313,20 +1343,20 @@
       return remaining_count_ != -1 || catch_all_;
     }
     // End of this set of catch blocks, convenience method to locate next set of catch blocks
-    const byte* EndDataPointer() const {
+    const uint8_t* EndDataPointer() const {
       CHECK(!HasNext());
       return current_data_;
     }
 
   private:
     void Init(const DexFile::CodeItem& code_item, int32_t offset);
-    void Init(const byte* handler_data);
+    void Init(const uint8_t* handler_data);
 
     struct CatchHandlerItem {
       uint16_t type_idx_;  // type index of the caught exception type
       uint32_t address_;  // handler address
     } handler_;
-    const byte *current_data_;  // the current handler in dex file.
+    const uint8_t* current_data_;  // the current handler in dex file.
     int32_t remaining_count_;   // number of handlers not read.
     bool catch_all_;            // is there a handler that will catch all exceptions in case
                                 // that all typed handler does not match.
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index d0c5603..7f5a181 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -21,6 +21,7 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
+#include "dex_file-inl.h"
 #include "os.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
@@ -31,11 +32,11 @@
 
 TEST_F(DexFileTest, Open) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* dex(OpenTestDexFile("Nested"));
-  ASSERT_TRUE(dex != NULL);
+  std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested"));
+  ASSERT_TRUE(dex.get() != NULL);
 }
 
-static const byte kBase64Map[256] = {
+static const uint8_t kBase64Map[256] = {
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@@ -60,12 +61,12 @@
   255, 255, 255, 255
 };
 
-static inline byte* DecodeBase64(const char* src, size_t* dst_size) {
-  std::vector<byte> tmp;
+static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+  std::vector<uint8_t> tmp;
   uint32_t t = 0, y = 0;
   int g = 3;
   for (size_t i = 0; src[i] != '\0'; ++i) {
-    byte c = kBase64Map[src[i] & 0xFF];
+    uint8_t c = kBase64Map[src[i] & 0xFF];
     if (c == 255) continue;
     // the final = symbols are read and used to trim the remaining bytes
     if (c == 254) {
@@ -96,7 +97,7 @@
     *dst_size = 0;
     return nullptr;
   }
-  std::unique_ptr<byte[]> dst(new byte[tmp.size()]);
+  std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
   if (dst_size != nullptr) {
     *dst_size = tmp.size();
   } else {
@@ -132,12 +133,12 @@
   "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
   "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
 
-static const DexFile* OpenDexFileBase64(const char* base64,
-                                        const char* location) {
+static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
+                                                        const char* location) {
   // decode base64
   CHECK(base64 != NULL);
   size_t length;
-  std::unique_ptr<byte[]> dex_bytes(DecodeBase64(base64, &length));
+  std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
   CHECK(dex_bytes.get() != NULL);
 
   // write to provided file
@@ -146,16 +147,19 @@
   if (!file->WriteFully(dex_bytes.get(), length)) {
     PLOG(FATAL) << "Failed to write base64 as dex file";
   }
+  if (file->FlushCloseOrErase() != 0) {
+    PLOG(FATAL) << "Could not flush and close test file.";
+  }
   file.reset();
 
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
   std::string error_msg;
-  std::vector<const DexFile*> tmp;
+  std::vector<std::unique_ptr<const DexFile>> tmp;
   bool success = DexFile::Open(location, location, &error_msg, &tmp);
   CHECK(success) << error_msg;
   EXPECT_EQ(1U, tmp.size());
-  const DexFile* dex_file = tmp[0];
+  std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
   EXPECT_TRUE(dex_file->IsReadOnly());
   return dex_file;
@@ -194,7 +198,7 @@
 
 TEST_F(DexFileTest, GetLocationChecksum) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* raw(OpenTestDexFile("Main"));
+  std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main"));
   EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
 }
 
@@ -209,8 +213,8 @@
 
 TEST_F(DexFileTest, ClassDefs) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* raw(OpenTestDexFile("Nested"));
-  ASSERT_TRUE(raw != NULL);
+  std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
+  ASSERT_TRUE(raw.get() != nullptr);
   EXPECT_EQ(2U, raw->NumClassDefs());
 
   const DexFile::ClassDef& c0 = raw->GetClassDef(0);
@@ -222,14 +226,14 @@
 
 TEST_F(DexFileTest, GetMethodSignature) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
-  ASSERT_TRUE(raw != NULL);
+  std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
+  ASSERT_TRUE(raw.get() != nullptr);
   EXPECT_EQ(1U, raw->NumClassDefs());
 
   const DexFile::ClassDef& class_def = raw->GetClassDef(0);
   ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
 
-  const byte* class_data = raw->GetClassData(class_def);
+  const uint8_t* class_data = raw->GetClassData(class_def);
   ASSERT_TRUE(class_data != NULL);
   ClassDataItemIterator it(*raw, class_data);
 
@@ -272,8 +276,8 @@
 
 TEST_F(DexFileTest, FindStringId) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
-  ASSERT_TRUE(raw != NULL);
+  std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
+  ASSERT_TRUE(raw.get() != nullptr);
   EXPECT_EQ(1U, raw->NumClassDefs());
 
   const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 9eba92f..a3f3de8 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -124,7 +124,7 @@
     error_stmt;                                             \
   }
 
-bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size,
+bool DexFileVerifier::Verify(const DexFile* dex_file, const uint8_t* begin, size_t size,
                              const char* location, std::string* error_msg) {
   std::unique_ptr<DexFileVerifier> verifier(new DexFileVerifier(dex_file, begin, size, location));
   if (!verifier->Verify()) {
@@ -142,7 +142,7 @@
         ErrorStringPrintf("Invalid use of void");
         return false;
       }
-      // Intentional fallthrough.
+      FALLTHROUGH_INTENDED;
     case 'B':
     case 'C':
     case 'D':
@@ -175,8 +175,8 @@
   // Check that size is not 0.
   CHECK_NE(elem_size, 0U);
 
-  const byte* range_start = reinterpret_cast<const byte*>(start);
-  const byte* file_start = reinterpret_cast<const byte*>(begin_);
+  const uint8_t* range_start = reinterpret_cast<const uint8_t*>(start);
+  const uint8_t* file_start = reinterpret_cast<const uint8_t*>(begin_);
 
   // Check for overflow.
   uintptr_t max = 0 - 1;
@@ -189,8 +189,8 @@
     return false;
   }
 
-  const byte* range_end = range_start + count * elem_size;
-  const byte* file_end = file_start + size_;
+  const uint8_t* range_end = range_start + count * elem_size;
+  const uint8_t* file_end = file_start + size_;
   if (UNLIKELY((range_start < file_start) || (range_end > file_end))) {
     // Note: these two tests are enough as we make sure above that there's no overflow.
     ErrorStringPrintf("Bad range for %s: %zx to %zx", label,
@@ -201,7 +201,7 @@
   return true;
 }
 
-bool DexFileVerifier::CheckList(size_t element_size, const char* label, const byte* *ptr) {
+bool DexFileVerifier::CheckList(size_t element_size, const char* label, const uint8_t* *ptr) {
   // Check that the list is available. The first 4B are the count.
   if (!CheckListSize(*ptr, 1, 4U, label)) {
     return false;
@@ -251,7 +251,7 @@
   // Compute and verify the checksum in the header.
   uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
   const uint32_t non_sum = sizeof(header_->magic_) + sizeof(header_->checksum_);
-  const byte* non_sum_ptr = reinterpret_cast<const byte*>(header_) + non_sum;
+  const uint8_t* non_sum_ptr = reinterpret_cast<const uint8_t*>(header_) + non_sum;
   adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
   if (adler_checksum != header_->checksum_) {
     ErrorStringPrintf("Bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_);
@@ -388,7 +388,7 @@
 
 uint32_t DexFileVerifier::ReadUnsignedLittleEndian(uint32_t size) {
   uint32_t result = 0;
-  if (LIKELY(CheckListSize(ptr_, size, sizeof(byte), "encoded_value"))) {
+  if (LIKELY(CheckListSize(ptr_, size, sizeof(uint8_t), "encoded_value"))) {
     for (uint32_t i = 0; i < size; i++) {
       result |= ((uint32_t) *(ptr_++)) << (i * 8);
     }
@@ -398,7 +398,7 @@
 
 bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
                                                 uint32_t* handler_offsets, uint32_t handlers_size) {
-  const byte* handlers_base = DexFile::GetCatchHandlerData(*code_item, 0);
+  const uint8_t* handlers_base = DexFile::GetCatchHandlerData(*code_item, 0);
 
   for (uint32_t i = 0; i < handlers_size; i++) {
     bool catch_all;
@@ -503,7 +503,7 @@
 
 bool DexFileVerifier::CheckPadding(size_t offset, uint32_t aligned_offset) {
   if (offset < aligned_offset) {
-    if (!CheckListSize(begin_ + offset, aligned_offset - offset, sizeof(byte), "section")) {
+    if (!CheckListSize(begin_ + offset, aligned_offset - offset, sizeof(uint8_t), "section")) {
       return false;
     }
     while (offset < aligned_offset) {
@@ -519,7 +519,7 @@
 }
 
 bool DexFileVerifier::CheckEncodedValue() {
-  if (!CheckListSize(ptr_, 1, sizeof(byte), "encoded_value header")) {
+  if (!CheckListSize(ptr_, 1, sizeof(uint8_t), "encoded_value header")) {
     return false;
   }
 
@@ -746,7 +746,7 @@
   // Grab the end of the insns if there are no try_items.
   uint32_t try_items_size = code_item->tries_size_;
   if (try_items_size == 0) {
-    ptr_ = reinterpret_cast<const byte*>(&insns[insns_size]);
+    ptr_ = reinterpret_cast<const uint8_t*>(&insns[insns_size]);
     return true;
   }
 
@@ -812,7 +812,7 @@
 
 bool DexFileVerifier::CheckIntraStringDataItem() {
   uint32_t size = DecodeUnsignedLeb128(&ptr_);
-  const byte* file_end = begin_ + size_;
+  const uint8_t* file_end = begin_ + size_;
 
   for (uint32_t i = 0; i < size; i++) {
     CHECK_LT(i, size);  // b/15014252 Prevents hitting the impossible case below
@@ -1003,7 +1003,7 @@
 }
 
 bool DexFileVerifier::CheckIntraAnnotationItem() {
-  if (!CheckListSize(ptr_, 1, sizeof(byte), "annotation visibility")) {
+  if (!CheckListSize(ptr_, 1, sizeof(uint8_t), "annotation visibility")) {
     return false;
   }
 
@@ -1090,7 +1090,7 @@
   }
 
   // Return a pointer to the end of the annotations.
-  ptr_ = reinterpret_cast<const byte*>(parameter_item);
+  ptr_ = reinterpret_cast<const uint8_t*>(parameter_item);
   return true;
 }
 
@@ -1416,7 +1416,7 @@
   return true;
 }
 
-uint16_t DexFileVerifier::FindFirstClassDataDefiner(const byte* ptr, bool* success) {
+uint16_t DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
   ClassDataItemIterator it(*dex_file_, ptr);
   *success = true;
 
@@ -1435,7 +1435,7 @@
   return DexFile::kDexNoIndex16;
 }
 
-uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const byte* ptr, bool* success) {
+uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success) {
   const DexFile::AnnotationsDirectoryItem* item =
       reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
   *success = true;
@@ -1759,7 +1759,7 @@
 
   // Check that references in class_data_item are to the right class.
   if (item->class_data_off_ != 0) {
-    const byte* data = begin_ + item->class_data_off_;
+    const uint8_t* data = begin_ + item->class_data_off_;
     bool success;
     uint16_t data_definer = FindFirstClassDataDefiner(data, &success);
     if (!success) {
@@ -1773,7 +1773,7 @@
 
   // Check that references in annotations_directory_item are to right class.
   if (item->annotations_off_ != 0) {
-    const byte* data = begin_ + item->annotations_off_;
+    const uint8_t* data = begin_ + item->annotations_off_;
     bool success;
     uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
     if (!success) {
@@ -1804,7 +1804,7 @@
     item++;
   }
 
-  ptr_ = reinterpret_cast<const byte*>(item);
+  ptr_ = reinterpret_cast<const uint8_t*>(item);
   return true;
 }
 
@@ -1834,7 +1834,7 @@
     offsets++;
   }
 
-  ptr_ = reinterpret_cast<const byte*>(offsets);
+  ptr_ = reinterpret_cast<const uint8_t*>(offsets);
   return true;
 }
 
@@ -1935,7 +1935,7 @@
     parameter_item++;
   }
 
-  ptr_ = reinterpret_cast<const byte*>(parameter_item);
+  ptr_ = reinterpret_cast<const uint8_t*>(parameter_item);
   return true;
 }
 
@@ -1956,7 +1956,7 @@
   for (uint32_t i = 0; i < count; i++) {
     uint32_t new_offset = (offset + alignment_mask) & ~alignment_mask;
     ptr_ = begin_ + new_offset;
-    const byte* prev_ptr = ptr_;
+    const uint8_t* prev_ptr = ptr_;
 
     // Check depending on the section type.
     switch (type) {
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 606da54..18bf2e7 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -26,7 +26,7 @@
 
 class DexFileVerifier {
  public:
-  static bool Verify(const DexFile* dex_file, const byte* begin, size_t size,
+  static bool Verify(const DexFile* dex_file, const uint8_t* begin, size_t size,
                      const char* location, std::string* error_msg);
 
   const std::string& FailureReason() const {
@@ -34,7 +34,7 @@
   }
 
  private:
-  DexFileVerifier(const DexFile* dex_file, const byte* begin, size_t size, const char* location)
+  DexFileVerifier(const DexFile* dex_file, const uint8_t* begin, size_t size, const char* location)
       : dex_file_(dex_file), begin_(begin), size_(size), location_(location),
         header_(&dex_file->GetHeader()), ptr_(NULL), previous_item_(NULL)  {
   }
@@ -45,7 +45,7 @@
   bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label);
   // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If
   // successful, the ptr will be moved forward the amount covered by the list.
-  bool CheckList(size_t element_size, const char* label, const byte* *ptr);
+  bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr);
   // Checks whether the offset is zero (when size is zero) or that the offset falls within the area
   // claimed by the file.
   bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, const char* label);
@@ -81,8 +81,8 @@
 
   // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
   // additional out parameter to signal any errors loading an index.
-  uint16_t FindFirstClassDataDefiner(const byte* ptr, bool* success);
-  uint16_t FindFirstAnnotationsDirectoryDefiner(const byte* ptr, bool* success);
+  uint16_t FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
+  uint16_t FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
 
   bool CheckInterStringIdItem();
   bool CheckInterTypeIdItem();
@@ -112,13 +112,13 @@
       __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
 
   const DexFile* const dex_file_;
-  const byte* const begin_;
+  const uint8_t* const begin_;
   const size_t size_;
   const char* const location_;
   const DexFile::Header* const header_;
 
   AllocationTrackingSafeMap<uint32_t, uint16_t, kAllocatorTagDexFileVerifier> offset_to_type_map_;
-  const byte* ptr_;
+  const uint8_t* ptr_;
   const void* previous_item_;
 
   std::string failure_reason_;
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index d475d42..00ca8a9 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -30,7 +30,7 @@
 
 class DexFileVerifierTest : public CommonRuntimeTest {};
 
-static const byte kBase64Map[256] = {
+static const uint8_t kBase64Map[256] = {
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@@ -55,12 +55,12 @@
   255, 255, 255, 255
 };
 
-static inline byte* DecodeBase64(const char* src, size_t* dst_size) {
-  std::vector<byte> tmp;
+static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+  std::vector<uint8_t> tmp;
   uint32_t t = 0, y = 0;
   int g = 3;
   for (size_t i = 0; src[i] != '\0'; ++i) {
-    byte c = kBase64Map[src[i] & 0xFF];
+    uint8_t c = kBase64Map[src[i] & 0xFF];
     if (c == 255) continue;
     // the final = symbols are read and used to trim the remaining bytes
     if (c == 254) {
@@ -91,7 +91,7 @@
     *dst_size = 0;
     return nullptr;
   }
-  std::unique_ptr<byte[]> dst(new byte[tmp.size()]);
+  std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
   if (dst_size != nullptr) {
     *dst_size = tmp.size();
   } else {
@@ -101,12 +101,13 @@
   return dst.release();
 }
 
-static const DexFile* OpenDexFileBase64(const char* base64, const char* location,
-                                        std::string* error_msg) {
+static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
+                                                        const char* location,
+                                                        std::string* error_msg) {
   // decode base64
   CHECK(base64 != NULL);
   size_t length;
-  std::unique_ptr<byte[]> dex_bytes(DecodeBase64(base64, &length));
+  std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
   CHECK(dex_bytes.get() != NULL);
 
   // write to provided file
@@ -115,15 +116,18 @@
   if (!file->WriteFully(dex_bytes.get(), length)) {
     PLOG(FATAL) << "Failed to write base64 as dex file";
   }
+  if (file->FlushCloseOrErase() != 0) {
+    PLOG(FATAL) << "Could not flush and close test file.";
+  }
   file.reset();
 
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
-  std::vector<const DexFile*> tmp;
+  std::vector<std::unique_ptr<const DexFile>> tmp;
   bool success = DexFile::Open(location, location, error_msg, &tmp);
   CHECK(success) << error_msg;
   EXPECT_EQ(1U, tmp.size());
-  const DexFile* dex_file = tmp[0];
+  std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
   EXPECT_TRUE(dex_file->IsReadOnly());
   return dex_file;
@@ -153,18 +157,19 @@
   ASSERT_TRUE(raw.get() != nullptr) << error_msg;
 }
 
-static void FixUpChecksum(byte* dex_file) {
+static void FixUpChecksum(uint8_t* dex_file) {
   DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
   uint32_t expected_size = header->file_size_;
   uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
   const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
-  const byte* non_sum_ptr = dex_file + non_sum;
+  const uint8_t* non_sum_ptr = dex_file + non_sum;
   adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
   header->checksum_ = adler_checksum;
 }
 
-static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char* location,
-                                         std::string* error_msg) {
+static std::unique_ptr<const DexFile> FixChecksumAndOpen(uint8_t* bytes, size_t length,
+                                                         const char* location,
+                                                         std::string* error_msg) {
   // Check data.
   CHECK(bytes != nullptr);
 
@@ -177,16 +182,19 @@
   if (!file->WriteFully(bytes, length)) {
     PLOG(FATAL) << "Failed to write base64 as dex file";
   }
+  if (file->FlushCloseOrErase() != 0) {
+    PLOG(FATAL) << "Could not flush and close test file.";
+  }
   file.reset();
 
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
-  std::vector<const DexFile*> tmp;
+  std::vector<std::unique_ptr<const DexFile>> tmp;
   if (!DexFile::Open(location, location, error_msg, &tmp)) {
     return nullptr;
   }
   EXPECT_EQ(1U, tmp.size());
-  const DexFile* dex_file = tmp[0];
+  std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
   EXPECT_TRUE(dex_file->IsReadOnly());
   return dex_file;
@@ -196,7 +204,7 @@
                                     std::string* error_msg) {
   // Decode base64.
   size_t length;
-  std::unique_ptr<byte[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
+  std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
   CHECK(dex_bytes.get() != NULL);
 
   // Make modifications.
diff --git a/runtime/dex_instruction-inl.h b/runtime/dex_instruction-inl.h
index ad9491f..dd65f2c 100644
--- a/runtime/dex_instruction-inl.h
+++ b/runtime/dex_instruction-inl.h
@@ -460,11 +460,21 @@
    * copies of those.) Note that cases 5..2 fall through.
    */
   switch (count) {
-    case 5: arg[4] = InstA(inst_data);
-    case 4: arg[3] = (regList >> 12) & 0x0f;
-    case 3: arg[2] = (regList >> 8) & 0x0f;
-    case 2: arg[1] = (regList >> 4) & 0x0f;
-    case 1: arg[0] = regList & 0x0f; break;
+    case 5:
+      arg[4] = InstA(inst_data);
+      FALLTHROUGH_INTENDED;
+    case 4:
+      arg[3] = (regList >> 12) & 0x0f;
+      FALLTHROUGH_INTENDED;
+    case 3:
+      arg[2] = (regList >> 8) & 0x0f;
+      FALLTHROUGH_INTENDED;
+    case 2:
+      arg[1] = (regList >> 4) & 0x0f;
+      FALLTHROUGH_INTENDED;
+    case 1:
+      arg[0] = regList & 0x0f;
+      break;
     default:  // case 0
       break;  // Valid, but no need to do anything.
   }
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 0a71d62..a802759 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"
@@ -111,8 +112,8 @@
       if ((*insns & 0xFF) == 0) {
         return 1;  // NOP.
       } else {
-        LOG(FATAL) << "Unreachable: " << DumpString(NULL);
-        return 0;
+        LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
+        UNREACHABLE();
       }
   }
 }
@@ -161,21 +162,23 @@
     case k21c: {
       switch (Opcode()) {
         case CONST_STRING:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t string_idx = VRegB_21c();
             os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(),
                                PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx);
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case CHECK_CAST:
         case CONST_CLASS:
         case NEW_INSTANCE:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t type_idx = VRegB_21c();
             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
                << " // type@" << type_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case SGET:
         case SGET_WIDE:
         case SGET_OBJECT:
@@ -183,12 +186,13 @@
         case SGET_BYTE:
         case SGET_CHAR:
         case SGET_SHORT:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t field_idx = VRegB_21c();
             os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
                << " // field@" << field_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case SPUT:
         case SPUT_WIDE:
         case SPUT_OBJECT:
@@ -196,12 +200,13 @@
         case SPUT_BYTE:
         case SPUT_CHAR:
         case SPUT_SHORT:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t field_idx = VRegB_21c();
             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
                << " // field@" << field_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         default:
           os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
           break;
@@ -221,20 +226,22 @@
         case IGET_BYTE:
         case IGET_CHAR:
         case IGET_SHORT:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t field_idx = VRegC_22c();
             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case IGET_QUICK:
         case IGET_OBJECT_QUICK:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t field_idx = VRegC_22c();
             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << "// offset@" << field_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case IPUT:
         case IPUT_WIDE:
         case IPUT_OBJECT:
@@ -242,34 +249,38 @@
         case IPUT_BYTE:
         case IPUT_CHAR:
         case IPUT_SHORT:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t field_idx = VRegC_22c();
             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case IPUT_QUICK:
         case IPUT_OBJECT_QUICK:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t field_idx = VRegC_22c();
             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << "// offset@" << field_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case INSTANCE_OF:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t type_idx = VRegC_22c();
             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyType(type_idx, *file) << " // type@" << type_idx;
             break;
           }
+          FALLTHROUGH_INTENDED;
         case NEW_ARRAY:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t type_idx = VRegC_22c();
             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyType(type_idx, *file) << " // type@" << type_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         default:
           os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c());
           break;
@@ -283,7 +294,7 @@
     case k31c:
       if (Opcode() == CONST_STRING_JUMBO) {
         uint32_t string_idx = VRegB_31c();
-        if (file != NULL) {
+        if (file != nullptr) {
           os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(),
                              PrintableString(file->StringDataByIdx(string_idx)).c_str(),
                              string_idx);
@@ -317,7 +328,7 @@
         case INVOKE_DIRECT:
         case INVOKE_STATIC:
         case INVOKE_INTERFACE:
-          if (file != NULL) {
+          if (file != nullptr) {
             os << opcode << " {";
             uint32_t method_idx = VRegB_35c();
             for (size_t i = 0; i < VRegA_35c(); ++i) {
@@ -328,9 +339,10 @@
             }
             os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case INVOKE_VIRTUAL_QUICK:
-          if (file != NULL) {
+          if (file != nullptr) {
             os << opcode << " {";
             uint32_t method_idx = VRegB_35c();
             for (size_t i = 0; i < VRegA_35c(); ++i) {
@@ -341,7 +353,8 @@
             }
             os << "},  // vtable@" << method_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         default:
           os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2]
                        << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c();
@@ -356,19 +369,21 @@
         case INVOKE_DIRECT_RANGE:
         case INVOKE_STATIC_RANGE:
         case INVOKE_INTERFACE_RANGE:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t method_idx = VRegB_3rc();
             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
                << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         case INVOKE_VIRTUAL_RANGE_QUICK:
-          if (file != NULL) {
+          if (file != nullptr) {
             uint32_t method_idx = VRegB_3rc();
             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
                << "// vtable@" << method_idx;
             break;
-          }  // else fall-through
+          }
+          FALLTHROUGH_INTENDED;
         default:
           os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(),
                              (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc());
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index b913220..af5d9d0 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -35,7 +35,7 @@
 class Instruction {
  public:
   // NOP-encoded switch-statement signatures.
-  enum {
+  enum Signatures {
     kPackedSwitchSignature = 0x0100,
     kSparseSwitchSignature = 0x0200,
     kArrayDataSignature = 0x0300,
@@ -79,15 +79,13 @@
     DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
   };
 
-  // TODO: the code layout below is deliberate to avoid this enum being picked up by
-  //       generate-operator-out.py.
-  enum Code
-  {  // NOLINT(whitespace/braces)
+  enum Code {  // private marker to avoid generate-operator-out.py from processing.
 #define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode,
 #include "dex_instruction_list.h"
     DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
 #undef DEX_INSTRUCTION_LIST
 #undef INSTRUCTION_ENUM
+    RSUB_INT_LIT16 = RSUB_INT,
   };
 
   enum Format {
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index 05214a4..a90f424 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -257,10 +257,10 @@
   V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
   V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
   V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xEF, UNUSED_EF, "unused-ef", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF0, UNUSED_F0, "unused-f0", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF1, UNUSED_F1, "unused-f1", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF2, UNUSED_F2, "unused-f2", k10x, false, kUnknown, 0, kVerifyError) \
+  V(0xEF, IGET_BOOLEAN_QUICK, "iget-boolean-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF0, IGET_BYTE_QUICK, "iget-byte-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF1, IGET_CHAR_QUICK, "iget-char-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF2, IGET_SHORT_QUICK, "iget-short-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
   V(0xF3, UNUSED_F3, "unused-f3", k10x, false, kUnknown, 0, kVerifyError) \
   V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kUnknown, 0, kVerifyError) \
   V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kUnknown, 0, kVerifyError) \
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.h b/runtime/dex_method_iterator.h
index 806266d..14e316f 100644
--- a/runtime/dex_method_iterator.h
+++ b/runtime/dex_method_iterator.h
@@ -139,7 +139,7 @@
   uint32_t dex_file_index_;
   uint32_t class_def_index_;
   const DexFile::ClassDef* class_def_;
-  const byte* class_data_;
+  const uint8_t* class_data_;
   std::unique_ptr<ClassDataItemIterator> it_;
   bool direct_method_;
 };
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index b8f180b..2681ad0 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -18,6 +18,7 @@
 
 #include "base/stl_util.h"
 #include "common_runtime_test.h"
+#include "oat_file.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
 
@@ -29,21 +30,20 @@
 TEST_F(DexMethodIteratorTest, Basic) {
   ScopedObjectAccess soa(Thread::Current());
   std::vector<const DexFile*> dex_files;
-  const char* jars[] = { "core-libart", "conscrypt", "okhttp", "core-junit", "bouncycastle" };
-  for (size_t i = 0; i < 5; ++i) {
-    dex_files.push_back(LoadExpectSingleDexFile(GetDexFileName(jars[i]).c_str()));
+  CHECK_NE(boot_class_path_.size(), 0U);
+  for (size_t i = 0; i < boot_class_path_.size(); ++i) {
+    dex_files.push_back(boot_class_path_[i]);
   }
   DexMethodIterator it(dex_files);
   while (it.HasNext()) {
     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();
   }
-  STLDeleteElements(&dex_files);
 }
 
 }  // namespace art
diff --git a/runtime/dwarf.h b/runtime/dwarf.h
index 370ad95..7daa5f1 100644
--- a/runtime/dwarf.h
+++ b/runtime/dwarf.h
@@ -364,38 +364,38 @@
   DW_OP_reg29 = 0x6d,
   DW_OP_reg30 = 0x6e,
   DW_OP_reg31 = 0x6f,
-  DW_OP_breg0 = 0x50,
-  DW_OP_breg1 = 0x51,
-  DW_OP_breg2 = 0x52,
-  DW_OP_breg3 = 0x53,
-  DW_OP_breg4 = 0x54,
-  DW_OP_breg5 = 0x55,
-  DW_OP_breg6 = 0x56,
-  DW_OP_breg7 = 0x57,
-  DW_OP_breg8 = 0x58,
-  DW_OP_breg9 = 0x59,
-  DW_OP_breg10 = 0x5a,
-  DW_OP_breg11 = 0x5b,
-  DW_OP_breg12 = 0x5c,
-  DW_OP_breg13 = 0x5d,
-  DW_OP_breg14 = 0x5e,
-  DW_OP_breg15 = 0x5f,
-  DW_OP_breg16 = 0x60,
-  DW_OP_breg17 = 0x61,
-  DW_OP_breg18 = 0x62,
-  DW_OP_breg19 = 0x63,
-  DW_OP_breg20 = 0x64,
-  DW_OP_breg21 = 0x65,
-  DW_OP_breg22 = 0x66,
-  DW_OP_breg23 = 0x67,
-  DW_OP_breg24 = 0x68,
-  DW_OP_breg25 = 0x69,
-  DW_OP_breg26 = 0x6a,
-  DW_OP_breg27 = 0x6b,
-  DW_OP_breg28 = 0x6c,
-  DW_OP_breg29 = 0x6d,
-  DW_OP_breg30 = 0x6e,
-  DW_OP_breg31 = 0x6f,
+  DW_OP_breg0 = 0x70,
+  DW_OP_breg1 = 0x71,
+  DW_OP_breg2 = 0x72,
+  DW_OP_breg3 = 0x73,
+  DW_OP_breg4 = 0x74,
+  DW_OP_breg5 = 0x75,
+  DW_OP_breg6 = 0x76,
+  DW_OP_breg7 = 0x77,
+  DW_OP_breg8 = 0x78,
+  DW_OP_breg9 = 0x79,
+  DW_OP_breg10 = 0x7a,
+  DW_OP_breg11 = 0x7b,
+  DW_OP_breg12 = 0x7c,
+  DW_OP_breg13 = 0x7d,
+  DW_OP_breg14 = 0x7e,
+  DW_OP_breg15 = 0x7f,
+  DW_OP_breg16 = 0x80,
+  DW_OP_breg17 = 0x81,
+  DW_OP_breg18 = 0x82,
+  DW_OP_breg19 = 0x83,
+  DW_OP_breg20 = 0x84,
+  DW_OP_breg21 = 0x85,
+  DW_OP_breg22 = 0x86,
+  DW_OP_breg23 = 0x87,
+  DW_OP_breg24 = 0x88,
+  DW_OP_breg25 = 0x89,
+  DW_OP_breg26 = 0x8a,
+  DW_OP_breg27 = 0x8b,
+  DW_OP_breg28 = 0x8c,
+  DW_OP_breg29 = 0x8d,
+  DW_OP_breg30 = 0x8e,
+  DW_OP_breg31 = 0x8f,
   DW_OP_regx = 0x90,
   DW_OP_fbreg = 0x91,
   DW_OP_bregx = 0x92,
diff --git a/runtime/elf.h b/runtime/elf.h
index 6e007a2..60b5248 100644
--- a/runtime/elf.h
+++ b/runtime/elf.h
@@ -1411,6 +1411,7 @@
 
 // BEGIN android-added for <elf.h> compat
 static inline unsigned char ELF32_ST_TYPE(unsigned char st_info) { return st_info & 0x0f; }
+static inline unsigned char ELF64_ST_TYPE(unsigned char st_info) { return st_info & 0x0f; }
 // END android-added for <elf.h> compat
 
 // Symbol table entries for ELF64.
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 65a557b..1b91aa6 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -16,16 +16,20 @@
 
 #include "elf_file.h"
 
+#include <inttypes.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "arch/instruction_set.h"
 #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"
 
 namespace art {
 
@@ -42,7 +46,7 @@
   struct JITCodeEntry {
     JITCodeEntry* next_;
     JITCodeEntry* prev_;
-    const byte *symfile_addr_;
+    const uint8_t *symfile_addr_;
     uint64_t symfile_size_;
   };
 
@@ -56,6 +60,7 @@
   // GDB will place breakpoint into this function.
   // To prevent GCC from inlining or removing it we place noinline attribute
   // and inline assembler statement inside.
+  void __attribute__((noinline)) __jit_debug_register_code();
   void __attribute__((noinline)) __jit_debug_register_code() {
     __asm__("");
   }
@@ -67,7 +72,7 @@
 }
 
 
-static JITCodeEntry* CreateCodeEntry(const byte *symfile_addr,
+static JITCodeEntry* CreateCodeEntry(const uint8_t *symfile_addr,
                                      uintptr_t symfile_size) {
   JITCodeEntry* entry = new JITCodeEntry;
   entry->symfile_addr_ = symfile_addr;
@@ -106,7 +111,12 @@
   delete entry;
 }
 
-ElfFile::ElfFile(File* file, bool writable, bool program_header_only)
+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>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base)
   : file_(file),
     writable_(writable),
     program_header_only_(program_header_only),
@@ -124,13 +134,25 @@
     symtab_symbol_table_(nullptr),
     dynsym_symbol_table_(nullptr),
     jit_elf_image_(nullptr),
-    jit_gdb_entry_(nullptr) {
+    jit_gdb_entry_(nullptr),
+    requested_base_(requested_base) {
   CHECK(file != nullptr);
 }
 
-ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only,
-                       std::string* error_msg) {
-  std::unique_ptr<ElfFile> elf_file(new ElfFile(file, writable, program_header_only));
+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>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>*
+    ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Open(File* file, bool writable, bool program_header_only,
+           std::string* error_msg, uint8_t* requested_base) {
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>>
+    elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+                 Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+                 (file, writable, program_header_only, requested_base));
   int prot;
   int flags;
   if (writable) {
@@ -146,15 +168,32 @@
   return elf_file.release();
 }
 
-ElfFile* ElfFile::Open(File* file, int prot, int flags, std::string* error_msg) {
-  std::unique_ptr<ElfFile> elf_file(new ElfFile(file, (prot & PROT_WRITE) == PROT_WRITE, false));
+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>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>*
+    ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Open(File* file, int prot, int flags, std::string* error_msg) {
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>>
+    elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+                 Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+                 (file, (prot & PROT_WRITE) == PROT_WRITE, /*program_header_only*/false,
+                 /*requested_base*/nullptr));
   if (!elf_file->Setup(prot, flags, error_msg)) {
     return nullptr;
   }
   return elf_file.release();
 }
 
-bool ElfFile::Setup(int prot, int flags, std::string* error_msg) {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Setup(int prot, int flags, std::string* error_msg) {
   int64_t temp_file_length = file_->GetLength();
   if (temp_file_length < 0) {
     errno = -temp_file_length;
@@ -163,16 +202,16 @@
     return false;
   }
   size_t file_length = static_cast<size_t>(temp_file_length);
-  if (file_length < sizeof(Elf32_Ehdr)) {
+  if (file_length < sizeof(Elf_Ehdr)) {
     *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF header of "
-                              "%zd bytes: '%s'", file_length, sizeof(Elf32_Ehdr),
+                              "%zd bytes: '%s'", file_length, sizeof(Elf_Ehdr),
                               file_->GetPath().c_str());
     return false;
   }
 
   if (program_header_only_) {
     // first just map ELF header to get program header size information
-    size_t elf_header_size = sizeof(Elf32_Ehdr);
+    size_t elf_header_size = sizeof(Elf_Ehdr);
     if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0,
                                 file_->GetPath().c_str(), error_msg),
                 error_msg)) {
@@ -183,7 +222,7 @@
     if (file_length < program_header_size) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF program "
                                 "header of %zd bytes: '%s'", file_length,
-                                sizeof(Elf32_Ehdr), file_->GetPath().c_str());
+                                sizeof(Elf_Ehdr), file_->GetPath().c_str());
       return false;
     }
     if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0,
@@ -215,7 +254,7 @@
     }
 
     // Find shstrtab.
-    Elf32_Shdr* shstrtab_section_header = GetSectionNameStringSection();
+    Elf_Shdr* shstrtab_section_header = GetSectionNameStringSection();
     if (shstrtab_section_header == nullptr) {
       *error_msg = StringPrintf("Failed to find shstrtab section header in ELF file: '%s'",
                                 file_->GetPath().c_str());
@@ -231,13 +270,13 @@
     }
 
     if (!CheckAndSet(GetDynamicProgramHeader().p_offset, "dynamic section",
-                     reinterpret_cast<byte**>(&dynamic_section_start_), error_msg)) {
+                     reinterpret_cast<uint8_t**>(&dynamic_section_start_), error_msg)) {
       return false;
     }
 
     // Find other sections from section headers
-    for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-      Elf32_Shdr* section_header = GetSectionHeader(i);
+    for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+      Elf_Shdr* section_header = GetSectionHeader(i);
       if (section_header == nullptr) {
         *error_msg = StringPrintf("Failed to find section header for section %d in ELF file: '%s'",
                                   i, file_->GetPath().c_str());
@@ -246,14 +285,14 @@
       switch (section_header->sh_type) {
         case SHT_SYMTAB: {
           if (!CheckAndSet(section_header->sh_offset, "symtab",
-                           reinterpret_cast<byte**>(&symtab_section_start_), error_msg)) {
+                           reinterpret_cast<uint8_t**>(&symtab_section_start_), error_msg)) {
             return false;
           }
           break;
         }
         case SHT_DYNSYM: {
           if (!CheckAndSet(section_header->sh_offset, "dynsym",
-                           reinterpret_cast<byte**>(&dynsym_section_start_), error_msg)) {
+                           reinterpret_cast<uint8_t**>(&dynsym_section_start_), error_msg)) {
             return false;
           }
           break;
@@ -265,7 +304,7 @@
             const char* header_name = GetString(*shstrtab_section_header, section_header->sh_name);
             if (strncmp(".dynstr", header_name, 8) == 0) {
               if (!CheckAndSet(section_header->sh_offset, "dynstr",
-                               reinterpret_cast<byte**>(&dynstr_section_start_), error_msg)) {
+                               reinterpret_cast<uint8_t**>(&dynstr_section_start_), error_msg)) {
                 return false;
               }
             }
@@ -274,7 +313,7 @@
             const char* header_name = GetString(*shstrtab_section_header, section_header->sh_name);
             if (strncmp(".strtab", header_name, 8) == 0) {
               if (!CheckAndSet(section_header->sh_offset, "strtab",
-                               reinterpret_cast<byte**>(&strtab_section_start_), error_msg)) {
+                               reinterpret_cast<uint8_t**>(&strtab_section_start_), error_msg)) {
                 return false;
               }
             }
@@ -282,7 +321,7 @@
           break;
         }
         case SHT_DYNAMIC: {
-          if (reinterpret_cast<byte*>(dynamic_section_start_) !=
+          if (reinterpret_cast<uint8_t*>(dynamic_section_start_) !=
               Begin() + section_header->sh_offset) {
             LOG(WARNING) << "Failed to find matching SHT_DYNAMIC for PT_DYNAMIC in "
                          << file_->GetPath() << ": " << std::hex
@@ -294,7 +333,7 @@
         }
         case SHT_HASH: {
           if (!CheckAndSet(section_header->sh_offset, "hash section",
-                           reinterpret_cast<byte**>(&hash_section_start_), error_msg)) {
+                           reinterpret_cast<uint8_t**>(&hash_section_start_), error_msg)) {
             return false;
           }
           break;
@@ -311,7 +350,12 @@
   return true;
 }
 
-ElfFile::~ElfFile() {
+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>
+ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::~ElfFileImpl() {
   STLDeleteElements(&segments_);
   delete symtab_symbol_table_;
   delete dynsym_symbol_table_;
@@ -321,8 +365,13 @@
   }
 }
 
-bool ElfFile::CheckAndSet(Elf32_Off offset, const char* label,
-                          byte** target, std::string* error_msg) {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::CheckAndSet(Elf32_Off offset, const char* label,
+                  uint8_t** target, std::string* error_msg) {
   if (Begin() + offset >= End()) {
     *error_msg = StringPrintf("Offset %d is out of range for %s in ELF file: '%s'", offset, label,
                               file_->GetPath().c_str());
@@ -332,18 +381,23 @@
   return true;
 }
 
-bool ElfFile::CheckSectionsLinked(const byte* source, const byte* target) const {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::CheckSectionsLinked(const uint8_t* source, const uint8_t* target) const {
   // Only works in whole-program mode, as we need to iterate over the sections.
   // Note that we normally can't search by type, as duplicates are allowed for most section types.
   if (program_header_only_) {
     return true;
   }
 
-  Elf32_Shdr* source_section = nullptr;
-  Elf32_Word target_index = 0;
+  Elf_Shdr* source_section = nullptr;
+  Elf_Word target_index = 0;
   bool target_found = false;
-  for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* section_header = GetSectionHeader(i);
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* section_header = GetSectionHeader(i);
 
     if (Begin() + section_header->sh_offset == source) {
       // Found the source.
@@ -363,7 +417,12 @@
   return target_found && source_section != nullptr && source_section->sh_link == target_index;
 }
 
-bool ElfFile::CheckSectionsExist(std::string* error_msg) const {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::CheckSectionsExist(std::string* error_msg) const {
   if (!program_header_only_) {
     // If in full mode, need section headers.
     if (section_headers_start_ == nullptr) {
@@ -396,8 +455,8 @@
     }
 
     // The symtab should link to the strtab.
-    if (!CheckSectionsLinked(reinterpret_cast<const byte*>(symtab_section_start_),
-                             reinterpret_cast<const byte*>(strtab_section_start_))) {
+    if (!CheckSectionsLinked(reinterpret_cast<const uint8_t*>(symtab_section_start_),
+                             reinterpret_cast<const uint8_t*>(strtab_section_start_))) {
       *error_msg = StringPrintf("Symtab is not linked to the strtab in ELF file: '%s'",
                                 file_->GetPath().c_str());
       return false;
@@ -422,17 +481,36 @@
   }
 
   // And the hash section should be linking to the dynsym.
-  if (!CheckSectionsLinked(reinterpret_cast<const byte*>(hash_section_start_),
-                           reinterpret_cast<const byte*>(dynsym_section_start_))) {
+  if (!CheckSectionsLinked(reinterpret_cast<const uint8_t*>(hash_section_start_),
+                           reinterpret_cast<const uint8_t*>(dynsym_section_start_))) {
     *error_msg = StringPrintf("Hash section is not linked to the dynstr in ELF file: '%s'",
                               file_->GetPath().c_str());
     return false;
   }
 
+  // We'd also like to confirm a shstrtab in program_header_only_ mode (else Open() does this for
+  // us). This is usually the last in an oat file, and a good indicator of whether writing was
+  // successful (or the process crashed and left garbage).
+  if (program_header_only_) {
+    // It might not be mapped, but we can compare against the file size.
+    int64_t offset = static_cast<int64_t>(GetHeader().e_shoff +
+                                          (GetHeader().e_shstrndx * GetHeader().e_shentsize));
+    if (offset >= file_->GetLength()) {
+      *error_msg = StringPrintf("Shstrtab is not in the mapped ELF file: '%s'",
+                                file_->GetPath().c_str());
+      return false;
+    }
+  }
+
   return true;
 }
 
-bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::SetMap(MemMap* map, std::string* error_msg) {
   if (map == nullptr) {
     // MemMap::Open should have already set an error.
     DCHECK(!error_msg->empty());
@@ -442,7 +520,7 @@
   CHECK(map_.get() != nullptr) << file_->GetPath();
   CHECK(map_->Begin() != nullptr) << file_->GetPath();
 
-  header_ = reinterpret_cast<Elf32_Ehdr*>(map_->Begin());
+  header_ = reinterpret_cast<Elf_Ehdr*>(map_->Begin());
   if ((ELFMAG0 != header_->e_ident[EI_MAG0])
       || (ELFMAG1 != header_->e_ident[EI_MAG1])
       || (ELFMAG2 != header_->e_ident[EI_MAG2])
@@ -456,9 +534,10 @@
                               header_->e_ident[EI_MAG3]);
     return false;
   }
-  if (ELFCLASS32 != header_->e_ident[EI_CLASS]) {
+  uint8_t elf_class = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)) ? ELFCLASS64 : ELFCLASS32;
+  if (elf_class != header_->e_ident[EI_CLASS]) {
     *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d in %s, found %d",
-                              ELFCLASS32,
+                              elf_class,
                               file_->GetPath().c_str(),
                               header_->e_ident[EI_CLASS]);
     return false;
@@ -495,7 +574,7 @@
     *error_msg = StringPrintf("Failed to find expected e_entry value %d in %s, found %d",
                               0,
                               file_->GetPath().c_str(),
-                              header_->e_entry);
+                              static_cast<int32_t>(header_->e_entry));
     return false;
   }
   if (0 == header_->e_phoff) {
@@ -548,15 +627,15 @@
 
   if (!program_header_only_) {
     if (header_->e_phoff >= Size()) {
-      *error_msg = StringPrintf("Failed to find e_phoff value %d less than %zd in %s",
-                                header_->e_phoff,
+      *error_msg = StringPrintf("Failed to find e_phoff value %" PRIu64 " less than %zd in %s",
+                                static_cast<uint64_t>(header_->e_phoff),
                                 Size(),
                                 file_->GetPath().c_str());
       return false;
     }
     if (header_->e_shoff >= Size()) {
-      *error_msg = StringPrintf("Failed to find e_shoff value %d less than %zd in %s",
-                                header_->e_shoff,
+      *error_msg = StringPrintf("Failed to find e_shoff value %" PRIu64 " less than %zd in %s",
+                                static_cast<uint64_t>(header_->e_shoff),
                                 Size(),
                                 file_->GetPath().c_str());
       return false;
@@ -565,39 +644,64 @@
   return true;
 }
 
-
-Elf32_Ehdr& ElfFile::GetHeader() const {
+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>
+Elf_Ehdr& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHeader() const {
   CHECK(header_ != nullptr);  // Header has been checked in SetMap. This is a sanity check.
   return *header_;
 }
 
-byte* ElfFile::GetProgramHeadersStart() const {
+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>
+uint8_t* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetProgramHeadersStart() const {
   CHECK(program_headers_start_ != nullptr);  // Header has been set in Setup. This is a sanity
                                              // check.
   return program_headers_start_;
 }
 
-byte* ElfFile::GetSectionHeadersStart() const {
+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>
+uint8_t* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionHeadersStart() const {
   CHECK(!program_header_only_);              // Only used in "full" mode.
   CHECK(section_headers_start_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return section_headers_start_;
 }
 
-Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const {
+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>
+Elf_Phdr& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamicProgramHeader() const {
   CHECK(dynamic_program_header_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return *dynamic_program_header_;
 }
 
-Elf32_Dyn* ElfFile::GetDynamicSectionStart() const {
+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>
+Elf_Dyn* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamicSectionStart() const {
   CHECK(dynamic_section_start_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return dynamic_section_start_;
 }
 
-static bool IsSymbolSectionType(Elf32_Word section_type) {
-  return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
-}
-
-Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const {
+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>
+Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbolSectionStart(Elf_Word section_type) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
@@ -615,7 +719,12 @@
   }
 }
 
-const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const {
+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>
+const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetStringSectionStart(Elf_Word section_type) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
@@ -631,7 +740,12 @@
   }
 }
 
-const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
+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>
+const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetString(Elf_Word section_type, Elf_Word i) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   if (i == 0) {
     return nullptr;
@@ -646,19 +760,39 @@
 // WARNING: The following methods do not check for an error condition (non-existent hash section).
 //          It is the caller's job to do this.
 
-Elf32_Word* ElfFile::GetHashSectionStart() const {
+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>
+Elf_Word* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashSectionStart() const {
   return hash_section_start_;
 }
 
-Elf32_Word ElfFile::GetHashBucketNum() const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashBucketNum() const {
   return GetHashSectionStart()[0];
 }
 
-Elf32_Word ElfFile::GetHashChainNum() const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashChainNum() const {
   return GetHashSectionStart()[1];
 }
 
-Elf32_Word ElfFile::GetHashBucket(size_t i, bool* ok) const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashBucket(size_t i, bool* ok) const {
   if (i >= GetHashBucketNum()) {
     *ok = false;
     return 0;
@@ -668,8 +802,13 @@
   return GetHashSectionStart()[2 + i];
 }
 
-Elf32_Word ElfFile::GetHashChain(size_t i, bool* ok) const {
-  if (i >= GetHashBucketNum()) {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetHashChain(size_t i, bool* ok) const {
+  if (i >= GetHashChainNum()) {
     *ok = false;
     return 0;
   }
@@ -678,22 +817,37 @@
   return GetHashSectionStart()[2 + GetHashBucketNum() + i];
 }
 
-Elf32_Word ElfFile::GetProgramHeaderNum() const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetProgramHeaderNum() const {
   return GetHeader().e_phnum;
 }
 
-Elf32_Phdr* ElfFile::GetProgramHeader(Elf32_Word i) const {
+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>
+Elf_Phdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetProgramHeader(Elf_Word i) const {
   CHECK_LT(i, GetProgramHeaderNum()) << file_->GetPath();  // Sanity check for caller.
-  byte* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize);
+  uint8_t* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize);
   if (program_header >= End()) {
     return nullptr;  // Failure condition.
   }
-  return reinterpret_cast<Elf32_Phdr*>(program_header);
+  return reinterpret_cast<Elf_Phdr*>(program_header);
 }
 
-Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const {
-  for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* program_header = GetProgramHeader(i);
+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>
+Elf_Phdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindProgamHeaderByType(Elf_Word type) const {
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header->p_type == type) {
       return program_header;
     }
@@ -701,30 +855,45 @@
   return nullptr;
 }
 
-Elf32_Word ElfFile::GetSectionHeaderNum() const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionHeaderNum() const {
   return GetHeader().e_shnum;
 }
 
-Elf32_Shdr* ElfFile::GetSectionHeader(Elf32_Word i) const {
+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>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionHeader(Elf_Word i) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // Even if we Load(), it doesn't bring in all the sections.
   CHECK(!program_header_only_) << file_->GetPath();
   if (i >= GetSectionHeaderNum()) {
     return nullptr;  // Failure condition.
   }
-  byte* section_header = GetSectionHeadersStart() + (i * GetHeader().e_shentsize);
+  uint8_t* section_header = GetSectionHeadersStart() + (i * GetHeader().e_shentsize);
   if (section_header >= End()) {
     return nullptr;  // Failure condition.
   }
-  return reinterpret_cast<Elf32_Shdr*>(section_header);
+  return reinterpret_cast<Elf_Shdr*>(section_header);
 }
 
-Elf32_Shdr* ElfFile::FindSectionByType(Elf32_Word type) const {
+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>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSectionByType(Elf_Word type) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // We could change this to switch on known types if they were detected during loading.
   CHECK(!program_header_only_) << file_->GetPath();
-  for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* section_header = GetSectionHeader(i);
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* section_header = GetSectionHeader(i);
     if (section_header->sh_type == type) {
       return section_header;
     }
@@ -746,17 +915,29 @@
   return h;
 }
 
-Elf32_Shdr* ElfFile::GetSectionNameStringSection() const {
+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>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSectionNameStringSection() const {
   return GetSectionHeader(GetHeader().e_shstrndx);
 }
 
-const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+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>
+const uint8_t* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicSymbolAddress(const std::string& symbol_name) const {
   // Check that we have a hash section.
   if (GetHashSectionStart() == nullptr) {
     return nullptr;  // Failure condition.
   }
-  const Elf32_Sym* sym = FindDynamicSymbol(symbol_name);
+  const Elf_Sym* sym = FindDynamicSymbol(symbol_name);
   if (sym != nullptr) {
+    // TODO: we need to change this to calculate base_address_ in ::Open,
+    // otherwise it will be wrongly 0 if ::Load has not yet been called.
     return base_address_ + sym->st_value;
   } else {
     return nullptr;
@@ -764,20 +945,25 @@
 }
 
 // WARNING: Only called from FindDynamicSymbolAddress. Elides check for hash section.
-const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const {
+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>
+const Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicSymbol(const std::string& symbol_name) const {
   if (GetHashBucketNum() == 0) {
     // No dynamic symbols at all.
     return nullptr;
   }
-  Elf32_Word hash = elfhash(symbol_name.c_str());
-  Elf32_Word bucket_index = hash % GetHashBucketNum();
+  Elf_Word hash = elfhash(symbol_name.c_str());
+  Elf_Word bucket_index = hash % GetHashBucketNum();
   bool ok;
-  Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok);
+  Elf_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok);
   if (!ok) {
     return nullptr;
   }
   while (symbol_and_chain_index != 0 /* STN_UNDEF */) {
-    Elf32_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
+    Elf_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
     if (symbol == nullptr) {
       return nullptr;  // Failure condition.
     }
@@ -793,23 +979,49 @@
   return nullptr;
 }
 
-Elf32_Word ElfFile::GetSymbolNum(Elf32_Shdr& section_header) const {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::IsSymbolSectionType(Elf_Word section_type) {
+  return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
+}
+
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbolNum(Elf_Shdr& section_header) const {
   CHECK(IsSymbolSectionType(section_header.sh_type))
       << file_->GetPath() << " " << section_header.sh_type;
   CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Sym* ElfFile::GetSymbol(Elf32_Word section_type,
-                              Elf32_Word i) const {
-  Elf32_Sym* sym_start = GetSymbolSectionStart(section_type);
+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>
+Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbol(Elf_Word section_type,
+                Elf_Word i) const {
+  Elf_Sym* sym_start = GetSymbolSectionStart(section_type);
   if (sym_start == nullptr) {
     return nullptr;
   }
   return sym_start + i;
 }
 
-ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) {
+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>
+typename ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::SymbolTable** ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetSymbolTable(Elf_Word section_type) {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   switch (section_type) {
     case SHT_SYMTAB: {
@@ -825,9 +1037,14 @@
   }
 }
 
-Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type,
-                                     const std::string& symbol_name,
-                                     bool build_map) {
+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>
+Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSymbolByName(Elf_Word section_type,
+                       const std::string& symbol_name,
+                       bool build_map) {
   CHECK(!program_header_only_) << file_->GetPath();
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
 
@@ -836,20 +1053,22 @@
     if (*symbol_table == nullptr) {
       DCHECK(build_map);
       *symbol_table = new SymbolTable;
-      Elf32_Shdr* symbol_section = FindSectionByType(section_type);
+      Elf_Shdr* symbol_section = FindSectionByType(section_type);
       if (symbol_section == nullptr) {
         return nullptr;  // Failure condition.
       }
-      Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
+      Elf_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
       if (string_section == nullptr) {
         return nullptr;  // Failure condition.
       }
       for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
-        Elf32_Sym* symbol = GetSymbol(section_type, i);
+        Elf_Sym* symbol = GetSymbol(section_type, i);
         if (symbol == nullptr) {
           return nullptr;  // Failure condition.
         }
-        unsigned char type = ELF32_ST_TYPE(symbol->st_info);
+        unsigned char type = (sizeof(Elf_Addr) == sizeof(Elf64_Addr))
+                             ? ELF64_ST_TYPE(symbol->st_info)
+                             : ELF32_ST_TYPE(symbol->st_info);
         if (type == STT_NOTYPE) {
           continue;
         }
@@ -857,7 +1076,7 @@
         if (name == nullptr) {
           continue;
         }
-        std::pair<SymbolTable::iterator, bool> result =
+        std::pair<typename SymbolTable::iterator, bool> result =
             (*symbol_table)->insert(std::make_pair(name, symbol));
         if (!result.second) {
           // If a duplicate, make sure it has the same logical value. Seen on x86.
@@ -872,7 +1091,7 @@
       }
     }
     CHECK(*symbol_table != nullptr);
-    SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
+    typename SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
     if (it == (*symbol_table)->end()) {
       return nullptr;
     }
@@ -880,16 +1099,16 @@
   }
 
   // Fall back to linear search
-  Elf32_Shdr* symbol_section = FindSectionByType(section_type);
+  Elf_Shdr* symbol_section = FindSectionByType(section_type);
   if (symbol_section == nullptr) {
     return nullptr;
   }
-  Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
+  Elf_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
   if (string_section == nullptr) {
     return nullptr;
   }
   for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
-    Elf32_Sym* symbol = GetSymbol(section_type, i);
+    Elf_Sym* symbol = GetSymbol(section_type, i);
     if (symbol == nullptr) {
       return nullptr;  // Failure condition.
     }
@@ -904,20 +1123,30 @@
   return nullptr;
 }
 
-Elf32_Addr ElfFile::FindSymbolAddress(Elf32_Word section_type,
-                                      const std::string& symbol_name,
-                                      bool build_map) {
-  Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
+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>
+Elf_Addr ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSymbolAddress(Elf_Word section_type,
+                        const std::string& symbol_name,
+                        bool build_map) {
+  Elf_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
   if (symbol == nullptr) {
     return 0;
   }
   return symbol->st_value;
 }
 
-const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const {
+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>
+const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetString(Elf_Shdr& string_section, Elf_Word i) const {
   CHECK(!program_header_only_) << file_->GetPath();
   // TODO: remove this static_cast from enum when using -std=gnu++0x
-  if (static_cast<Elf32_Word>(SHT_STRTAB) != string_section.sh_type) {
+  if (static_cast<Elf_Word>(SHT_STRTAB) != string_section.sh_type) {
     return nullptr;  // Failure condition.
   }
   if (i >= string_section.sh_size) {
@@ -926,26 +1155,41 @@
   if (i == 0) {
     return nullptr;
   }
-  byte* strings = Begin() + string_section.sh_offset;
-  byte* string = strings + i;
+  uint8_t* strings = Begin() + string_section.sh_offset;
+  uint8_t* string = strings + i;
   if (string >= End()) {
     return nullptr;
   }
   return reinterpret_cast<const char*>(string);
 }
 
-Elf32_Word ElfFile::GetDynamicNum() const {
-  return GetDynamicProgramHeader().p_filesz / sizeof(Elf32_Dyn);
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamicNum() const {
+  return GetDynamicProgramHeader().p_filesz / sizeof(Elf_Dyn);
 }
 
-Elf32_Dyn& ElfFile::GetDynamic(Elf32_Word i) const {
+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>
+Elf_Dyn& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetDynamic(Elf_Word i) const {
   CHECK_LT(i, GetDynamicNum()) << file_->GetPath();
   return *(GetDynamicSectionStart() + i);
 }
 
-Elf32_Dyn* ElfFile::FindDynamicByType(Elf32_Sword type) const {
-  for (Elf32_Word i = 0; i < GetDynamicNum(); i++) {
-    Elf32_Dyn* dyn = &GetDynamic(i);
+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>
+Elf_Dyn* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicByType(Elf_Sword type) const {
+  for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
+    Elf_Dyn* dyn = &GetDynamic(i);
     if (dyn->d_tag == type) {
       return dyn;
     }
@@ -953,8 +1197,13 @@
   return NULL;
 }
 
-Elf32_Word ElfFile::FindDynamicValueByType(Elf32_Sword type) const {
-  Elf32_Dyn* dyn = FindDynamicByType(type);
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindDynamicValueByType(Elf_Sword type) const {
+  Elf_Dyn* dyn = FindDynamicByType(type);
   if (dyn == NULL) {
     return 0;
   } else {
@@ -962,53 +1211,88 @@
   }
 }
 
-Elf32_Rel* ElfFile::GetRelSectionStart(Elf32_Shdr& section_header) const {
+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>
+Elf_Rel* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRelSectionStart(Elf_Shdr& section_header) const {
   CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  return reinterpret_cast<Elf32_Rel*>(Begin() + section_header.sh_offset);
+  return reinterpret_cast<Elf_Rel*>(Begin() + section_header.sh_offset);
 }
 
-Elf32_Word ElfFile::GetRelNum(Elf32_Shdr& section_header) const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRelNum(Elf_Shdr& section_header) const {
   CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath();
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Rel& ElfFile::GetRel(Elf32_Shdr& section_header, Elf32_Word i) const {
+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>
+Elf_Rel& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRel(Elf_Shdr& section_header, Elf_Word i) const {
   CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   CHECK_LT(i, GetRelNum(section_header)) << file_->GetPath();
   return *(GetRelSectionStart(section_header) + i);
 }
 
-Elf32_Rela* ElfFile::GetRelaSectionStart(Elf32_Shdr& section_header) const {
+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>
+Elf_Rela* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+  Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+  ::GetRelaSectionStart(Elf_Shdr& section_header) const {
   CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
-  return reinterpret_cast<Elf32_Rela*>(Begin() + section_header.sh_offset);
+  return reinterpret_cast<Elf_Rela*>(Begin() + section_header.sh_offset);
 }
 
-Elf32_Word ElfFile::GetRelaNum(Elf32_Shdr& section_header) const {
+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>
+Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRelaNum(Elf_Shdr& section_header) const {
   CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Rela& ElfFile::GetRela(Elf32_Shdr& section_header, Elf32_Word i) const {
+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>
+Elf_Rela& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetRela(Elf_Shdr& section_header, Elf_Word i) const {
   CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type;
   CHECK_LT(i, GetRelaNum(section_header)) << file_->GetPath();
   return *(GetRelaSectionStart(section_header) + i);
 }
 
 // Base on bionic phdr_table_get_load_size
-size_t ElfFile::GetLoadedSize() const {
-  Elf32_Addr min_vaddr = 0xFFFFFFFFu;
-  Elf32_Addr max_vaddr = 0x00000000u;
-  for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* program_header = GetProgramHeader(i);
+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>
+size_t ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GetLoadedSize() const {
+  Elf_Addr min_vaddr = 0xFFFFFFFFu;
+  Elf_Addr max_vaddr = 0x00000000u;
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header->p_type != PT_LOAD) {
       continue;
     }
-    Elf32_Addr begin_vaddr = program_header->p_vaddr;
+    Elf_Addr begin_vaddr = program_header->p_vaddr;
     if (begin_vaddr < min_vaddr) {
        min_vaddr = begin_vaddr;
     }
-    Elf32_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
+    Elf_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
     if (end_vaddr > max_vaddr) {
       max_vaddr = end_vaddr;
     }
@@ -1020,7 +1304,12 @@
   return loaded_size;
 }
 
-bool ElfFile::Load(bool executable, std::string* error_msg) {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Load(bool executable, std::string* error_msg) {
   CHECK(program_header_only_) << file_->GetPath();
 
   if (executable) {
@@ -1043,7 +1332,12 @@
         break;
       }
       case EM_MIPS: {
-        elf_ISA = kMips;
+        if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
+            (GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
+          elf_ISA = kMips;
+        } else if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
+          elf_ISA = kMips64;
+        }
         break;
       }
     }
@@ -1057,8 +1351,8 @@
   }
 
   bool reserved = false;
-  for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr* program_header = GetProgramHeader(i);
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* program_header = GetProgramHeader(i);
     if (program_header == nullptr) {
       *error_msg = StringPrintf("No program header for entry %d in ELF file %s.",
                                 i, file_->GetPath().c_str());
@@ -1094,12 +1388,16 @@
     }
     size_t file_length = static_cast<size_t>(temp_file_length);
     if (!reserved) {
-      byte* reserve_base = ((program_header->p_vaddr != 0) ?
-                            reinterpret_cast<byte*>(program_header->p_vaddr) : nullptr);
+      uint8_t* reserve_base = reinterpret_cast<uint8_t*>(program_header->p_vaddr);
+      uint8_t* reserve_base_override = reserve_base;
+      // Override the base (e.g. when compiling with --compile-pic)
+      if (requested_base_ != nullptr) {
+        reserve_base_override = requested_base_;
+      }
       std::string reservation_name("ElfFile reservation for ");
       reservation_name += file_->GetPath();
       std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
-                                                           reserve_base,
+                                                           reserve_base_override,
                                                            GetLoadedSize(), PROT_NONE, false,
                                                            error_msg));
       if (reserve.get() == nullptr) {
@@ -1108,16 +1406,22 @@
         return false;
       }
       reserved = true;
-      if (reserve_base == nullptr) {
-        base_address_ = reserve->Begin();
-      }
+
+      // Base address is the difference of actual mapped location and the p_vaddr
+      base_address_ = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(reserve->Begin())
+                       - reinterpret_cast<uintptr_t>(reserve_base));
+      // By adding the p_vaddr of a section/symbol to base_address_ we will always get the
+      // dynamic memory address of where that object is actually mapped
+      //
+      // TODO: base_address_ needs to be calculated in ::Open, otherwise
+      // FindDynamicSymbolAddress returns the wrong values until Load is called.
       segments_.push_back(reserve.release());
     }
     // empty segment, nothing to map
     if (program_header->p_memsz == 0) {
       continue;
     }
-    byte* p_vaddr = base_address_ + program_header->p_vaddr;
+    uint8_t* p_vaddr = base_address_ + program_header->p_vaddr;
     int prot = 0;
     if (executable && ((program_header->p_flags & PF_X) != 0)) {
       prot |= PROT_EXEC;
@@ -1137,8 +1441,8 @@
     }
     if (file_length < (program_header->p_offset + program_header->p_memsz)) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment "
-                                "%d of %d bytes: '%s'", file_length, i,
-                                program_header->p_offset + program_header->p_memsz,
+                                "%d of %" PRIu64 " bytes: '%s'", file_length, i,
+                                static_cast<uint64_t>(program_header->p_offset + program_header->p_memsz),
                                 file_->GetPath().c_str());
       return false;
     }
@@ -1164,17 +1468,17 @@
   }
 
   // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash
-  byte* dsptr = base_address_ + GetDynamicProgramHeader().p_vaddr;
+  uint8_t* dsptr = base_address_ + GetDynamicProgramHeader().p_vaddr;
   if ((dsptr < Begin() || dsptr >= End()) && !ValidPointer(dsptr)) {
     *error_msg = StringPrintf("dynamic section address invalid in ELF file %s",
                               file_->GetPath().c_str());
     return false;
   }
-  dynamic_section_start_ = reinterpret_cast<Elf32_Dyn*>(dsptr);
+  dynamic_section_start_ = reinterpret_cast<Elf_Dyn*>(dsptr);
 
-  for (Elf32_Word i = 0; i < GetDynamicNum(); i++) {
-    Elf32_Dyn& elf_dyn = GetDynamic(i);
-    byte* d_ptr = base_address_ + elf_dyn.d_un.d_ptr;
+  for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
+    Elf_Dyn& elf_dyn = GetDynamic(i);
+    uint8_t* d_ptr = base_address_ + elf_dyn.d_un.d_ptr;
     switch (elf_dyn.d_tag) {
       case DT_HASH: {
         if (!ValidPointer(d_ptr)) {
@@ -1182,7 +1486,7 @@
                                     d_ptr, file_->GetPath().c_str());
           return false;
         }
-        hash_section_start_ = reinterpret_cast<Elf32_Word*>(d_ptr);
+        hash_section_start_ = reinterpret_cast<Elf_Word*>(d_ptr);
         break;
       }
       case DT_STRTAB: {
@@ -1200,7 +1504,7 @@
                                     d_ptr, file_->GetPath().c_str());
           return false;
         }
-        dynsym_section_start_ = reinterpret_cast<Elf32_Sym*>(d_ptr);
+        dynsym_section_start_ = reinterpret_cast<Elf_Sym*>(d_ptr);
         break;
       }
       case DT_NULL: {
@@ -1228,7 +1532,12 @@
   return true;
 }
 
-bool ElfFile::ValidPointer(const byte* start) const {
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::ValidPointer(const uint8_t* start) const {
   for (size_t i = 0; i < segments_.size(); ++i) {
     const MemMap* segment = segments_[i];
     if (segment->Begin() <= start && start < segment->End()) {
@@ -1239,14 +1548,19 @@
 }
 
 
-Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const {
+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>
+Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FindSectionByName(const std::string& name) const {
   CHECK(!program_header_only_);
-  Elf32_Shdr* shstrtab_sec = GetSectionNameStringSection();
+  Elf_Shdr* shstrtab_sec = GetSectionNameStringSection();
   if (shstrtab_sec == nullptr) {
     return nullptr;
   }
   for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr* shdr = GetSectionHeader(i);
+    Elf_Shdr* shdr = GetSectionHeader(i);
     if (shdr == nullptr) {
       return nullptr;
     }
@@ -1273,7 +1587,7 @@
 };
 
 static FDE32* NextFDE(FDE32* frame) {
-  byte* fde_bytes = reinterpret_cast<byte*>(frame);
+  uint8_t* fde_bytes = reinterpret_cast<uint8_t*>(frame);
   fde_bytes += frame->GetLength();
   return reinterpret_cast<FDE32*>(fde_bytes);
 }
@@ -1295,7 +1609,7 @@
 };
 
 static FDE64* NextFDE(FDE64* frame) {
-  byte* fde_bytes = reinterpret_cast<byte*>(frame);
+  uint8_t* fde_bytes = reinterpret_cast<uint8_t*>(frame);
   fde_bytes += frame->GetLength();
   return reinterpret_cast<FDE64*>(fde_bytes);
 }
@@ -1305,7 +1619,7 @@
 }
 
 static bool FixupEHFrame(off_t base_address_delta,
-                           byte* eh_frame, size_t eh_frame_size) {
+                           uint8_t* eh_frame, size_t eh_frame_size) {
   if (*(reinterpret_cast<uint32_t*>(eh_frame)) == 0xffffffff) {
     FDE64* last_frame = reinterpret_cast<FDE64*>(eh_frame + eh_frame_size);
     FDE64* frame = NextFDE(reinterpret_cast<FDE64*>(eh_frame));
@@ -1384,7 +1698,7 @@
   }
 };
 
-class DebugLineInstructionIterator {
+class DebugLineInstructionIterator FINAL {
  public:
   static DebugLineInstructionIterator* Create(DebugLineHeader* header, size_t section_size) {
     std::unique_ptr<DebugLineInstructionIterator> line_iter(
@@ -1411,11 +1725,11 @@
     }
   }
 
-  uint8_t* GetInstruction() {
+  uint8_t* GetInstruction() const {
     return current_instruction_;
   }
 
-  bool IsExtendedOpcode() {
+  bool IsExtendedOpcode() const {
     return header_->IsExtendedOpcode(current_instruction_);
   }
 
@@ -1442,8 +1756,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_;
 };
 
@@ -1504,14 +1818,13 @@
   }
 }
 
-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.
-  static DebugTag* Create(const byte** data_pointer) {
-    const byte* data = *data_pointer;
+  static DebugTag* Create(const uint8_t** data_pointer) {
+    const uint8_t* data = *data_pointer;
     uint32_t index = DecodeUnsignedLeb128(&data);
     std::unique_ptr<DebugTag> tag(new DebugTag(index));
     tag->size_ = static_cast<uint32_t>(
@@ -1543,14 +1856,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.
@@ -1580,6 +1897,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_;
@@ -1590,7 +1909,7 @@
 class DebugAbbrev {
  public:
   ~DebugAbbrev() {}
-  static DebugAbbrev* Create(const byte* dbg_abbrev, size_t dbg_abbrev_size) {
+  static DebugAbbrev* Create(const uint8_t* dbg_abbrev, size_t dbg_abbrev_size) {
     std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev(dbg_abbrev, dbg_abbrev + dbg_abbrev_size));
     if (!abbrev->ReadAtOffset(0)) {
       return nullptr;
@@ -1601,20 +1920,20 @@
   bool ReadAtOffset(uint32_t abbrev_offset) {
     tags_.clear();
     tag_list_.clear();
-    const byte* dbg_abbrev = begin_ + abbrev_offset;
+    const uint8_t* dbg_abbrev = begin_ + abbrev_offset;
     while (dbg_abbrev < end_ && *dbg_abbrev != 0) {
       std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
       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));
       }
     }
     return true;
   }
 
-  DebugTag* ReadTag(const byte* entry) {
+  DebugTag* ReadTag(const uint8_t* entry) {
     uint32_t tag_num = DecodeUnsignedLeb128(&entry);
     auto it = tags_.find(tag_num);
     if (it == tags_.end()) {
@@ -1626,9 +1945,9 @@
   }
 
  private:
-  DebugAbbrev(const byte* begin, const byte* end) : begin_(begin), end_(end) {}
-  const byte* begin_;
-  const byte* end_;
+  DebugAbbrev(const uint8_t* begin, const uint8_t* end) : begin_(begin), end_(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_;
 };
@@ -1657,7 +1976,7 @@
     if (reinterpret_cast<DebugInfoHeader*>(current_entry_) >= next_cu_) {
       current_cu_ = next_cu_;
       next_cu_ = GetNextCu(current_cu_);
-      current_entry_ = reinterpret_cast<byte*>(current_cu_) + sizeof(DebugInfoHeader);
+      current_entry_ = reinterpret_cast<uint8_t*>(current_cu_) + sizeof(DebugInfoHeader);
       reread_abbrev = true;
     }
     if (current_entry_ >= last_entry_) {
@@ -1679,7 +1998,7 @@
   const DebugTag* GetCurrentTag() {
     return const_cast<DebugTag*>(current_tag_);
   }
-  byte* GetPointerToField(uint8_t dwarf_field) {
+  uint8_t* GetPointerToField(uint8_t dwarf_field) {
     if (current_tag_ == nullptr || current_entry_ == nullptr || current_entry_ >= last_entry_) {
       return nullptr;
     }
@@ -1695,7 +2014,7 @@
 
  private:
   static DebugInfoHeader* GetNextCu(DebugInfoHeader* hdr) {
-    byte* hdr_byte = reinterpret_cast<byte*>(hdr);
+    uint8_t* hdr_byte = reinterpret_cast<uint8_t*>(hdr);
     return reinterpret_cast<DebugInfoHeader*>(hdr_byte + sizeof(uint32_t) + hdr->unit_length);
   }
 
@@ -1703,14 +2022,14 @@
       : abbrev_(abbrev),
         current_cu_(header),
         next_cu_(GetNextCu(header)),
-        last_entry_(reinterpret_cast<byte*>(header) + frame_size),
-        current_entry_(reinterpret_cast<byte*>(header) + sizeof(DebugInfoHeader)),
+        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_;
-  byte* last_entry_;
-  byte* current_entry_;
+  uint8_t* const last_entry_;
+  uint8_t* current_entry_;
   DebugTag* current_tag_;
 };
 
@@ -1731,14 +2050,19 @@
   return true;
 }
 
-bool ElfFile::FixupDebugSections(off_t base_address_delta) {
-  const Elf32_Shdr* debug_info = FindSectionByName(".debug_info");
-  const Elf32_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
-  const Elf32_Shdr* eh_frame = FindSectionByName(".eh_frame");
-  const Elf32_Shdr* debug_str = FindSectionByName(".debug_str");
-  const Elf32_Shdr* debug_line = FindSectionByName(".debug_line");
-  const Elf32_Shdr* strtab_sec = FindSectionByName(".strtab");
-  const Elf32_Shdr* symtab_sec = FindSectionByName(".symtab");
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupDebugSections(off_t base_address_delta) {
+  const Elf_Shdr* debug_info = FindSectionByName(".debug_info");
+  const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
+  const Elf_Shdr* eh_frame = FindSectionByName(".eh_frame");
+  const Elf_Shdr* debug_str = FindSectionByName(".debug_str");
+  const Elf_Shdr* debug_line = FindSectionByName(".debug_line");
+  const Elf_Shdr* strtab_sec = FindSectionByName(".strtab");
+  const Elf_Shdr* symtab_sec = FindSectionByName(".symtab");
 
   if (debug_info == nullptr || debug_abbrev == nullptr ||
       debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
@@ -1781,7 +2105,12 @@
   return FixupDebugInfo(base_address_delta, info_iter.get());
 }
 
-void ElfFile::GdbJITSupport() {
+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>
+void ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::GdbJITSupport() {
   // We only get here if we only are mapping the program header.
   DCHECK(program_header_only_);
 
@@ -1789,15 +2118,18 @@
   std::string error_msg;
   // Make it MAP_PRIVATE so we can just give it to gdb if all the necessary
   // sections are there.
-  std::unique_ptr<ElfFile> all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
-                                        MAP_PRIVATE, &error_msg));
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+      Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>>
+      all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE, &error_msg));
   if (all_ptr.get() == nullptr) {
     return;
   }
-  ElfFile& all = *all_ptr;
+  ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+      Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>& all = *all_ptr;
 
   // We need the eh_frame for gdb but debug info might be present without it.
-  const Elf32_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
+  const Elf_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
   if (eh_frame == nullptr) {
     return;
   }
@@ -1806,7 +2138,7 @@
   // We need to add in a strtab and symtab to the image.
   // all is MAP_PRIVATE so it can be written to freely.
   // We also already have strtab and symtab so we are fine there.
-  Elf32_Ehdr& elf_hdr = all.GetHeader();
+  Elf_Ehdr& elf_hdr = all.GetHeader();
   elf_hdr.e_entry = 0;
   elf_hdr.e_phoff = 0;
   elf_hdr.e_phnum = 0;
@@ -1824,4 +2156,463 @@
   gdb_file_mapping_.reset(all_ptr.release());
 }
 
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Strip(std::string* error_msg) {
+  // ELF files produced by MCLinker look roughly like this
+  //
+  // +------------+
+  // | Elf_Ehdr   | contains number of Elf_Shdr and offset to first
+  // +------------+
+  // | Elf_Phdr   | program headers
+  // | Elf_Phdr   |
+  // | ...        |
+  // | Elf_Phdr   |
+  // +------------+
+  // | section    | mixture of needed and unneeded sections
+  // +------------+
+  // | section    |
+  // +------------+
+  // | ...        |
+  // +------------+
+  // | section    |
+  // +------------+
+  // | Elf_Shdr   | section headers
+  // | Elf_Shdr   |
+  // | ...        | contains offset to section start
+  // | Elf_Shdr   |
+  // +------------+
+  //
+  // To strip:
+  // - leave the Elf_Ehdr and Elf_Phdr values in place.
+  // - walk the sections making a new set of Elf_Shdr section headers for what we want to keep
+  // - move the sections are keeping up to fill in gaps of sections we want to strip
+  // - write new Elf_Shdr section headers to end of file, updating Elf_Ehdr
+  // - truncate rest of file
+  //
+
+  std::vector<Elf_Shdr> section_headers;
+  std::vector<Elf_Word> section_headers_original_indexes;
+  section_headers.reserve(GetSectionHeaderNum());
+
+
+  Elf_Shdr* string_section = GetSectionNameStringSection();
+  CHECK(string_section != nullptr);
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* sh = GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    const char* name = GetString(*string_section, sh->sh_name);
+    if (name == nullptr) {
+      CHECK_EQ(0U, i);
+      section_headers.push_back(*sh);
+      section_headers_original_indexes.push_back(0);
+      continue;
+    }
+    if (StartsWith(name, ".debug")
+        || (strcmp(name, ".strtab") == 0)
+        || (strcmp(name, ".symtab") == 0)) {
+      continue;
+    }
+    section_headers.push_back(*sh);
+    section_headers_original_indexes.push_back(i);
+  }
+  CHECK_NE(0U, section_headers.size());
+  CHECK_EQ(section_headers.size(), section_headers_original_indexes.size());
+
+  // section 0 is the NULL section, sections start at offset of first section
+  CHECK(GetSectionHeader(1) != nullptr);
+  Elf_Off offset = GetSectionHeader(1)->sh_offset;
+  for (size_t i = 1; i < section_headers.size(); i++) {
+    Elf_Shdr& new_sh = section_headers[i];
+    Elf_Shdr* old_sh = GetSectionHeader(section_headers_original_indexes[i]);
+    CHECK(old_sh != nullptr);
+    CHECK_EQ(new_sh.sh_name, old_sh->sh_name);
+    if (old_sh->sh_addralign > 1) {
+      offset = RoundUp(offset, old_sh->sh_addralign);
+    }
+    if (old_sh->sh_offset == offset) {
+      // already in place
+      offset += old_sh->sh_size;
+      continue;
+    }
+    // shift section earlier
+    memmove(Begin() + offset,
+            Begin() + old_sh->sh_offset,
+            old_sh->sh_size);
+    new_sh.sh_offset = offset;
+    offset += old_sh->sh_size;
+  }
+
+  Elf_Off shoff = offset;
+  size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf_Shdr);
+  memcpy(Begin() + offset, &section_headers[0], section_headers_size_in_bytes);
+  offset += section_headers_size_in_bytes;
+
+  GetHeader().e_shnum = section_headers.size();
+  GetHeader().e_shoff = shoff;
+  int result = ftruncate(file_->Fd(), offset);
+  if (result != 0) {
+    *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s",
+                              file_->GetPath().c_str(), strerror(errno));
+    return false;
+  }
+  return true;
+}
+
+static const bool DEBUG_FIXUP = false;
+
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::Fixup(uintptr_t base_address) {
+  if (!FixupDynamic(base_address)) {
+    LOG(WARNING) << "Failed to fixup .dynamic in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupSectionHeaders(base_address)) {
+    LOG(WARNING) << "Failed to fixup section headers in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupProgramHeaders(base_address)) {
+    LOG(WARNING) << "Failed to fixup program headers in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupSymbols(base_address, true)) {
+    LOG(WARNING) << "Failed to fixup .dynsym in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupSymbols(base_address, false)) {
+    LOG(WARNING) << "Failed to fixup .symtab in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupRelocations(base_address)) {
+    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file_->GetPath();
+    return false;
+  }
+  if (!FixupDebugSections(base_address)) {
+    LOG(WARNING) << "Failed to fixup debug sections in " << file_->GetPath();
+    return false;
+  }
+  return true;
+}
+
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupDynamic(uintptr_t base_address) {
+  for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
+    Elf_Dyn& elf_dyn = GetDynamic(i);
+    Elf_Word d_tag = elf_dyn.d_tag;
+    if (IsDynamicSectionPointer(d_tag, GetHeader().e_machine)) {
+      Elf_Addr d_ptr = elf_dyn.d_un.d_ptr;
+      if (DEBUG_FIXUP) {
+        LOG(INFO) << StringPrintf("In %s moving Elf_Dyn[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                  GetFile().GetPath().c_str(), i,
+                                  static_cast<uint64_t>(d_ptr),
+                                  static_cast<uint64_t>(d_ptr + base_address));
+      }
+      d_ptr += base_address;
+      elf_dyn.d_un.d_ptr = d_ptr;
+    }
+  }
+  return true;
+}
+
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupSectionHeaders(uintptr_t base_address) {
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* sh = GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    // 0 implies that the section will not exist in the memory of the process
+    if (sh->sh_addr == 0) {
+      continue;
+    }
+    if (DEBUG_FIXUP) {
+      LOG(INFO) << StringPrintf("In %s moving Elf_Shdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                GetFile().GetPath().c_str(), i,
+                                static_cast<uint64_t>(sh->sh_addr),
+                                static_cast<uint64_t>(sh->sh_addr + base_address));
+    }
+    sh->sh_addr += base_address;
+  }
+  return true;
+}
+
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupProgramHeaders(uintptr_t base_address) {
+  // TODO: ELFObjectFile doesn't have give to Elf_Phdr, so we do that ourselves for now.
+  for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+    Elf_Phdr* ph = GetProgramHeader(i);
+    CHECK(ph != nullptr);
+    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << GetFile().GetPath() << " i=" << i;
+    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
+            << GetFile().GetPath() << " i=" << i;
+    if (DEBUG_FIXUP) {
+      LOG(INFO) << StringPrintf("In %s moving Elf_Phdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                GetFile().GetPath().c_str(), i,
+                                static_cast<uint64_t>(ph->p_vaddr),
+                                static_cast<uint64_t>(ph->p_vaddr + base_address));
+    }
+    ph->p_vaddr += base_address;
+    ph->p_paddr += base_address;
+    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
+            << GetFile().GetPath() << " i=" << i;
+  }
+  return true;
+}
+
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupSymbols(uintptr_t base_address, bool dynamic) {
+  Elf_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
+  // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
+  Elf_Shdr* symbol_section = FindSectionByType(section_type);
+  if (symbol_section == nullptr) {
+    // file is missing optional .symtab
+    CHECK(!dynamic) << GetFile().GetPath();
+    return true;
+  }
+  for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
+    Elf_Sym* symbol = GetSymbol(section_type, i);
+    CHECK(symbol != nullptr);
+    if (symbol->st_value != 0) {
+      if (DEBUG_FIXUP) {
+        LOG(INFO) << StringPrintf("In %s moving Elf_Sym[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                  GetFile().GetPath().c_str(), i,
+                                  static_cast<uint64_t>(symbol->st_value),
+                                  static_cast<uint64_t>(symbol->st_value + base_address));
+      }
+      symbol->st_value += base_address;
+    }
+  }
+  return true;
+}
+
+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>
+bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+    Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
+    ::FixupRelocations(uintptr_t base_address) {
+  for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf_Shdr* sh = GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    if (sh->sh_type == SHT_REL) {
+      for (uint32_t j = 0; j < GetRelNum(*sh); j++) {
+        Elf_Rel& rel = GetRel(*sh, j);
+        if (DEBUG_FIXUP) {
+          LOG(INFO) << StringPrintf("In %s moving Elf_Rel[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                    GetFile().GetPath().c_str(), j,
+                                    static_cast<uint64_t>(rel.r_offset),
+                                    static_cast<uint64_t>(rel.r_offset + base_address));
+        }
+        rel.r_offset += base_address;
+      }
+    } else if (sh->sh_type == SHT_RELA) {
+      for (uint32_t j = 0; j < GetRelaNum(*sh); j++) {
+        Elf_Rela& rela = GetRela(*sh, j);
+        if (DEBUG_FIXUP) {
+          LOG(INFO) << StringPrintf("In %s moving Elf_Rela[%d] from 0x%" PRIx64 " to 0x%" PRIx64,
+                                    GetFile().GetPath().c_str(), j,
+                                    static_cast<uint64_t>(rela.r_offset),
+                                    static_cast<uint64_t>(rela.r_offset + base_address));
+        }
+        rela.r_offset += base_address;
+      }
+    }
+  }
+  return true;
+}
+
+// Explicit instantiations
+template class ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word,
+    Elf32_Sword, Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off>;
+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) : elf32_(elf32), elf64_(nullptr) {
+}
+
+ElfFile::ElfFile(ElfFileImpl64* elf64) : elf32_(nullptr), elf64_(elf64) {
+}
+
+ElfFile::~ElfFile() {
+  // 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,
+                       uint8_t* requested_base) {
+  if (file->GetLength() < EI_NIDENT) {
+    *error_msg = StringPrintf("File %s is too short to be a valid ELF file",
+                              file->GetPath().c_str());
+    return nullptr;
+  }
+  std::unique_ptr<MemMap> map(MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), 0,
+                                              file->GetPath().c_str(), error_msg));
+  if (map == nullptr && map->Size() != EI_NIDENT) {
+    return nullptr;
+  }
+  uint8_t* header = map->Begin();
+  if (header[EI_CLASS] == ELFCLASS64) {
+    ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only,
+                                                       error_msg, requested_base);
+    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, writable, program_header_only,
+                                                       error_msg, requested_base);
+    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",
+                              ELFCLASS32, ELFCLASS64,
+                              file->GetPath().c_str(),
+                              header[EI_CLASS]);
+    return nullptr;
+  }
+}
+
+ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg) {
+  if (file->GetLength() < EI_NIDENT) {
+    *error_msg = StringPrintf("File %s is too short to be a valid ELF file",
+                              file->GetPath().c_str());
+    return nullptr;
+  }
+  std::unique_ptr<MemMap> map(MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), 0,
+                                              file->GetPath().c_str(), error_msg));
+  if (map == nullptr && map->Size() != EI_NIDENT) {
+    return nullptr;
+  }
+  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) {
+      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) {
+      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",
+                              ELFCLASS32, ELFCLASS64,
+                              file->GetPath().c_str(),
+                              header[EI_CLASS]);
+    return nullptr;
+  }
+}
+
+#define DELEGATE_TO_IMPL(func, ...) \
+  if (elf64_.get() != nullptr) { \
+    return elf64_->func(__VA_ARGS__); \
+  } else { \
+    DCHECK(elf32_.get() != nullptr); \
+    return elf32_->func(__VA_ARGS__); \
+  }
+
+bool ElfFile::Load(bool executable, std::string* error_msg) {
+  DELEGATE_TO_IMPL(Load, executable, error_msg);
+}
+
+const uint8_t* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+  DELEGATE_TO_IMPL(FindDynamicSymbolAddress, symbol_name);
+}
+
+size_t ElfFile::Size() const {
+  DELEGATE_TO_IMPL(Size);
+}
+
+uint8_t* ElfFile::Begin() const {
+  DELEGATE_TO_IMPL(Begin);
+}
+
+uint8_t* ElfFile::End() const {
+  DELEGATE_TO_IMPL(End);
+}
+
+const File& ElfFile::GetFile() const {
+  DELEGATE_TO_IMPL(GetFile);
+}
+
+bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) {
+  if (elf32_.get() == nullptr) {
+    CHECK(elf64_.get() != nullptr);
+
+    Elf64_Shdr *shdr = elf64_->FindSectionByName(section_name);
+    if (shdr == nullptr) {
+      return false;
+    }
+    if (offset != nullptr) {
+      *offset = shdr->sh_offset;
+    }
+    if (size != nullptr) {
+      *size = shdr->sh_size;
+    }
+    return true;
+  } else {
+    Elf32_Shdr *shdr = elf32_->FindSectionByName(section_name);
+    if (shdr == nullptr) {
+      return false;
+    }
+    if (offset != nullptr) {
+      *offset = shdr->sh_offset;
+    }
+    if (size != nullptr) {
+      *size = shdr->sh_size;
+    }
+    return true;
+  }
+}
+
+uint64_t ElfFile::FindSymbolAddress(unsigned section_type,
+                                    const std::string& symbol_name,
+                                    bool build_map) {
+  DELEGATE_TO_IMPL(FindSymbolAddress, section_type, symbol_name, build_map);
+}
+
+size_t ElfFile::GetLoadedSize() const {
+  DELEGATE_TO_IMPL(GetLoadedSize);
+}
+
+bool ElfFile::Strip(File* file, std::string* error_msg) {
+  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg));
+  if (elf_file.get() == nullptr) {
+    return false;
+  }
+
+  if (elf_file->elf64_.get() != nullptr)
+    return elf_file->elf64_->Strip(error_msg);
+  else
+    return elf_file->elf32_->Strip(error_msg);
+}
+
+bool ElfFile::Fixup(uintptr_t base_address) {
+  DELEGATE_TO_IMPL(Fixup, base_address);
+}
+
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 916d693..41c54bc 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -17,191 +17,91 @@
 #ifndef ART_RUNTIME_ELF_FILE_H_
 #define ART_RUNTIME_ELF_FILE_H_
 
-#include <map>
 #include <memory>
-#include <vector>
+#include <string>
 
-#include "base/unix_file/fd_file.h"
-#include "globals.h"
-#include "elf_utils.h"
-#include "mem_map.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;
 
-// Interface to GDB JIT for backtrace information.
-extern "C" {
-  struct JITCodeEntry;
-}
-
+// 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
 // ELFObjectFile.
 class ElfFile {
  public:
-  static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg);
+  static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg,
+                       uint8_t* requested_base = nullptr);  // TODO: move arg to before error_msg.
   // Open with specific mmap flags, Always maps in the whole file, not just the
   // program header sections.
   static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
   ~ElfFile();
 
   // Load segments into memory based on PT_LOAD program headers
-
-  const File& GetFile() const {
-    return *file_;
-  }
-
-  byte* Begin() const {
-    return map_->Begin();
-  }
-
-  byte* End() const {
-    return map_->End();
-  }
-
-  size_t Size() const {
-    return map_->Size();
-  }
-
-  Elf32_Ehdr& GetHeader() const;
-
-  Elf32_Word GetProgramHeaderNum() const;
-  Elf32_Phdr* GetProgramHeader(Elf32_Word) const;
-
-  Elf32_Word GetSectionHeaderNum() const;
-  Elf32_Shdr* GetSectionHeader(Elf32_Word) const;
-  Elf32_Shdr* FindSectionByType(Elf32_Word type) const;
-  Elf32_Shdr* FindSectionByName(const std::string& name) const;
-
-  Elf32_Shdr* GetSectionNameStringSection() const;
-
-  // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
-  const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
-
-  Elf32_Word GetSymbolNum(Elf32_Shdr&) const;
-  Elf32_Sym* GetSymbol(Elf32_Word section_type, Elf32_Word i) const;
-
-  // Find address of symbol in specified table, returning 0 if it is
-  // not found. See FindSymbolByName for an explanation of build_map.
-  Elf32_Addr FindSymbolAddress(Elf32_Word section_type,
-                               const std::string& symbol_name,
-                               bool build_map);
-
-  // Lookup a string given string section and offset. Returns nullptr for
-  // special 0 offset.
-  const char* GetString(Elf32_Shdr&, Elf32_Word) const;
-
-  Elf32_Word GetDynamicNum() const;
-  Elf32_Dyn& GetDynamic(Elf32_Word) const;
-
-  Elf32_Word GetRelNum(Elf32_Shdr&) const;
-  Elf32_Rel& GetRel(Elf32_Shdr&, Elf32_Word) const;
-
-  Elf32_Word GetRelaNum(Elf32_Shdr&) const;
-  Elf32_Rela& GetRela(Elf32_Shdr&, Elf32_Word) const;
-
-  // Returns the expected size when the file is loaded at runtime
-  size_t GetLoadedSize() const;
-
-  // Load segments into memory based on PT_LOAD program headers.
-  // executable is true at run time, false at compile time.
   bool Load(bool executable, std::string* error_msg);
 
-  bool FixupDebugSections(off_t base_address_delta);
+  const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name) const;
+
+  size_t Size() const;
+
+  // The start of the memory map address range for this ELF file.
+  uint8_t* Begin() const;
+
+  // The end of the memory map address range for this ELF file.
+  uint8_t* End() const;
+
+  const File& GetFile() const;
+
+  bool GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size);
+
+  uint64_t FindSymbolAddress(unsigned section_type,
+                             const std::string& symbol_name,
+                             bool build_map);
+
+  size_t GetLoadedSize() const;
+
+  // Strip an ELF file of unneeded debugging information.
+  // Returns true on success, false on failure.
+  static bool Strip(File* file, std::string* error_msg);
+
+  // Fixup an ELF file so that that oat header will be loaded at oat_begin.
+  // Returns true on success, false on failure.
+  static bool Fixup(File* file, uintptr_t oat_data_begin);
+
+  bool Fixup(uintptr_t base_address);
+
+  bool Is64Bit() const {
+    return elf64_.get() != nullptr;
+  }
+
+  ElfFileImpl32* GetImpl32() const {
+    return elf32_.get();
+  }
+
+  ElfFileImpl64* GetImpl64() const {
+    return elf64_.get();
+  }
 
  private:
-  ElfFile(File* file, bool writable, bool program_header_only);
+  explicit ElfFile(ElfFileImpl32* elf32);
+  explicit ElfFile(ElfFileImpl64* elf64);
 
-  bool Setup(int prot, int flags, std::string* error_msg);
+  const std::unique_ptr<ElfFileImpl32> elf32_;
+  const std::unique_ptr<ElfFileImpl64> elf64_;
 
-  bool SetMap(MemMap* map, std::string* error_msg);
-
-  byte* GetProgramHeadersStart() const;
-  byte* GetSectionHeadersStart() const;
-  Elf32_Phdr& GetDynamicProgramHeader() const;
-  Elf32_Dyn* GetDynamicSectionStart() const;
-  Elf32_Sym* GetSymbolSectionStart(Elf32_Word section_type) const;
-  const char* GetStringSectionStart(Elf32_Word section_type) const;
-  Elf32_Rel* GetRelSectionStart(Elf32_Shdr&) const;
-  Elf32_Rela* GetRelaSectionStart(Elf32_Shdr&) const;
-  Elf32_Word* GetHashSectionStart() const;
-  Elf32_Word GetHashBucketNum() const;
-  Elf32_Word GetHashChainNum() const;
-  Elf32_Word GetHashBucket(size_t i, bool* ok) const;
-  Elf32_Word GetHashChain(size_t i, bool* ok) const;
-
-  typedef std::map<std::string, Elf32_Sym*> SymbolTable;
-  SymbolTable** GetSymbolTable(Elf32_Word section_type);
-
-  bool ValidPointer(const byte* start) const;
-
-  const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
-
-  // Check that certain sections and their dependencies exist.
-  bool CheckSectionsExist(std::string* error_msg) const;
-
-  // Check that the link of the first section links to the second section.
-  bool CheckSectionsLinked(const byte* source, const byte* target) const;
-
-  // Check whether the offset is in range, and set to target to Begin() + offset if OK.
-  bool CheckAndSet(Elf32_Off offset, const char* label, byte** target, std::string* error_msg);
-
-  // Find symbol in specified table, returning nullptr if it is not found.
-  //
-  // If build_map is true, builds a map to speed repeated access. The
-  // map does not included untyped symbol values (aka STT_NOTYPE)
-  // since they can contain duplicates. If build_map is false, the map
-  // will be used if it was already created. Typically build_map
-  // should be set unless only a small number of symbols will be
-  // looked up.
-  Elf32_Sym* FindSymbolByName(Elf32_Word section_type,
-                              const std::string& symbol_name,
-                              bool build_map);
-
-  Elf32_Phdr* FindProgamHeaderByType(Elf32_Word type) const;
-
-  Elf32_Dyn* FindDynamicByType(Elf32_Sword type) const;
-  Elf32_Word FindDynamicValueByType(Elf32_Sword type) const;
-
-  // Lookup a string by section type. Returns nullptr for special 0 offset.
-  const char* GetString(Elf32_Word section_type, Elf32_Word) const;
-
-  const File* const file_;
-  const bool writable_;
-  const bool program_header_only_;
-
-  // ELF header mapping. If program_header_only_ is false, will
-  // actually point to the entire elf file.
-  std::unique_ptr<MemMap> map_;
-  Elf32_Ehdr* header_;
-  std::vector<MemMap*> segments_;
-
-  // Pointer to start of first PT_LOAD program segment after Load()
-  // when program_header_only_ is true.
-  byte* base_address_;
-
-  // The program header should always available but use GetProgramHeadersStart() to be sure.
-  byte* program_headers_start_;
-
-  // Conditionally available values. Use accessors to ensure they exist if they are required.
-  byte* section_headers_start_;
-  Elf32_Phdr* dynamic_program_header_;
-  Elf32_Dyn* dynamic_section_start_;
-  Elf32_Sym* symtab_section_start_;
-  Elf32_Sym* dynsym_section_start_;
-  char* strtab_section_start_;
-  char* dynstr_section_start_;
-  Elf32_Word* hash_section_start_;
-
-  SymbolTable* symtab_symbol_table_;
-  SymbolTable* dynsym_symbol_table_;
-
-  // Support for GDB JIT
-  byte* jit_elf_image_;
-  JITCodeEntry* jit_gdb_entry_;
-  std::unique_ptr<ElfFile> gdb_file_mapping_;
-  void GdbJITSupport();
+  DISALLOW_COPY_AND_ASSIGN(ElfFile);
 };
 
 }  // namespace art
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
new file mode 100644
index 0000000..a70fa17
--- /dev/null
+++ b/runtime/elf_file_impl.h
@@ -0,0 +1,218 @@
+/*
+ * 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_ELF_FILE_IMPL_H_
+#define ART_RUNTIME_ELF_FILE_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+// Explicitly include our own elf.h to avoid Linux and other dependencies.
+#include "./elf.h"
+#include "mem_map.h"
+
+namespace art {
+
+extern "C" {
+  struct JITCodeEntry;
+}
+
+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 {
+ public:
+  static ElfFileImpl* Open(File* file, bool writable, bool program_header_only,
+                           std::string* error_msg, uint8_t* requested_base = nullptr);
+  static ElfFileImpl* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
+  ~ElfFileImpl();
+
+  const File& GetFile() const {
+    return *file_;
+  }
+
+  uint8_t* Begin() const {
+    return map_->Begin();
+  }
+
+  uint8_t* End() const {
+    return map_->End();
+  }
+
+  size_t Size() const {
+    return map_->Size();
+  }
+
+  Elf_Ehdr& GetHeader() const;
+
+  Elf_Word GetProgramHeaderNum() const;
+  Elf_Phdr* GetProgramHeader(Elf_Word) const;
+
+  Elf_Word GetSectionHeaderNum() const;
+  Elf_Shdr* GetSectionHeader(Elf_Word) const;
+  Elf_Shdr* FindSectionByType(Elf_Word type) const;
+  Elf_Shdr* FindSectionByName(const std::string& name) const;
+
+  Elf_Shdr* GetSectionNameStringSection() const;
+
+  // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
+  const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name) const;
+
+  static bool IsSymbolSectionType(Elf_Word section_type);
+  Elf_Word GetSymbolNum(Elf_Shdr&) const;
+  Elf_Sym* GetSymbol(Elf_Word section_type, Elf_Word i) const;
+
+  // Find address of symbol in specified table, returning 0 if it is
+  // not found. See FindSymbolByName for an explanation of build_map.
+  Elf_Addr FindSymbolAddress(Elf_Word section_type,
+                             const std::string& symbol_name,
+                             bool build_map);
+
+  // Lookup a string given string section and offset. Returns nullptr for
+  // special 0 offset.
+  const char* GetString(Elf_Shdr&, Elf_Word) const;
+
+  Elf_Word GetDynamicNum() const;
+  Elf_Dyn& GetDynamic(Elf_Word) const;
+
+  Elf_Word GetRelNum(Elf_Shdr&) const;
+  Elf_Rel& GetRel(Elf_Shdr&, Elf_Word) const;
+
+  Elf_Word GetRelaNum(Elf_Shdr&) const;
+  Elf_Rela& GetRela(Elf_Shdr&, Elf_Word) const;
+
+  // Returns the expected size when the file is loaded at runtime
+  size_t GetLoadedSize() const;
+
+  // Load segments into memory based on PT_LOAD program headers.
+  // executable is true at run time, false at compile time.
+  bool Load(bool executable, std::string* error_msg);
+
+  bool Fixup(uintptr_t base_address);
+  bool FixupDynamic(uintptr_t base_address);
+  bool FixupSectionHeaders(uintptr_t base_address);
+  bool FixupProgramHeaders(uintptr_t base_address);
+  bool FixupSymbols(uintptr_t base_address, bool dynamic);
+  bool FixupRelocations(uintptr_t base_address);
+  bool FixupDebugSections(off_t base_address_delta);
+
+  bool Strip(std::string* error_msg);
+
+ private:
+  ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base);
+
+  bool Setup(int prot, int flags, std::string* error_msg);
+
+  bool SetMap(MemMap* map, std::string* error_msg);
+
+  uint8_t* GetProgramHeadersStart() const;
+  uint8_t* GetSectionHeadersStart() const;
+  Elf_Phdr& GetDynamicProgramHeader() const;
+  Elf_Dyn* GetDynamicSectionStart() const;
+  Elf_Sym* GetSymbolSectionStart(Elf_Word section_type) const;
+  const char* GetStringSectionStart(Elf_Word section_type) const;
+  Elf_Rel* GetRelSectionStart(Elf_Shdr&) const;
+  Elf_Rela* GetRelaSectionStart(Elf_Shdr&) const;
+  Elf_Word* GetHashSectionStart() const;
+  Elf_Word GetHashBucketNum() const;
+  Elf_Word GetHashChainNum() const;
+  Elf_Word GetHashBucket(size_t i, bool* ok) const;
+  Elf_Word GetHashChain(size_t i, bool* ok) const;
+
+  typedef std::map<std::string, Elf_Sym*> SymbolTable;
+  SymbolTable** GetSymbolTable(Elf_Word section_type);
+
+  bool ValidPointer(const uint8_t* start) const;
+
+  const Elf_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
+
+  // Check that certain sections and their dependencies exist.
+  bool CheckSectionsExist(std::string* error_msg) const;
+
+  // Check that the link of the first section links to the second section.
+  bool CheckSectionsLinked(const uint8_t* source, const uint8_t* target) const;
+
+  // Check whether the offset is in range, and set to target to Begin() + offset if OK.
+  bool CheckAndSet(Elf32_Off offset, const char* label, uint8_t** target, std::string* error_msg);
+
+  // Find symbol in specified table, returning nullptr if it is not found.
+  //
+  // If build_map is true, builds a map to speed repeated access. The
+  // map does not included untyped symbol values (aka STT_NOTYPE)
+  // since they can contain duplicates. If build_map is false, the map
+  // will be used if it was already created. Typically build_map
+  // should be set unless only a small number of symbols will be
+  // looked up.
+  Elf_Sym* FindSymbolByName(Elf_Word section_type,
+                            const std::string& symbol_name,
+                            bool build_map);
+
+  Elf_Phdr* FindProgamHeaderByType(Elf_Word type) const;
+
+  Elf_Dyn* FindDynamicByType(Elf_Sword type) const;
+  Elf_Word FindDynamicValueByType(Elf_Sword type) const;
+
+  // Lookup a string by section type. Returns nullptr for special 0 offset.
+  const char* GetString(Elf_Word section_type, Elf_Word) const;
+
+  const File* const file_;
+  const bool writable_;
+  const bool program_header_only_;
+
+  // ELF header mapping. If program_header_only_ is false, will
+  // actually point to the entire elf file.
+  std::unique_ptr<MemMap> map_;
+  Elf_Ehdr* header_;
+  std::vector<MemMap*> segments_;
+
+  // Pointer to start of first PT_LOAD program segment after Load()
+  // when program_header_only_ is true.
+  uint8_t* base_address_;
+
+  // The program header should always available but use GetProgramHeadersStart() to be sure.
+  uint8_t* program_headers_start_;
+
+  // Conditionally available values. Use accessors to ensure they exist if they are required.
+  uint8_t* section_headers_start_;
+  Elf_Phdr* dynamic_program_header_;
+  Elf_Dyn* dynamic_section_start_;
+  Elf_Sym* symtab_section_start_;
+  Elf_Sym* dynsym_section_start_;
+  char* strtab_section_start_;
+  char* dynstr_section_start_;
+  Elf_Word* hash_section_start_;
+
+  SymbolTable* symtab_symbol_table_;
+  SymbolTable* dynsym_symbol_table_;
+
+  // Support for GDB JIT
+  uint8_t* jit_elf_image_;
+  JITCodeEntry* jit_gdb_entry_;
+  std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
+                  Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel,
+                  Elf_Rela, Elf_Dyn, Elf_Off>> gdb_file_mapping_;
+  void GdbJITSupport();
+
+  // Override the 'base' p_vaddr in the first LOAD segment with this value (if non-null).
+  uint8_t* requested_base_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElfFileImpl);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ELF_FILE_IMPL_H_
diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h
index 5966d05..418d937 100644
--- a/runtime/elf_utils.h
+++ b/runtime/elf_utils.h
@@ -24,10 +24,14 @@
 
 #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
 #define EF_MIPS_ARCH_32R2 0x70000000
+#define EF_MIPS_ARCH_32R6 0x90000000
+#define EF_MIPS_ARCH_64R6 0xa0000000
 
 #define EI_ABIVERSION 8
 #define EM_ARM 40
@@ -67,11 +71,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 +167,6 @@
   }
 }
 
+}  // namespace art
+
 #endif  // ART_RUNTIME_ELF_UTILS_H_
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 9fb9a3b..35579d6 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -35,12 +35,11 @@
 
 namespace art {
 
-// TODO: Fix no thread safety analysis when GCC can handle template specialization.
 template <const bool kAccessCheck>
 ALWAYS_INLINE
-static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
-                                              mirror::ArtMethod* method,
-                                              Thread* self, bool* slow_path) {
+inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+                                       mirror::ArtMethod* method,
+                                       Thread* self, bool* slow_path) {
   mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx);
   if (UNLIKELY(klass == NULL)) {
     klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
@@ -90,11 +89,10 @@
   return klass;
 }
 
-// TODO: Fix no thread safety analysis when annotalysis is smarter.
 ALWAYS_INLINE
-static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
-                                                                 Thread* self,
-                                                                 bool* slow_path) {
+inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
+                                                          Thread* self,
+                                                          bool* slow_path) {
   if (UNLIKELY(!klass->IsInitialized())) {
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> h_class(hs.NewHandle(klass));
@@ -120,13 +118,12 @@
 // cannot be resolved, throw an error. If it can, use it to create an instance.
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
-// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE
-static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
-                                                  mirror::ArtMethod* method,
-                                                  Thread* self,
-                                                  gc::AllocatorType allocator_type) {
+inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+                                           mirror::ArtMethod* method,
+                                           Thread* self,
+                                           gc::AllocatorType allocator_type) {
   bool slow_path = false;
   mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path);
   if (UNLIKELY(slow_path)) {
@@ -140,13 +137,11 @@
 }
 
 // Given the context of a calling Method and a resolved class, create an instance.
-// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
 template <bool kInstrumented>
 ALWAYS_INLINE
-static inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
-                                                          mirror::ArtMethod* method,
-                                                          Thread* self,
-                                                          gc::AllocatorType allocator_type) {
+inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
+                                                   Thread* self,
+                                                   gc::AllocatorType allocator_type) {
   DCHECK(klass != nullptr);
   bool slow_path = false;
   klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path);
@@ -163,26 +158,23 @@
 }
 
 // Given the context of a calling Method and an initialized class, create an instance.
-// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
 template <bool kInstrumented>
 ALWAYS_INLINE
-static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
-                                                             mirror::ArtMethod* method,
-                                                             Thread* self,
-                                                             gc::AllocatorType allocator_type) {
+inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
+                                                      Thread* self,
+                                                      gc::AllocatorType allocator_type) {
   DCHECK(klass != nullptr);
   // Pass in false since the object can not be finalizable.
   return klass->Alloc<kInstrumented, false>(self, allocator_type);
 }
 
 
-// TODO: Fix no thread safety analysis when GCC can handle template specialization.
 template <bool kAccessCheck>
 ALWAYS_INLINE
-static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
-                                             mirror::ArtMethod* method,
-                                             int32_t component_count,
-                                             bool* slow_path) {
+inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+                                      int32_t component_count,
+                                      mirror::ArtMethod* method,
+                                      bool* slow_path) {
   if (UNLIKELY(component_count < 0)) {
     ThrowNegativeArraySizeException(component_count);
     *slow_path = true;
@@ -213,16 +205,15 @@
 // it cannot be resolved, throw an error. If it can, use it to create an array.
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
-// TODO: Fix no thread safety analysis when GCC can handle template specialization.
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE
-static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
-                                                mirror::ArtMethod* method,
-                                                int32_t component_count,
-                                                Thread* self,
-                                                gc::AllocatorType allocator_type) {
+inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+                                         int32_t component_count,
+                                         mirror::ArtMethod* method,
+                                         Thread* self,
+                                         gc::AllocatorType allocator_type) {
   bool slow_path = false;
-  mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, method, component_count,
+  mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method,
                                                        &slow_path);
   if (UNLIKELY(slow_path)) {
     if (klass == nullptr) {
@@ -239,11 +230,11 @@
 
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE
-static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
-                                                        mirror::ArtMethod* method,
-                                                        int32_t component_count,
-                                                        Thread* self,
-                                                        gc::AllocatorType allocator_type) {
+inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
+                                                 int32_t component_count,
+                                                 mirror::ArtMethod* method,
+                                                 Thread* self,
+                                                 gc::AllocatorType allocator_type) {
   DCHECK(klass != nullptr);
   if (UNLIKELY(component_count < 0)) {
     ThrowNegativeArraySizeException(component_count);
@@ -263,8 +254,8 @@
 }
 
 template<FindFieldType type, bool access_check>
-static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
-                                                  Thread* self, size_t expected_size) {
+inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
+                                           Thread* self, size_t expected_size) {
   bool is_primitive;
   bool is_set;
   bool is_static;
@@ -358,11 +349,11 @@
 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
 
 template<InvokeType type, bool access_check>
-static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
-                                                    mirror::Object** this_object,
-                                                    mirror::ArtMethod** referrer, Thread* self) {
+inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
+                                             mirror::Object** this_object,
+                                             mirror::ArtMethod** referrer, Thread* self) {
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type);
+  mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer);
   if (resolved_method == nullptr) {
     StackHandleScope<1> hs(self);
     mirror::Object* null_this = nullptr;
@@ -437,7 +428,14 @@
     case kInterface: {
       uint32_t imt_index = resolved_method->GetDexMethodIndex() % mirror::Class::kImtSize;
       mirror::ArtMethod* imt_method = (*this_object)->GetClass()->GetEmbeddedImTableEntry(imt_index);
-      if (!imt_method->IsImtConflictMethod()) {
+      if (!imt_method->IsImtConflictMethod() && !imt_method->IsImtUnimplementedMethod()) {
+        if (kIsDebugBuild) {
+          mirror::Class* klass = (*this_object)->GetClass();
+          mirror::ArtMethod* method = klass->FindVirtualMethodForInterface(resolved_method);
+          CHECK_EQ(imt_method, method) << PrettyMethod(resolved_method) << " / " <<
+              PrettyMethod(imt_method) << " / " << PrettyMethod(method) << " / " <<
+              PrettyClass(klass);
+        }
         return imt_method;
       } else {
         mirror::ArtMethod* interface_method =
@@ -477,9 +475,9 @@
 #undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
 
 // Fast path field resolution that can't initialize classes or throw exceptions.
-static inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
-                                              mirror::ArtMethod* referrer,
-                                              FindFieldType type, size_t expected_size) {
+inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
+                                       mirror::ArtMethod* referrer,
+                                       FindFieldType type, size_t expected_size) {
   mirror::ArtField* resolved_field =
       referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
   if (UNLIKELY(resolved_field == nullptr)) {
@@ -499,11 +497,8 @@
     case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
     case StaticPrimitiveWrite:   is_primitive = true;  is_set = true;  is_static = true;  break;
     default:
-      LOG(FATAL) << "UNREACHABLE";  // Assignment below to avoid GCC warnings.
-      is_primitive = true;
-      is_set = true;
-      is_static = true;
-      break;
+      LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
   }
   if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
     // Incompatible class change.
@@ -533,12 +528,11 @@
 }
 
 // Fast path method resolution that can't throw exceptions.
-static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
-                                                mirror::Object* this_object,
-                                                mirror::ArtMethod* referrer,
-                                                bool access_check, InvokeType type) {
-  bool is_direct = type == kStatic || type == kDirect;
-  if (UNLIKELY(this_object == NULL && !is_direct)) {
+inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
+                                         mirror::Object* this_object,
+                                         mirror::ArtMethod* referrer,
+                                         bool access_check, InvokeType type) {
+  if (UNLIKELY(this_object == NULL && type != kStatic)) {
     return NULL;
   }
   mirror::ArtMethod* resolved_method =
@@ -563,7 +557,7 @@
   }
   if (type == kInterface) {  // Most common form of slow path dispatch.
     return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
-  } else if (is_direct) {
+  } else if (type == kStatic || type == kDirect) {
     return resolved_method;
   } else if (type == kSuper) {
     return referrer->GetDeclaringClass()->GetSuperClass()
@@ -574,7 +568,7 @@
   }
 }
 
-static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
                                                     mirror::ArtMethod* referrer,
                                                     Thread* self, bool can_run_clinit,
                                                     bool verify_access) {
@@ -610,13 +604,13 @@
   return h_class.Get();
 }
 
-static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer,
-                                                    uint32_t string_idx) {
+inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer,
+                                             uint32_t string_idx) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   return class_linker->ResolveString(string_idx, referrer);
 }
 
-static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
+inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
   // Save any pending exception over monitor exit call.
   mirror::Throwable* saved_exception = NULL;
   ThrowLocation saved_throw_location;
@@ -641,7 +635,7 @@
 }
 
 template <typename INT_TYPE, typename FLOAT_TYPE>
-static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
+inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
   const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max());
   const INT_TYPE kMinInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::min());
   const FLOAT_TYPE kMaxIntAsFloat = static_cast<FLOAT_TYPE>(kMaxInt);
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 835d6e2..db51264 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -20,7 +20,6 @@
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "gc/accounting/card_table-inl.h"
-#include "method_helper-inl.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -34,8 +33,8 @@
 namespace art {
 
 static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx,
-                                                      mirror::ArtMethod* referrer,
                                                       int32_t component_count,
+                                                      mirror::ArtMethod* referrer,
                                                       Thread* self,
                                                       bool access_check)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -77,11 +76,11 @@
 }
 
 // Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* referrer,
-                                          int32_t component_count, Thread* self,
+mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
+                                          mirror::ArtMethod* referrer, Thread* self,
                                           bool access_check,
                                           gc::AllocatorType /* allocator_type */) {
-  mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, referrer, component_count, self,
+  mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
                                                   access_check);
   if (UNLIKELY(klass == nullptr)) {
     return nullptr;
@@ -97,12 +96,12 @@
 
 // Helper function to allocate array for FILLED_NEW_ARRAY.
 mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
-                                                      mirror::ArtMethod* referrer,
                                                       int32_t component_count,
+                                                      mirror::ArtMethod* referrer,
                                                       Thread* self,
                                                       bool access_check,
                                                       gc::AllocatorType /* allocator_type */) {
-  mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, referrer, component_count, self,
+  mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
                                                   access_check);
   if (UNLIKELY(klass == nullptr)) {
     return nullptr;
@@ -184,14 +183,12 @@
         env->SetObjectField(exc.get(),
                             WellKnownClasses::java_lang_Throwable_stackTrace,
                             stack_trace_elem.get());
-
-        // Throw the exception.
-        ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-        self->SetException(throw_location,
-            reinterpret_cast<mirror::Throwable*>(self->DecodeJObject(exc.get())));
       } else {
         error_msg = "Could not create stack trace.";
       }
+      // Throw the exception.
+      self->SetException(self->GetCurrentLocationForThrow(),
+                         reinterpret_cast<mirror::Throwable*>(self->DecodeJObject(exc.get())));
     } else {
       // Could not allocate a string object.
       error_msg = "Couldn't throw new StackOverflowError because JNI NewStringUTF failed.";
@@ -218,17 +215,14 @@
   if (o == nullptr) {
     return;
   }
-  mirror::ArtMethod* m = self->GetCurrentMethod(nullptr);
   // Make sure that the result is an instance of the type this method was expected to return.
-  StackHandleScope<1> hs(self);
-  Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
-  mirror::Class* return_type = MethodHelper(h_m).GetReturnType();
+  mirror::Class* return_type = self->GetCurrentMethod(nullptr)->GetReturnType();
 
   if (!o->InstanceOf(return_type)) {
     Runtime::Current()->GetJavaVM()->JniAbortF(nullptr,
                                                "attempt to return an instance of %s from %s",
                                                PrettyTypeOf(o).c_str(),
-                                               PrettyMethod(h_m.Get()).c_str());
+                                               PrettyMethod(self->GetCurrentMethod(nullptr)).c_str());
   }
 }
 
@@ -283,20 +277,19 @@
       return zero;
     } else {
       StackHandleScope<1> hs(soa.Self());
-      MethodHelper mh_interface_method(
+      Handle<mirror::ArtMethod> h_interface_method(
           hs.NewHandle(soa.Decode<mirror::ArtMethod*>(interface_method_jobj)));
       // This can cause thread suspension.
-      mirror::Class* result_type = mh_interface_method.GetReturnType();
+      mirror::Class* result_type = h_interface_method->GetReturnType();
       mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
       mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
       mirror::ArtMethod* proxy_method;
-      if (mh_interface_method.GetMethod()->GetDeclaringClass()->IsInterface()) {
-        proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
-            mh_interface_method.GetMethod());
+      if (h_interface_method->GetDeclaringClass()->IsInterface()) {
+        proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(h_interface_method.Get());
       } else {
         // Proxy dispatch to a method defined in Object.
-        DCHECK(mh_interface_method.GetMethod()->GetDeclaringClass()->IsObjectClass());
-        proxy_method = mh_interface_method.GetMethod();
+        DCHECK(h_interface_method->GetDeclaringClass()->IsObjectClass());
+        proxy_method = h_interface_method.Get();
       }
       ThrowLocation throw_location(rcvr, proxy_method, -1);
       JValue result_unboxed;
@@ -344,4 +337,28 @@
     return zero;
   }
 }
+
+bool FillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload) {
+  DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
+  if (UNLIKELY(obj == nullptr)) {
+    ThrowNullPointerException(nullptr, "null array in FILL_ARRAY_DATA");
+    return false;
+  }
+  mirror::Array* array = obj->AsArray();
+  DCHECK(!array->IsObjectArray());
+  if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
+    Thread* self = Thread::Current();
+    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+    self->ThrowNewExceptionF(throw_location,
+                             "Ljava/lang/ArrayIndexOutOfBoundsException;",
+                             "failed FILL_ARRAY_DATA; length=%d, index=%d",
+                             array->GetLength(), payload->element_count);
+    return false;
+  }
+  // Copy data from dex file to memory assuming both are little endian.
+  uint32_t size_in_bytes = payload->element_count * payload->element_width;
+  memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
+  return true;
+}
+
 }  // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 08edecf..77eec46 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -22,6 +22,7 @@
 
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "dex_instruction.h"
 #include "gc/allocator_type.h"
 #include "invoke_type.h"
 #include "jvalue.h"
@@ -41,14 +42,14 @@
 class Thread;
 
 template <const bool kAccessCheck>
-ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
-                                                            mirror::ArtMethod* method,
-                                                            Thread* self, bool* slow_path)
+ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+                                                     mirror::ArtMethod* method,
+                                                     Thread* self, bool* slow_path)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-// TODO: Fix no thread safety analysis when annotalysis is smarter.
-ALWAYS_INLINE static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
-                                                                               Thread* self, bool* slow_path)
+ALWAYS_INLINE inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
+                                                                        Thread* self,
+                                                                        bool* slow_path)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
@@ -56,34 +57,32 @@
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
 template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
-                                                                mirror::ArtMethod* method,
-                                                                Thread* self,
-                                                                gc::AllocatorType allocator_type)
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+                                                         mirror::ArtMethod* method,
+                                                         Thread* self,
+                                                         gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Given the context of a calling Method and a resolved class, create an instance.
 template <bool kInstrumented>
-ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
-                                                                        mirror::ArtMethod* method,
-                                                                        Thread* self,
-                                                                        gc::AllocatorType allocator_type)
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
+                                                                 Thread* self,
+                                                                 gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Given the context of a calling Method and an initialized class, create an instance.
 template <bool kInstrumented>
-ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
-                                                                           mirror::ArtMethod* method,
-                                                                           Thread* self,
-                                                                           gc::AllocatorType allocator_type)
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
+                                                                    Thread* self,
+                                                                    gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
 template <bool kAccessCheck>
-ALWAYS_INLINE static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
-                                                           mirror::ArtMethod* method,
-                                                           int32_t component_count,
-                                                           bool* slow_path)
+ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+                                                    int32_t component_count,
+                                                    mirror::ArtMethod* method,
+                                                    bool* slow_path)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
@@ -91,30 +90,31 @@
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
 template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
-                                                              mirror::ArtMethod* method,
-                                                              int32_t component_count,
-                                                              Thread* self,
-                                                              gc::AllocatorType allocator_type)
+ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+                                                       int32_t component_count,
+                                                       mirror::ArtMethod* method,
+                                                       Thread* self,
+                                                       gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
-                                                                      mirror::ArtMethod* method,
-                                                                      int32_t component_count,
-                                                                      Thread* self,
-                                                                      gc::AllocatorType allocator_type)
+ALWAYS_INLINE inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
+                                                               int32_t component_count,
+                                                               mirror::ArtMethod* method,
+                                                               Thread* self,
+                                                               gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* method,
-                                                 int32_t component_count, Thread* self,
+extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
+                                                 mirror::ArtMethod* method, Thread* self,
                                                  bool access_check,
                                                  gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 extern mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
+                                                             int32_t component_count,
                                                              mirror::ArtMethod* method,
-                                                             int32_t component_count, Thread* self,
+                                                             Thread* self,
                                                              bool access_check,
                                                              gc::AllocatorType allocator_type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -132,43 +132,42 @@
 };
 
 template<FindFieldType type, bool access_check>
-static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
-                                                  Thread* self, size_t expected_size)
+inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
+                                           Thread* self, size_t expected_size)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 template<InvokeType type, bool access_check>
-static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
-                                                    mirror::Object** this_object,
-                                                    mirror::ArtMethod** referrer, Thread* self)
+inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
+                                             mirror::Object** this_object,
+                                             mirror::ArtMethod** referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path field resolution that can't initialize classes or throw exceptions.
-static inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
-                                              mirror::ArtMethod* referrer,
-                                              FindFieldType type, size_t expected_size)
+inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
+                                       mirror::ArtMethod* referrer,
+                                       FindFieldType type, size_t expected_size)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path method resolution that can't throw exceptions.
-static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
-                                                mirror::Object* this_object,
-                                                mirror::ArtMethod* referrer,
-                                                bool access_check, InvokeType type)
+inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
+                                         mirror::Object* this_object,
+                                         mirror::ArtMethod* referrer,
+                                         bool access_check, InvokeType type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
-                                                    mirror::ArtMethod* referrer,
-                                                    Thread* self, bool can_run_clinit,
-                                                    bool verify_access)
+inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+                                             mirror::ArtMethod* referrer,
+                                             Thread* self, bool can_run_clinit,
+                                             bool verify_access)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer,
-                                                    uint32_t string_idx)
+inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer, uint32_t string_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // TODO: annotalysis disabled as monitor semantics are maintained in Java code.
-static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
+inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
     NO_THREAD_SAFETY_ANALYSIS;
 
 void CheckReferenceResult(mirror::Object* o, Thread* self)
@@ -179,61 +178,11 @@
                                     std::vector<jvalue>& args)
     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);
-}
+bool FillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 template <typename INT_TYPE, typename FLOAT_TYPE>
-static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f);
+inline INT_TYPE art_float_to_integral(FLOAT_TYPE f);
 
 }  // namespace art
 
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index b617636..28e19d4 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -15,6 +15,7 @@
  */
 
 #include "class_linker.h"
+#include "dex_file-inl.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
@@ -24,9 +25,7 @@
 
 namespace art {
 
-// TODO: Make the MethodHelper here be compaction safe.
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                                   const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item,
                                                    ShadowFrame* shadow_frame, JValue* result) {
   mirror::ArtMethod* method = shadow_frame->GetMethod();
   // Ensure static methods are initialized.
@@ -49,13 +48,9 @@
     }
   }
   uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
-  if (kUsePortableCompiler) {
-    InvokeWithShadowFrame(self, shadow_frame, arg_offset, mh, result);
-  } else {
-    method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
-                   (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
-                   result, mh.GetShorty());
-  }
+  method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
+                 (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
+                 result, method->GetShorty());
 }
 
 }  // namespace art
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.h b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
index d8b2204..0952214 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.h
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
@@ -27,17 +27,14 @@
 namespace art {
 
 union JValue;
-class MethodHelper;
 class ShadowFrame;
 class Thread;
 
 // Pointers to functions that are called by interpreter trampolines via thread-local storage.
 struct PACKED(4) InterpreterEntryPoints {
-  void (*pInterpreterToInterpreterBridge)(Thread* self, MethodHelper& mh,
-                                          const DexFile::CodeItem* code_item,
+  void (*pInterpreterToInterpreterBridge)(Thread* self, const DexFile::CodeItem* code_item,
                                           ShadowFrame* shadow_frame, JValue* result);
-  void (*pInterpreterToCompiledCodeBridge)(Thread* self, MethodHelper& mh,
-                                           const DexFile::CodeItem* code_item,
+  void (*pInterpreterToCompiledCodeBridge)(Thread* self, 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_alloc_entrypoints.cc b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
deleted file mode 100644
index de95f7d..0000000
--- a/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-static constexpr gc::AllocatorType kPortableAllocatorType =
-    gc::kUseRosAlloc ? gc::kAllocatorTypeRosAlloc : gc::kAllocatorTypeDlMalloc;
-
-extern "C" mirror::Object* art_portable_alloc_object_from_code(uint32_t type_idx,
-                                                               mirror::ArtMethod* referrer,
-                                                               Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocObjectFromCode<false, true>(type_idx, referrer, thread, kPortableAllocatorType);
-}
-
-extern "C" mirror::Object* art_portable_alloc_object_from_code_with_access_check(uint32_t type_idx,
-                                                                                 mirror::ArtMethod* referrer,
-                                                                                 Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocObjectFromCode<true, true>(type_idx, referrer, thread, kPortableAllocatorType);
-}
-
-extern "C" mirror::Object* art_portable_alloc_array_from_code(uint32_t type_idx,
-                                                              mirror::ArtMethod* referrer,
-                                                              uint32_t length,
-                                                              Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocArrayFromCode<false, true>(type_idx, referrer, length, self,
-                                         kPortableAllocatorType);
-}
-
-extern "C" mirror::Object* art_portable_alloc_array_from_code_with_access_check(uint32_t type_idx,
-                                                                                mirror::ArtMethod* referrer,
-                                                                                uint32_t length,
-                                                                                Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocArrayFromCode<true, true>(type_idx, referrer, length, self,
-                                        kPortableAllocatorType);
-}
-
-extern "C" mirror::Object* art_portable_check_and_alloc_array_from_code(uint32_t type_idx,
-                                                                        mirror::ArtMethod* referrer,
-                                                                        uint32_t length,
-                                                                        Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return CheckAndAllocArrayFromCodeInstrumented(type_idx, referrer, length, thread, false,
-                                                kPortableAllocatorType);
-}
-
-extern "C" mirror::Object* art_portable_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx,
-                                                                                          mirror::ArtMethod* referrer,
-                                                                                          uint32_t length,
-                                                                                          Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return CheckAndAllocArrayFromCodeInstrumented(type_idx, referrer, length, thread, true,
-                                                kPortableAllocatorType);
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_cast_entrypoints.cc b/runtime/entrypoints/portable/portable_cast_entrypoints.cc
deleted file mode 100644
index 151b178..0000000
--- a/runtime/entrypoints/portable/portable_cast_entrypoints.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "common_throws.h"
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-extern "C" int32_t art_portable_is_assignable_from_code(mirror::Class* dest_type,
-                                                        mirror::Class* src_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(dest_type != NULL);
-  DCHECK(src_type != NULL);
-  return dest_type->IsAssignableFrom(src_type) ? 1 : 0;
-}
-
-extern "C" void art_portable_check_cast_from_code(mirror::Class* dest_type,
-                                                  mirror::Class* src_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
-  DCHECK(src_type->IsClass()) << PrettyClass(src_type);
-  if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) {
-    ThrowClassCastException(dest_type, src_type);
-  }
-}
-
-extern "C" void art_portable_check_put_array_element_from_code(mirror::Object* element,
-                                                               mirror::Object* array)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (element == NULL) {
-    return;
-  }
-  DCHECK(array != NULL);
-  mirror::Class* array_class = array->GetClass();
-  DCHECK(array_class != NULL);
-  mirror::Class* component_type = array_class->GetComponentType();
-  mirror::Class* element_class = element->GetClass();
-  if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
-    ThrowArrayStoreException(element_class, array_class);
-  }
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
deleted file mode 100644
index 9364c46..0000000
--- a/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "gc/accounting/card_table-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-extern "C" mirror::Object* art_portable_initialize_static_storage_from_code(uint32_t type_idx,
-                                                                            mirror::ArtMethod* referrer,
-                                                                            Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ResolveVerifyAndClinit(type_idx, referrer, thread, true, false);
-}
-
-extern "C" mirror::Object* art_portable_initialize_type_from_code(uint32_t type_idx,
-                                                                  mirror::ArtMethod* referrer,
-                                                                  Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ResolveVerifyAndClinit(type_idx, referrer, thread, false, false);
-}
-
-extern "C" mirror::Object* art_portable_initialize_type_and_verify_access_from_code(uint32_t type_idx,
-                                                                                    mirror::ArtMethod* referrer,
-                                                                                    Thread* thread)
-    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
-  return ResolveVerifyAndClinit(type_idx, referrer, thread, false, true);
-}
-
-extern "C" mirror::Object* art_portable_resolve_string_from_code(mirror::ArtMethod* referrer,
-                                                                 uint32_t string_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ResolveStringFromCode(referrer, string_idx);
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h
deleted file mode 100644
index 6f77e1c..0000000
--- a/runtime/entrypoints/portable/portable_entrypoints.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_
-#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_
-
-#include "dex_file-inl.h"
-#include "runtime.h"
-
-namespace art {
-namespace mirror {
-  class ArtMethod;
-  class Object;
-}  // namespace mirror
-class Thread;
-
-#define PORTABLE_ENTRYPOINT_OFFSET(ptr_size, x) \
-    Thread::PortableEntryPointOffset<ptr_size>(OFFSETOF_MEMBER(PortableEntryPoints, x))
-
-// Pointers to functions that are called by code generated by compiler's adhering to the portable
-// compiler ABI.
-struct PACKED(4) PortableEntryPoints {
-  // Invocation
-  void (*pPortableImtConflictTrampoline)(mirror::ArtMethod*);
-  void (*pPortableResolutionTrampoline)(mirror::ArtMethod*);
-  void (*pPortableToInterpreterBridge)(mirror::ArtMethod*);
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_
diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc
deleted file mode 100644
index 371aca4..0000000
--- a/runtime/entrypoints/portable/portable_field_entrypoints.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_field-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-extern "C" int32_t art_portable_set32_static_from_code(uint32_t field_idx,
-                                                       mirror::ArtMethod* referrer,
-                                                       int32_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx,
-                               referrer,
-                               StaticPrimitiveWrite,
-                               sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set32<false>(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
-                                                        sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set32<false>(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  return -1;
-}
-
-extern "C" int32_t art_portable_set64_static_from_code(uint32_t field_idx,
-                                                       mirror::ArtMethod* referrer,
-                                                       int64_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set64<false>(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
-                                                        sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set64<false>(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  return -1;
-}
-
-extern "C" int32_t art_portable_set_obj_static_from_code(uint32_t field_idx,
-                                                         mirror::ArtMethod* referrer,
-                                                         mirror::Object* new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite,
-                                          sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->SetObj<false>(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, Thread::Current(),
-                                                     sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->SetObj<false>(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  return -1;
-}
-
-extern "C" int32_t art_portable_get32_static_from_code(uint32_t field_idx,
-                                                       mirror::ArtMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get32(field->GetDeclaringClass());
-  }
-  field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, Thread::Current(),
-                                                       sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get32(field->GetDeclaringClass());
-  }
-  return 0;
-}
-
-extern "C" int64_t art_portable_get64_static_from_code(uint32_t field_idx,
-                                                       mirror::ArtMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get64(field->GetDeclaringClass());
-  }
-  field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, Thread::Current(),
-                                                       sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get64(field->GetDeclaringClass());
-  }
-  return 0;
-}
-
-extern "C" mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_idx,
-                                                                 mirror::ArtMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectRead,
-                                          sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(field->GetDeclaringClass());
-  }
-  field = FindFieldFromCode<StaticObjectRead, true>(field_idx, referrer, Thread::Current(),
-                                                    sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(field->GetDeclaringClass());
-  }
-  return 0;
-}
-
-extern "C" int32_t art_portable_set32_instance_from_code(uint32_t field_idx,
-                                                         mirror::ArtMethod* referrer,
-                                                         mirror::Object* obj, uint32_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set32<false>(obj, new_value);
-    return 0;
-  }
-  field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
-                                                          sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set32<false>(obj, new_value);
-    return 0;
-  }
-  return -1;
-}
-
-extern "C" int32_t art_portable_set64_instance_from_code(uint32_t field_idx,
-                                                         mirror::ArtMethod* referrer,
-                                                         mirror::Object* obj, int64_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set64<false>(obj, new_value);
-    return 0;
-  }
-  field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
-                                                          sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->Set64<false>(obj, new_value);
-    return 0;
-  }
-  return -1;
-}
-
-extern "C" int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx,
-                                                           mirror::ArtMethod* referrer,
-                                                           mirror::Object* obj,
-                                                           mirror::Object* new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
-                                          sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->SetObj<false>(obj, new_value);
-    return 0;
-  }
-  field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, Thread::Current(),
-                                                       sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    // Compiled code can't use transactional mode.
-    field->SetObj<false>(obj, new_value);
-    return 0;
-  }
-  return -1;
-}
-
-extern "C" int32_t art_portable_get32_instance_from_code(uint32_t field_idx,
-                                                         mirror::ArtMethod* referrer,
-                                                         mirror::Object* obj)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get32(obj);
-  }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, Thread::Current(),
-                                                         sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get32(obj);
-  }
-  return 0;
-}
-
-extern "C" int64_t art_portable_get64_instance_from_code(uint32_t field_idx,
-                                                         mirror::ArtMethod* referrer,
-                                                         mirror::Object* obj)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get64(obj);
-  }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, Thread::Current(),
-                                                         sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get64(obj);
-  }
-  return 0;
-}
-
-extern "C" mirror::Object* art_portable_get_obj_instance_from_code(uint32_t field_idx,
-                                                                   mirror::ArtMethod* referrer,
-                                                                   mirror::Object* obj)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectRead,
-                                          sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(obj);
-  }
-  field = FindFieldFromCode<InstanceObjectRead, true>(field_idx, referrer, Thread::Current(),
-                                                      sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(obj);
-  }
-  return 0;
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
deleted file mode 100644
index 686954b..0000000
--- a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_instruction.h"
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-extern "C" void art_portable_fill_array_data_from_code(mirror::ArtMethod* method,
-                                                       uint32_t dex_pc,
-                                                       mirror::Array* array,
-                                                       uint32_t payload_offset)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = method->GetCodeItem();
-  const Instruction::ArrayDataPayload* payload =
-      reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item->insns_ + payload_offset);
-  DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
-  if (UNLIKELY(array == NULL)) {
-    ThrowNullPointerException(NULL, "null array in FILL_ARRAY_DATA");
-    return;  // Error
-  }
-  DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
-  if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
-    Thread* self = Thread::Current();
-    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-    self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
-                             "failed FILL_ARRAY_DATA; length=%d, index=%d",
-                             array->GetLength(), payload->element_count - 1);
-    return;  // Error
-  }
-  uint32_t size_in_bytes = payload->element_count * payload->element_width;
-  memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
deleted file mode 100644
index 6f9c083..0000000
--- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/dex_cache-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-template<InvokeType type, bool access_check>
-mirror::ArtMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_object,
-                                    mirror::ArtMethod* caller_method, Thread* self) {
-  mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method,
-                                             access_check, type);
-  if (UNLIKELY(method == NULL)) {
-    // Note: This can cause thread suspension.
-    self->AssertThreadSuspensionIsAllowable();
-    method = FindMethodFromCode<type, access_check>(method_idx, &this_object, &caller_method,
-                                                    self);
-    if (UNLIKELY(method == NULL)) {
-      CHECK(self->IsExceptionPending());
-      return 0;  // failure
-    }
-  }
-  DCHECK(!self->IsExceptionPending());
-  const void* code = method->GetEntryPointFromPortableCompiledCode();
-
-  // When we return, the caller will branch to this address, so it had better not be 0!
-  if (UNLIKELY(code == NULL)) {
-      LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method)
-                 << " location: " << method->GetDexFile()->GetLocation();
-  }
-  return method;
-}
-
-// Explicit template declarations of FindMethodHelper for all invoke types.
-#define EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, _access_check)                        \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                         \
-  mirror::ArtMethod* FindMethodHelper<_type, _access_check>(uint32_t method_idx,               \
-                                                            mirror::Object* this_object,       \
-                                                            mirror::ArtMethod* caller_method,  \
-                                                            Thread* thread)
-#define EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(_type) \
-    EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, false);   \
-    EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, true)
-
-EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(kStatic);
-EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(kDirect);
-EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(kVirtual);
-EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(kSuper);
-EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(kInterface);
-
-#undef EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL
-#undef EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL
-
-extern "C" mirror::Object* art_portable_find_static_method_from_code_with_access_check(uint32_t method_idx,
-                                                                                       mirror::Object* this_object,
-                                                                                       mirror::ArtMethod* referrer,
-                                                                                       Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper<kStatic, true>(method_idx, this_object, referrer, thread);
-}
-
-extern "C" mirror::Object* art_portable_find_direct_method_from_code_with_access_check(uint32_t method_idx,
-                                                                                       mirror::Object* this_object,
-                                                                                       mirror::ArtMethod* referrer,
-                                                                                       Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper<kDirect, true>(method_idx, this_object, referrer, thread);
-}
-
-extern "C" mirror::Object* art_portable_find_virtual_method_from_code_with_access_check(uint32_t method_idx,
-                                                                                        mirror::Object* this_object,
-                                                                                        mirror::ArtMethod* referrer,
-                                                                                        Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper<kVirtual, true>(method_idx, this_object, referrer, thread);
-}
-
-extern "C" mirror::Object* art_portable_find_super_method_from_code_with_access_check(uint32_t method_idx,
-                                                                                      mirror::Object* this_object,
-                                                                                      mirror::ArtMethod* referrer,
-                                                                                      Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper<kSuper, true>(method_idx, this_object, referrer, thread);
-}
-
-extern "C" mirror::Object* art_portable_find_interface_method_from_code_with_access_check(uint32_t method_idx,
-                                                                                          mirror::Object* this_object,
-                                                                                          mirror::ArtMethod* referrer,
-                                                                                          Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper<kInterface, true>(method_idx, this_object, referrer, thread);
-}
-
-extern "C" mirror::Object* art_portable_find_interface_method_from_code(uint32_t method_idx,
-                                                                        mirror::Object* this_object,
-                                                                        mirror::ArtMethod* referrer,
-                                                                        Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper<kInterface, false>(method_idx, this_object, referrer, thread);
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_jni_entrypoints.cc b/runtime/entrypoints/portable/portable_jni_entrypoints.cc
deleted file mode 100644
index 0d0f21b..0000000
--- a/runtime/entrypoints/portable/portable_jni_entrypoints.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-#include "thread-inl.h"
-
-namespace art {
-
-// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
-extern "C" uint32_t art_portable_jni_method_start(Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) {
-  JNIEnvExt* env = self->GetJniEnv();
-  uint32_t saved_local_ref_cookie = env->local_ref_cookie;
-  env->local_ref_cookie = env->locals.GetSegmentState();
-  self->TransitionFromRunnableToSuspended(kNative);
-  return saved_local_ref_cookie;
-}
-
-extern "C" uint32_t art_portable_jni_method_start_synchronized(jobject to_lock, Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) NO_THREAD_SAFETY_ANALYSIS {
-  self->DecodeJObject(to_lock)->MonitorEnter(self);
-  return art_portable_jni_method_start(self);
-}
-
-static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  JNIEnvExt* env = self->GetJniEnv();
-  env->locals.SetSegmentState(env->local_ref_cookie);
-  env->local_ref_cookie = saved_local_ref_cookie;
-}
-
-extern "C" void art_portable_jni_method_end(uint32_t saved_local_ref_cookie, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  PopLocalReferences(saved_local_ref_cookie, self);
-}
-
-
-extern "C" void art_portable_jni_method_end_synchronized(uint32_t saved_local_ref_cookie,
-                                              jobject locked,
-                                              Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
-  PopLocalReferences(saved_local_ref_cookie, self);
-}
-
-extern "C" mirror::Object* art_portable_jni_method_end_with_reference(jobject result,
-                                                                      uint32_t saved_local_ref_cookie,
-                                                                      Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  mirror::Object* o = self->DecodeJObject(result);  // Must decode before pop.
-  PopLocalReferences(saved_local_ref_cookie, self);
-  // Process result.
-  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
-    if (self->IsExceptionPending()) {
-      return NULL;
-    }
-    CheckReferenceResult(o, self);
-  }
-  return o;
-}
-
-extern "C" mirror::Object* art_portable_jni_method_end_with_reference_synchronized(jobject result,
-                                                                                   uint32_t saved_local_ref_cookie,
-                                                                                   jobject locked,
-                                                                                   Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
-  mirror::Object* o = self->DecodeJObject(result);
-  PopLocalReferences(saved_local_ref_cookie, self);
-  // Process result.
-  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
-    if (self->IsExceptionPending()) {
-      return NULL;
-    }
-    CheckReferenceResult(o, self);
-  }
-  return o;
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_lock_entrypoints.cc b/runtime/entrypoints/portable/portable_lock_entrypoints.cc
deleted file mode 100644
index fcd3e9d..0000000
--- a/runtime/entrypoints/portable/portable_lock_entrypoints.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-extern "C" void art_portable_lock_object_from_code(mirror::Object* obj, Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-    NO_THREAD_SAFETY_ANALYSIS /* EXCLUSIVE_LOCK_FUNCTION(Monitor::monitor_lock_) */ {
-  DCHECK(obj != nullptr);        // Assumed to have been checked before entry.
-  obj->MonitorEnter(thread);  // May block.
-  DCHECK(thread->HoldsLock(obj));
-  // Only possible exception is NPE and is handled before entry.
-  DCHECK(!thread->IsExceptionPending());
-}
-
-extern "C" void art_portable_unlock_object_from_code(mirror::Object* obj, Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-    NO_THREAD_SAFETY_ANALYSIS /* UNLOCK_FUNCTION(Monitor::monitor_lock_) */ {
-  DCHECK(obj != nullptr);  // Assumed to have been checked before entry.
-  // MonitorExit may throw exception.
-  obj->MonitorExit(thread);
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
deleted file mode 100644
index ecbc65e..0000000
--- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mirror/art_method-inl.h"
-#include "verifier/dex_gc_map.h"
-#include "stack.h"
-#include "thread-inl.h"
-
-namespace art {
-
-class ShadowFrameCopyVisitor : public StackVisitor {
- public:
-  explicit ShadowFrameCopyVisitor(Thread* self) : StackVisitor(self, NULL), prev_frame_(NULL),
-      top_frame_(NULL) {}
-
-  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (IsShadowFrame()) {
-      ShadowFrame* cur_frame = GetCurrentShadowFrame();
-      size_t num_regs = cur_frame->NumberOfVRegs();
-      mirror::ArtMethod* method = cur_frame->GetMethod();
-      uint32_t dex_pc = cur_frame->GetDexPC();
-      ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
-
-      const uint8_t* gc_map = method->GetNativeGcMap();
-      verifier::DexPcToReferenceMap dex_gc_map(gc_map);
-      const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
-      for (size_t reg = 0; reg < num_regs; ++reg) {
-        if (TestBitmap(reg, reg_bitmap)) {
-          new_frame->SetVRegReference(reg, cur_frame->GetVRegReference(reg));
-        } else {
-          new_frame->SetVReg(reg, cur_frame->GetVReg(reg));
-        }
-      }
-
-      if (prev_frame_ != NULL) {
-        prev_frame_->SetLink(new_frame);
-      } else {
-        top_frame_ = new_frame;
-      }
-      prev_frame_ = new_frame;
-    }
-    return true;
-  }
-
-  ShadowFrame* GetShadowFrameCopy() {
-    return top_frame_;
-  }
-
- private:
-  static bool TestBitmap(int reg, const uint8_t* reg_vector) {
-    return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
-  }
-
-  ShadowFrame* prev_frame_;
-  ShadowFrame* top_frame_;
-};
-
-extern "C" void art_portable_test_suspend_from_code(Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  self->CheckSuspend();
-  if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) {
-    // Save out the shadow frame to the heap
-    ShadowFrameCopyVisitor visitor(self);
-    visitor.WalkStack(true);
-    self->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy());
-    self->SetDeoptimizationReturnValue(JValue());
-    self->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
-  }
-}
-
-extern "C" ShadowFrame* art_portable_push_shadow_frame_from_code(Thread* thread,
-                                                                 ShadowFrame* new_shadow_frame,
-                                                                 mirror::ArtMethod* method,
-                                                                 uint32_t num_vregs) {
-  ShadowFrame* old_frame = thread->PushShadowFrame(new_shadow_frame);
-  new_shadow_frame->SetMethod(method);
-  new_shadow_frame->SetNumberOfVRegs(num_vregs);
-  return old_frame;
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
deleted file mode 100644
index 4317358..0000000
--- a/runtime/entrypoints/portable/portable_throw_entrypoints.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_instruction.h"
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-
-namespace art {
-
-extern "C" void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowArithmeticExceptionDivideByZero();
-}
-
-extern "C" void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowArrayIndexOutOfBoundsException(index, length);
-}
-
-extern "C" void art_portable_throw_no_such_method_from_code(int32_t method_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowNoSuchMethodError(method_idx);
-}
-
-extern "C" void art_portable_throw_null_pointer_exception_from_code(uint32_t dex_pc)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // TODO: remove dex_pc argument from caller.
-  UNUSED(dex_pc);
-  Thread* self = Thread::Current();
-  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-  ThrowNullPointerExceptionFromDexPC(throw_location);
-}
-
-extern "C" void art_portable_throw_stack_overflow_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowStackOverflowError(Thread::Current());
-}
-
-extern "C" void art_portable_throw_exception_from_code(mirror::Throwable* exception)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Thread* self = Thread::Current();
-  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-  if (exception == NULL) {
-    ThrowNullPointerException(NULL, "throw with null exception");
-  } else {
-    self->SetException(throw_location, exception);
-  }
-}
-
-extern "C" void* art_portable_get_and_clear_exception(Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(self->IsExceptionPending());
-  // TODO: make this inline.
-  mirror::Throwable* exception = self->GetException(NULL);
-  self->ClearException();
-  return exception;
-}
-
-extern "C" int32_t art_portable_find_catch_block_from_code(mirror::ArtMethod* current_method,
-                                                           uint32_t ti_offset)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Thread* self = Thread::Current();  // TODO: make an argument.
-  ThrowLocation throw_location;
-  mirror::Throwable* exception = self->GetException(&throw_location);
-  // Check for special deoptimization exception.
-  if (UNLIKELY(reinterpret_cast<intptr_t>(exception) == -1)) {
-    return -1;
-  }
-  mirror::Class* exception_type = exception->GetClass();
-  StackHandleScope<1> hs(self);
-  const DexFile::CodeItem* code_item = current_method->GetCodeItem();
-  DCHECK_LT(ti_offset, code_item->tries_size_);
-  const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
-
-  int iter_index = 0;
-  int result = -1;
-  uint32_t catch_dex_pc = -1;
-  // Iterate over the catch handlers associated with dex_pc
-  for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) {
-    uint16_t iter_type_idx = it.GetHandlerTypeIndex();
-    // Catch all case
-    if (iter_type_idx == DexFile::kDexNoIndex16) {
-      catch_dex_pc = it.GetHandlerAddress();
-      result = iter_index;
-      break;
-    }
-    // Does this catch exception type apply?
-    mirror::Class* iter_exception_type =
-        current_method->GetDexCacheResolvedType(iter_type_idx);
-    if (UNLIKELY(iter_exception_type == NULL)) {
-      // TODO: check, the verifier (class linker?) should take care of resolving all exception
-      //       classes early.
-      LOG(WARNING) << "Unresolved exception class when finding catch block: "
-          << current_method->GetTypeDescriptorFromTypeIdx(iter_type_idx);
-    } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
-      catch_dex_pc = it.GetHandlerAddress();
-      result = iter_index;
-      break;
-    }
-    ++iter_index;
-  }
-  if (result != -1) {
-    // Handler found.
-    Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(
-        self, throw_location, current_method, catch_dex_pc, exception);
-    // If the catch block has no move-exception then clear the exception for it.
-    const Instruction* first_catch_instr = Instruction::At(
-        &current_method->GetCodeItem()->insns_[catch_dex_pc]);
-    if (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION) {
-      self->ClearException();
-    }
-  }
-  return result;
-}
-
-}  // namespace art
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
deleted file mode 100644
index 7f6144b..0000000
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
-#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
-
-#include "dex_instruction-inl.h"
-#include "entrypoints/entrypoint_utils-inl.h"
-#include "interpreter/interpreter.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
-
-namespace art {
-
-// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
-class PortableArgumentVisitor {
- public:
-// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
-// Size of Runtime::kRefAndArgs callee save frame.
-// Size of Method* and register parameters in out stack arguments.
-#if defined(__arm__)
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
-#define PORTABLE_STACK_ARG_SKIP 0
-#elif defined(__mips__)
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
-#define PORTABLE_STACK_ARG_SKIP 16
-#elif defined(__i386__)
-// For x86 there are no register arguments and the stack pointer will point directly to the called
-// method argument passed by the caller.
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
-#define PORTABLE_STACK_ARG_SKIP 4
-#elif defined(__x86_64__)
-// TODO: implement and check these.
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 16
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 96
-#define PORTABLE_STACK_ARG_SKIP 0
-#else
-// TODO: portable should be disabled for aarch64 for now.
-// #error "Unsupported architecture"
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
-#define PORTABLE_STACK_ARG_SKIP 0
-#endif
-
-  PortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
-    caller_mh_(caller_mh),
-    args_in_regs_(ComputeArgsInRegs(caller_mh)),
-    num_params_(caller_mh.NumArgs()),
-    reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
-    stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
-                + PORTABLE_STACK_ARG_SKIP),
-    cur_args_(reg_args_),
-    cur_arg_index_(0),
-    param_index_(0) {
-  }
-
-  virtual ~PortableArgumentVisitor() {}
-
-  virtual void Visit() = 0;
-
-  bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return caller_mh_.IsParamAReference(param_index_);
-  }
-
-  bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return caller_mh_.IsParamALongOrDouble(param_index_);
-  }
-
-  Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return caller_mh_.GetParamPrimitiveType(param_index_);
-  }
-
-  byte* GetParamAddress() const {
-    return cur_args_ + (cur_arg_index_ * kPointerSize);
-  }
-
-  void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    for (cur_arg_index_ = 0;  cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
-#if (defined(__arm__) || defined(__mips__))
-      if (IsParamALongOrDouble() && cur_arg_index_ == 2) {
-        break;
-      }
-#endif
-      Visit();
-      cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
-      param_index_++;
-    }
-    cur_args_ = stack_args_;
-    cur_arg_index_ = 0;
-    while (param_index_ < num_params_) {
-#if (defined(__arm__) || defined(__mips__))
-      if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) {
-        cur_arg_index_++;
-      }
-#endif
-      Visit();
-      cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
-      param_index_++;
-    }
-  }
-
- private:
-  static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if (defined(__i386__))
-    return 0;
-#else
-    size_t args_in_regs = 0;
-    size_t num_params = mh.NumArgs();
-    for (size_t i = 0; i < num_params; i++) {
-      args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
-      if (args_in_regs > 3) {
-        args_in_regs = 3;
-        break;
-      }
-    }
-    return args_in_regs;
-#endif
-  }
-  MethodHelper& caller_mh_;
-  const size_t args_in_regs_;
-  const size_t num_params_;
-  byte* const reg_args_;
-  byte* const stack_args_;
-  byte* cur_args_;
-  size_t cur_arg_index_;
-  size_t param_index_;
-};
-
-// Visits arguments on the stack placing them into the shadow frame.
-class BuildPortableShadowFrameVisitor : public PortableArgumentVisitor {
- public:
-  BuildPortableShadowFrameVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp,
-      ShadowFrame& sf, size_t first_arg_reg) :
-    PortableArgumentVisitor(caller_mh, sp), sf_(sf), cur_reg_(first_arg_reg) { }
-  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Primitive::Type type = GetParamPrimitiveType();
-    switch (type) {
-      case Primitive::kPrimLong:  // Fall-through.
-      case Primitive::kPrimDouble:
-        sf_.SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress()));
-        ++cur_reg_;
-        break;
-      case Primitive::kPrimNot:
-        sf_.SetVRegReference(cur_reg_, *reinterpret_cast<mirror::Object**>(GetParamAddress()));
-        break;
-      case Primitive::kPrimBoolean:  // Fall-through.
-      case Primitive::kPrimByte:     // Fall-through.
-      case Primitive::kPrimChar:     // Fall-through.
-      case Primitive::kPrimShort:    // Fall-through.
-      case Primitive::kPrimInt:      // Fall-through.
-      case Primitive::kPrimFloat:
-        sf_.SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress()));
-        break;
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "UNREACHABLE";
-        break;
-    }
-    ++cur_reg_;
-  }
-
- private:
-  ShadowFrame& sf_;
-  size_t cur_reg_;
-
-  DISALLOW_COPY_AND_ASSIGN(BuildPortableShadowFrameVisitor);
-};
-
-extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Thread* self,
-                                                   mirror::ArtMethod** sp)
-    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);
-
-  if (method->IsAbstract()) {
-    ThrowAbstractMethodError(method);
-    return 0;
-  } else {
-    const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
-    StackHandleScope<2> hs(self);
-    MethodHelper mh(hs.NewHandle(method));
-    const DexFile::CodeItem* code_item = method->GetCodeItem();
-    uint16_t num_regs = code_item->registers_size_;
-    void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
-    ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL,  // No last shadow coming from quick.
-                                                  method, 0, memory));
-    size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
-    BuildPortableShadowFrameVisitor shadow_frame_builder(mh, sp,
-                                                 *shadow_frame, first_arg_reg);
-    shadow_frame_builder.VisitArguments();
-    // Push a transition back into managed code onto the linked list in thread.
-    ManagedStack fragment;
-    self->PushManagedStackFragment(&fragment);
-    self->PushShadowFrame(shadow_frame);
-    self->EndAssertNoThreadSuspension(old_cause);
-
-    if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) {
-      // Ensure static method's class is initialized.
-      Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
-      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
-        DCHECK(Thread::Current()->IsExceptionPending());
-        self->PopManagedStackFragment(fragment);
-        return 0;
-      }
-    }
-
-    JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
-    // Pop transition.
-    self->PopManagedStackFragment(fragment);
-    return result.GetJ();
-  }
-}
-
-// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
-// to jobjects.
-class BuildPortableArgumentVisitor : public PortableArgumentVisitor {
- public:
-  BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp,
-                               ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
-    PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
-
-  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    jvalue val;
-    Primitive::Type type = GetParamPrimitiveType();
-    switch (type) {
-      case Primitive::kPrimNot: {
-        mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress());
-        val.l = soa_.AddLocalReference<jobject>(obj);
-        break;
-      }
-      case Primitive::kPrimLong:  // Fall-through.
-      case Primitive::kPrimDouble:
-        val.j = *reinterpret_cast<jlong*>(GetParamAddress());
-        break;
-      case Primitive::kPrimBoolean:  // Fall-through.
-      case Primitive::kPrimByte:     // Fall-through.
-      case Primitive::kPrimChar:     // Fall-through.
-      case Primitive::kPrimShort:    // Fall-through.
-      case Primitive::kPrimInt:      // Fall-through.
-      case Primitive::kPrimFloat:
-        val.i =  *reinterpret_cast<jint*>(GetParamAddress());
-        break;
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "UNREACHABLE";
-        val.j = 0;
-        break;
-    }
-    args_.push_back(val);
-  }
-
- private:
-  ScopedObjectAccessUnchecked& soa_;
-  std::vector<jvalue>& args_;
-
-  DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor);
-};
-
-// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
-// which is responsible for recording callee save registers. We explicitly place into jobjects the
-// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
-// field within the proxy object, which will box the primitive arguments and deal with error cases.
-extern "C" uint64_t artPortableProxyInvokeHandler(mirror::ArtMethod* proxy_method,
-                                                  mirror::Object* receiver,
-                                                  Thread* self, mirror::ArtMethod** sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
-  const char* old_cause =
-      self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
-  self->VerifyStack();
-  // Start new JNI local reference state.
-  JNIEnvExt* env = self->GetJniEnv();
-  ScopedObjectAccessUnchecked soa(env);
-  ScopedJniEnvLocalRefState env_state(env);
-  // Create local ref. copies of proxy method and the receiver.
-  jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
-
-  // Placing arguments into args vector and remove the receiver.
-  StackHandleScope<1> hs(self);
-  MethodHelper proxy_mh(hs.NewHandle(proxy_method));
-  std::vector<jvalue> args;
-  BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
-  local_ref_visitor.VisitArguments();
-  args.erase(args.begin());
-
-  // Convert proxy method into expected interface method.
-  mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod();
-  DCHECK(interface_method != NULL);
-  DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
-  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
-
-  // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
-  // that performs allocations.
-  self->EndAssertNoThreadSuspension(old_cause);
-  JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
-                                               rcvr_jobj, interface_method_jobj, args);
-  return result.GetJ();
-}
-
-// Lazily resolve a method for portable. Called by stub code.
-extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called,
-                                                       mirror::Object* receiver,
-                                                       Thread* self,
-                                                       mirror::ArtMethod** called_addr)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  uint32_t dex_pc;
-  mirror::ArtMethod* caller = self->GetCurrentMethod(&dex_pc);
-
-  ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  InvokeType invoke_type;
-  bool is_range;
-  if (called->IsRuntimeMethod()) {
-    const DexFile::CodeItem* code = caller->GetCodeItem();
-    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
-    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
-    Instruction::Code instr_code = instr->Opcode();
-    switch (instr_code) {
-      case Instruction::INVOKE_DIRECT:
-        invoke_type = kDirect;
-        is_range = false;
-        break;
-      case Instruction::INVOKE_DIRECT_RANGE:
-        invoke_type = kDirect;
-        is_range = true;
-        break;
-      case Instruction::INVOKE_STATIC:
-        invoke_type = kStatic;
-        is_range = false;
-        break;
-      case Instruction::INVOKE_STATIC_RANGE:
-        invoke_type = kStatic;
-        is_range = true;
-        break;
-      case Instruction::INVOKE_SUPER:
-        invoke_type = kSuper;
-        is_range = false;
-        break;
-      case Instruction::INVOKE_SUPER_RANGE:
-        invoke_type = kSuper;
-        is_range = true;
-        break;
-      case Instruction::INVOKE_VIRTUAL:
-        invoke_type = kVirtual;
-        is_range = false;
-        break;
-      case Instruction::INVOKE_VIRTUAL_RANGE:
-        invoke_type = kVirtual;
-        is_range = true;
-        break;
-      case Instruction::INVOKE_INTERFACE:
-        invoke_type = kInterface;
-        is_range = false;
-        break;
-      case Instruction::INVOKE_INTERFACE_RANGE:
-        invoke_type = kInterface;
-        is_range = true;
-        break;
-      default:
-        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
-        // Avoid used uninitialized warnings.
-        invoke_type = kDirect;
-        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);
-    // Incompatible class change should have been handled in resolve method.
-    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
-    // Refine called method based on receiver.
-    if (invoke_type == kVirtual) {
-      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
-    } else if (invoke_type == kInterface) {
-      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
-    }
-  } else {
-    CHECK(called->IsStatic()) << PrettyMethod(called);
-    invoke_type = kStatic;
-    // Incompatible class change should have been handled in resolve method.
-    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
-  }
-  const void* code = nullptr;
-  if (LIKELY(!self->IsExceptionPending())) {
-    // 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);
-    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);
-      }
-    } 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);
-      } 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);
-        }
-      }
-    } else {
-      DCHECK(called_class->IsErroneous());
-    }
-  }
-  if (LIKELY(code != nullptr)) {
-    // Expect class to at least be initializing.
-    DCHECK(called->GetDeclaringClass()->IsInitializing());
-    // Don't want infinite recursion.
-    DCHECK(code != linker->GetPortableResolutionTrampoline());
-    // Set up entry into main method
-    *called_addr = called;
-  }
-  return code;
-}
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index e728f7d..8cd6ca6 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -17,10 +17,9 @@
 #ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
 #define ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
 
+#include "arch/instruction_set.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
@@ -28,6 +27,7 @@
 #include "arch/arm/quick_method_frame_info_arm.h"
 #include "arch/arm64/quick_method_frame_info_arm64.h"
 #include "arch/mips/quick_method_frame_info_mips.h"
+#include "arch/mips64/quick_method_frame_info_mips64.h"
 #include "arch/x86/quick_method_frame_info_x86.h"
 #include "arch/x86_64/quick_method_frame_info_x86_64.h"
 
@@ -36,22 +36,48 @@
 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.
   return (isa == kArm || isa == kThumb2) ? arm::ArmCalleeSaveFrameSize(type) :
          isa == kArm64 ? arm64::Arm64CalleeSaveFrameSize(type) :
          isa == kMips ? mips::MipsCalleeSaveFrameSize(type) :
+         isa == kMips64 ? mips64::Mips64CalleeSaveFrameSize(type) :
          isa == kX86 ? x86::X86CalleeSaveFrameSize(type) :
          isa == kX86_64 ? x86_64::X86_64CalleeSaveFrameSize(type) :
          isa == kNone ? (LOG(FATAL) << "kNone has no frame size", 0) :
@@ -64,6 +90,7 @@
   return (isa == kArm || isa == kThumb2) ? kArmPointerSize :
          isa == kArm64 ? kArm64PointerSize :
          isa == kMips ? kMipsPointerSize :
+         isa == kMips64 ? kMips64PointerSize :
          isa == kX86 ? kX86PointerSize :
          isa == kX86_64 ? kX86_64PointerSize :
          isa == kNone ? (LOG(FATAL) << "kNone has no pointer size", 0) :
@@ -71,7 +98,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..1fd1150 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -29,9 +29,9 @@
 
 #define GENERATE_ENTRYPOINTS_FOR_ALLOCATOR_INST(suffix, suffix2, instrumented_bool, allocator_type) \
 extern "C" mirror::Object* artAllocObjectFromCode ##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_) { \
+  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 +53,13 @@
       } \
     } \
   } \
-  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_) { \
+  UNUSED(method); \
+  ScopedQuickEntrypointChecks sqec(self); \
   if (kUseTlabFastPath && !instrumented_bool && allocator_type == gc::kAllocatorTypeTLAB) { \
     if (LIKELY(klass->IsInitialized())) { \
       size_t byte_count = klass->GetObjectSize(); \
@@ -80,13 +80,13 @@
       } \
     } \
   } \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
-  return AllocObjectFromCodeResolved<instrumented_bool>(klass, method, self, allocator_type); \
+  return AllocObjectFromCodeResolved<instrumented_bool>(klass, 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_) { \
+  UNUSED(method); \
+  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,60 +105,53 @@
       return obj; \
     } \
   } \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
-  return AllocObjectFromCodeInitialized<instrumented_bool>(klass, method, self, allocator_type); \
+  return AllocObjectFromCodeInitialized<instrumented_bool>(klass, 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, int32_t component_count, mirror::ArtMethod* method, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
-  return AllocArrayFromCode<false, instrumented_bool>(type_idx, method, component_count, self, \
+  ScopedQuickEntrypointChecks sqec(self); \
+  return AllocArrayFromCode<false, instrumented_bool>(type_idx, component_count, method, 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, int32_t component_count, mirror::ArtMethod* method, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
-  return AllocArrayFromCodeResolved<false, instrumented_bool>(klass, method, component_count, self, \
+  ScopedQuickEntrypointChecks sqec(self); \
+  return AllocArrayFromCodeResolved<false, instrumented_bool>(klass, component_count, method, 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, int32_t component_count, mirror::ArtMethod* method, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
-  return AllocArrayFromCode<true, instrumented_bool>(type_idx, method, component_count, self, \
+  ScopedQuickEntrypointChecks sqec(self); \
+  return AllocArrayFromCode<true, instrumented_bool>(type_idx, component_count, method, 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, int32_t component_count, mirror::ArtMethod* method, 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); \
+    return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, false, allocator_type); \
   } else { \
-    return CheckAndAllocArrayFromCodeInstrumented(type_idx, method, component_count, self, false, allocator_type); \
+    return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, false, allocator_type); \
   } \
 } \
 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, int32_t component_count, mirror::ArtMethod* method, 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); \
+    return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, true, allocator_type); \
   } else { \
-    return CheckAndAllocArrayFromCodeInstrumented(type_idx, method, component_count, self, true, allocator_type); \
+    return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, true, allocator_type); \
   } \
 }
 
@@ -172,24 +165,24 @@
 GENERATE_ENTRYPOINTS_FOR_ALLOCATOR(TLAB, gc::kAllocatorTypeTLAB)
 
 #define GENERATE_ENTRYPOINTS(suffix) \
-extern "C" void* art_quick_alloc_array##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_resolved##suffix(void* klass, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_alloc_object_resolved##suffix(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_initialized##suffix(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_with_access_check##suffix(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(void* klass, void*, int32_t); \
-extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(void* klass, void* method); \
-extern "C" void* art_quick_alloc_object_with_access_check##suffix##_instrumented(uint32_t type_idx, void* method); \
-extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
-extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_array##suffix(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_array_resolved##suffix(mirror::Class* klass, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_resolved##suffix(mirror::Class* klass, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_initialized##suffix(mirror::Class* klass, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_with_access_check##suffix(uint32_t type_idx, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(mirror::Class* klass, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(mirror::Class* klass, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_initialized##suffix##_instrumented(mirror::Class* klass, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_alloc_object_with_access_check##suffix##_instrumented(uint32_t type_idx, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_check_and_alloc_array##suffix##_instrumented(uint32_t, int32_t, mirror::ArtMethod* ref); \
+extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented(uint32_t, int32_t, mirror::ArtMethod* ref); \
 void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrumented) { \
   if (instrumented) { \
     qpoints->pAllocArray = art_quick_alloc_array##suffix##_instrumented; \
@@ -234,31 +227,34 @@
 }
 
 void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints) {
-  switch (entry_points_allocator) {
 #if !defined(__APPLE__) || !defined(__LP64__)
+  switch (entry_points_allocator) {
     case gc::kAllocatorTypeDlMalloc: {
       SetQuickAllocEntryPoints_dlmalloc(qpoints, entry_points_instrumented);
-      break;
+      return;
     }
     case gc::kAllocatorTypeRosAlloc: {
       SetQuickAllocEntryPoints_rosalloc(qpoints, entry_points_instrumented);
-      break;
+      return;
     }
     case gc::kAllocatorTypeBumpPointer: {
       CHECK(kMovingCollector);
       SetQuickAllocEntryPoints_bump_pointer(qpoints, entry_points_instrumented);
-      break;
+      return;
     }
     case gc::kAllocatorTypeTLAB: {
       CHECK(kMovingCollector);
       SetQuickAllocEntryPoints_tlab(qpoints, entry_points_instrumented);
+      return;
+    }
+    default:
       break;
-    }
-#endif
-    default: {
-      LOG(FATAL) << "Unimplemented";
-    }
   }
+#else
+  UNUSED(qpoints);
+#endif
+  UNIMPLEMENTED(FATAL);
+  UNREACHABLE();
 }
 
 }  // namespace art
diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h
new file mode 100644
index 0000000..b7e8d50
--- /dev/null
+++ b/runtime/entrypoints/quick/quick_default_externs.h
@@ -0,0 +1,120 @@
+/*
+ * 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_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_EXTERNS_H_
+#define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_EXTERNS_H_
+
+#include <cstdint>
+
+namespace art {
+namespace mirror {
+class Array;
+class ArtMethod;
+class Class;
+class Object;
+}  // namespace mirror
+}  // namespace art
+
+// These are extern declarations of assembly stubs with common names.
+
+// Cast entrypoints.
+extern "C" void art_quick_check_cast(const art::mirror::Class*, const art::mirror::Class*);
+
+// DexCache entrypoints.
+extern "C" void* art_quick_initialize_static_storage(uint32_t, art::mirror::ArtMethod*);
+extern "C" void* art_quick_initialize_type(uint32_t, art::mirror::ArtMethod*);
+extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t, art::mirror::ArtMethod*);
+extern "C" void* art_quick_resolve_string(uint32_t, art::mirror::ArtMethod*);
+
+// Field entrypoints.
+extern "C" int art_quick_set8_instance(uint32_t, void*, int8_t);
+extern "C" int art_quick_set8_static(uint32_t, int8_t);
+extern "C" int art_quick_set16_instance(uint32_t, void*, int16_t);
+extern "C" int art_quick_set16_static(uint32_t, int16_t);
+extern "C" int art_quick_set32_instance(uint32_t, void*, int32_t);
+extern "C" int art_quick_set32_static(uint32_t, int32_t);
+extern "C" int art_quick_set64_instance(uint32_t, void*, int64_t);
+extern "C" int art_quick_set64_static(uint32_t, int64_t);
+extern "C" int art_quick_set_obj_instance(uint32_t, void*, void*);
+extern "C" int art_quick_set_obj_static(uint32_t, void*);
+extern "C" int8_t art_quick_get_byte_instance(uint32_t, void*);
+extern "C" uint8_t art_quick_get_boolean_instance(uint32_t, void*);
+extern "C" int8_t art_quick_get_byte_static(uint32_t);
+extern "C" uint8_t art_quick_get_boolean_static(uint32_t);
+extern "C" int16_t art_quick_get_short_instance(uint32_t, void*);
+extern "C" uint16_t art_quick_get_char_instance(uint32_t, void*);
+extern "C" int16_t art_quick_get_short_static(uint32_t);
+extern "C" uint16_t art_quick_get_char_static(uint32_t);
+extern "C" int32_t art_quick_get32_instance(uint32_t, void*);
+extern "C" int32_t art_quick_get32_static(uint32_t);
+extern "C" int64_t art_quick_get64_instance(uint32_t, void*);
+extern "C" int64_t art_quick_get64_static(uint32_t);
+extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
+extern "C" void* art_quick_get_obj_static(uint32_t);
+
+// Array entrypoints.
+extern "C" void art_quick_aput_obj_with_null_and_bound_check(art::mirror::Array*, int32_t,
+                                                             art::mirror::Object*);
+extern "C" void art_quick_aput_obj_with_bound_check(art::mirror::Array*, int32_t,
+                                                    art::mirror::Object*);
+extern "C" void art_quick_aput_obj(art::mirror::Array*, int32_t, art::mirror::Object*);
+extern "C" void art_quick_handle_fill_data(void*, void*);
+
+// Lock entrypoints.
+extern "C" void art_quick_lock_object(art::mirror::Object*);
+extern "C" void art_quick_unlock_object(art::mirror::Object*);
+
+// Math entrypoints.
+extern "C" int64_t art_quick_d2l(double);
+extern "C" int64_t art_quick_f2l(float);
+extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
+extern "C" int64_t art_quick_lmod(int64_t, int64_t);
+extern "C" int64_t art_quick_lmul(int64_t, int64_t);
+extern "C" uint64_t art_quick_lshl(uint64_t, uint32_t);
+extern "C" uint64_t art_quick_lshr(uint64_t, uint32_t);
+extern "C" uint64_t art_quick_lushr(uint64_t, uint32_t);
+extern "C" int64_t art_quick_mul_long(int64_t, int64_t);
+extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t);
+extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
+extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
+
+// Intrinsic entrypoints.
+extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
+extern "C" int32_t art_quick_string_compareto(void*, void*);
+extern "C" void* art_quick_memcpy(void*, const void*, size_t);
+
+// Invoke entrypoints.
+extern "C" void art_quick_imt_conflict_trampoline(art::mirror::ArtMethod*);
+extern "C" void art_quick_resolution_trampoline(art::mirror::ArtMethod*);
+extern "C" void art_quick_to_interpreter_bridge(art::mirror::ArtMethod*);
+extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
+
+// Thread entrypoints.
+extern "C" void art_quick_test_suspend();
+
+// Throw entrypoints.
+extern "C" void art_quick_deliver_exception(art::mirror::Object*);
+extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
+extern "C" void art_quick_throw_div_zero();
+extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
+extern "C" void art_quick_throw_null_pointer_exception();
+extern "C" void art_quick_throw_stack_overflow(void*);
+
+#endif  // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_EXTERNS_H_
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..348495d 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)
+extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx,
+                                                    mirror::ArtMethod* referrer,
+                                                    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_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index 8c108a8..db8c0e3 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -28,6 +28,7 @@
 namespace art {
 
 namespace mirror {
+class Array;
 class ArtMethod;
 class Class;
 class Object;
diff --git a/runtime/entrypoints/quick/quick_entrypoints_enum.h b/runtime/entrypoints/quick/quick_entrypoints_enum.h
index 84158cd..5a95491 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_enum.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_enum.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_ENUM_H_
 
 #include "quick_entrypoints.h"
+#include "quick_entrypoints_enum.h"
 #include "thread.h"
 
 namespace art {
@@ -47,10 +48,20 @@
   #undef ENTRYPOINT_ENUM
   };
   LOG(FATAL) << "Unexpected trampoline " << static_cast<int>(trampoline);
-  return ThreadOffset<pointer_size>(-1);
+  UNREACHABLE();
 }
 
-}  // namespace art
+// Do a check functions to be able to test whether the right signature is used.
+template <QuickEntrypointEnum entrypoint, typename... Types>
+void CheckEntrypointTypes();
 
+#define ENTRYPOINT_ENUM(name, ...) \
+template <> inline void CheckEntrypointTypes<kQuick ## name, __VA_ARGS__>() {};  // NOLINT [readability/braces] [4]
+#include "quick_entrypoints_list.h"
+  QUICK_ENTRYPOINT_LIST(ENTRYPOINT_ENUM)
+#undef QUICK_ENTRYPOINT_LIST
+#undef ENTRYPOINT_ENUM
+
+}  // namespace art
 
 #endif  // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_ENUM_H_
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index fbc7913..da454f3 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -20,23 +20,23 @@
 // All quick entrypoints. Format is name, return type, argument types.
 
 #define QUICK_ENTRYPOINT_LIST(V) \
-  V(AllocArray, void*, uint32_t, void*, int32_t) \
-  V(AllocArrayResolved, void*, void*, void*, int32_t) \
-  V(AllocArrayWithAccessCheck, void*, uint32_t, void*, int32_t) \
-  V(AllocObject, void*, uint32_t, void*) \
-  V(AllocObjectResolved, void*, void*, void*) \
-  V(AllocObjectInitialized, void*, void*, void*) \
-  V(AllocObjectWithAccessCheck, void*, uint32_t, void*) \
-  V(CheckAndAllocArray, void*, uint32_t, void*, int32_t) \
-  V(CheckAndAllocArrayWithAccessCheck, void*, uint32_t, void*, int32_t) \
+  V(AllocArray, void*, uint32_t, int32_t, mirror::ArtMethod*) \
+  V(AllocArrayResolved, void*, mirror::Class*, int32_t, mirror::ArtMethod*) \
+  V(AllocArrayWithAccessCheck, void*, uint32_t, int32_t, mirror::ArtMethod*) \
+  V(AllocObject, void*, uint32_t, mirror::ArtMethod*) \
+  V(AllocObjectResolved, void*, mirror::Class*, mirror::ArtMethod*) \
+  V(AllocObjectInitialized, void*, mirror::Class*, mirror::ArtMethod*) \
+  V(AllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*) \
+  V(CheckAndAllocArray, void*, uint32_t, int32_t, mirror::ArtMethod*) \
+  V(CheckAndAllocArrayWithAccessCheck, void*, uint32_t, int32_t, mirror::ArtMethod*) \
 \
   V(InstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*) \
-  V(CheckCast, void , void*, void*) \
+  V(CheckCast, void, const mirror::Class*, const mirror::Class*) \
 \
-  V(InitializeStaticStorage, void*, uint32_t, void*) \
-  V(InitializeTypeAndVerifyAccess, void*, uint32_t, void*) \
-  V(InitializeType, void*, uint32_t, void*) \
-  V(ResolveString, void*, void*, uint32_t) \
+  V(InitializeStaticStorage, void*, uint32_t, mirror::ArtMethod*) \
+  V(InitializeTypeAndVerifyAccess, void*, uint32_t, mirror::ArtMethod*) \
+  V(InitializeType, void*, uint32_t, mirror::ArtMethod*) \
+  V(ResolveString, void*, uint32_t, mirror::ArtMethod*) \
 \
   V(Set8Instance, int, uint32_t, void*, int8_t) \
   V(Set8Static, int, uint32_t, int8_t) \
@@ -63,21 +63,21 @@
   V(GetObjInstance, void*, uint32_t, void*) \
   V(GetObjStatic, void*, uint32_t) \
 \
-  V(AputObjectWithNullAndBoundCheck, void, void*, uint32_t, void*) \
-  V(AputObjectWithBoundCheck, void, void*, uint32_t, void*) \
-  V(AputObject, void, void*, uint32_t, void*) \
+  V(AputObjectWithNullAndBoundCheck, void, mirror::Array*, int32_t, mirror::Object*) \
+  V(AputObjectWithBoundCheck, void, mirror::Array*, int32_t, mirror::Object*) \
+  V(AputObject, void, mirror::Array*, int32_t, mirror::Object*) \
   V(HandleFillArrayData, void, void*, void*) \
 \
   V(JniMethodStart, uint32_t, Thread*) \
-  V(JniMethodStartSynchronized, uint32_t, jobject to_lock, Thread* self) \
-  V(JniMethodEnd, void, uint32_t cookie, Thread* self) \
-  V(JniMethodEndSynchronized, void, uint32_t cookie, jobject locked, Thread* self) \
-  V(JniMethodEndWithReference, mirror::Object*, jobject result, uint32_t cookie, Thread* self) \
-  V(JniMethodEndWithReferenceSynchronized, mirror::Object*, jobject result, uint32_t cookie, jobject locked, Thread* self) \
+  V(JniMethodStartSynchronized, uint32_t, jobject, Thread*) \
+  V(JniMethodEnd, void, uint32_t, Thread*) \
+  V(JniMethodEndSynchronized, void, uint32_t, jobject, Thread*) \
+  V(JniMethodEndWithReference, mirror::Object*, jobject, uint32_t, Thread*) \
+  V(JniMethodEndWithReferenceSynchronized, mirror::Object*, jobject, uint32_t, jobject, Thread*) \
   V(QuickGenericJniTrampoline, void, mirror::ArtMethod*) \
 \
-  V(LockObject, void, void*) \
-  V(UnlockObject, void, void*) \
+  V(LockObject, void, mirror::Object*) \
+  V(UnlockObject, void, mirror::Object*) \
 \
   V(CmpgDouble, int32_t, double, double) \
   V(CmpgFloat, int32_t, float, float) \
@@ -114,7 +114,7 @@
 \
   V(TestSuspend, void, void) \
 \
-  V(DeliverException, void, void*) \
+  V(DeliverException, void, mirror::Object*) \
   V(ThrowArrayBounds, void, int32_t, int32_t) \
   V(ThrowDivZero, void, void) \
   V(ThrowNoSuchMethod, void, int32_t) \
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 4ec2879..e336543 100644
--- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
@@ -15,49 +15,24 @@
  */
 
 #include "callee_save_frame.h"
-#include "common_throws.h"
-#include "dex_instruction.h"
 #include "mirror/array.h"
-#include "mirror/object-inl.h"
+#include "mirror/art_method-inl.h"
+#include "entrypoints/entrypoint_utils.h"
 
 namespace art {
 
 /*
- * Fill the array with predefined constant values, throwing exceptions if the array is null or
- * not of sufficient length.
- *
- * NOTE: When dealing with a raw dex file, the data to be copied uses
- * little-endian ordering.  Require that oat2dex do any required swapping
- * so this routine can get by with a memcpy().
- *
- * Format of the data:
- *  ushort ident = 0x0300   magic value
- *  ushort width            width of each element in the table
- *  uint   size             number of elements in the table
- *  ubyte  data[size*width] table of data values (may contain a single-byte
- *                          padding at the end)
+ * Handle fill array data by copying appropriate part of dex file into array.
  */
-extern "C" int artHandleFillArrayDataFromCode(mirror::Array* array,
-                                              const Instruction::ArrayDataPayload* payload,
-                                              Thread* self, StackReference<mirror::ArtMethod>* sp)
+extern "C" int artHandleFillArrayDataFromCode(uint32_t payload_offset, mirror::Array* array,
+                                              mirror::ArtMethod* method, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
-  if (UNLIKELY(array == NULL)) {
-    ThrowNullPointerException(NULL, "null array in FILL_ARRAY_DATA");
-    return -1;  // Error
-  }
-  DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
-  if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
-    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-    self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
-                             "failed FILL_ARRAY_DATA; length=%d, index=%d",
-                             array->GetLength(), payload->element_count - 1);
-    return -1;  // Error
-  }
-  uint32_t size_in_bytes = payload->element_count * payload->element_width;
-  memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
-  return 0;  // Success
+  ScopedQuickEntrypointChecks sqec(self);
+  const uint16_t* const insns = method->GetCodeItem()->insns_;
+  const Instruction::ArrayDataPayload* payload =
+      reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + payload_offset);
+  bool success = FillArrayData(array, payload);
+  return success ? 0 : -1;
 }
 
 }  // namespace art
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 49df62d..54dbd8c 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "callee_save_frame.h"
-#include "instruction_set.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "instrumentation.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
@@ -27,19 +27,17 @@
 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)) {
     result = GetQuickToInterpreterBridge();
   } else {
-    result = instrumentation->GetQuickCodeFor(method);
+    result = instrumentation->GetQuickCodeFor(method, sizeof(void*));
+    DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(result));
   }
-  DCHECK((result != Runtime::Current()->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline())
-         || !Runtime::Current()->GetHeap()->HasImageSpace());
   bool interpreter_entry = (result == GetQuickToInterpreterBridge());
   instrumentation->PushInstrumentationStackFrame(self, method->IsStatic() ? nullptr : this_object,
                                                  method, lr, interpreter_entry);
@@ -52,23 +50,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);
-  uintptr_t* return_pc = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) +
+  // 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_math_entrypoints.cc b/runtime/entrypoints/quick/quick_math_entrypoints.cc
index 014aad3..1c658b7 100644
--- a/runtime/entrypoints/quick/quick_math_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_math_entrypoints.cc
@@ -18,6 +18,11 @@
 
 namespace art {
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
 int CmplFloat(float a, float b) {
   if (a == b) {
     return 0;
@@ -62,6 +67,10 @@
   return -1;
 }
 
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
 extern "C" int64_t artLmul(int64_t a, int64_t b) {
   return a * b;
 }
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 1dbbb70..9947b55 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -19,9 +19,10 @@
 #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"
+#include "method_reference.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
@@ -49,15 +50,21 @@
   // | arg1 spill |  |
   // | Method*    | ---
   // | LR         |
-  // | ...        |    callee saves
-  // | R3         |    arg3
-  // | R2         |    arg2
-  // | R1         |    arg1
-  // | R0         |    padding
+  // | ...        |    4x6 bytes callee saves
+  // | R3         |
+  // | R2         |
+  // | R1         |
+  // | S15        |
+  // | :          |
+  // | S0         |
+  // |            |    4x2 bytes padding
   // | Method*    |  <- sp
-  static constexpr bool kQuickSoftFloatAbi = true;  // This is a soft float ABI.
-  static constexpr size_t kNumQuickGprArgs = 3;  // 3 arguments passed in GPRs.
-  static constexpr size_t kNumQuickFprArgs = 0;  // 0 arguments passed in FPRs.
+  static constexpr bool kAlignPairRegister = !kArm32QuickCodeUseSoftFloat;
+  static constexpr bool kQuickSoftFloatAbi = kArm32QuickCodeUseSoftFloat;
+  static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = !kArm32QuickCodeUseSoftFloat;
+  static constexpr size_t kNumQuickGprArgs = 3;
+  static constexpr size_t kNumQuickFprArgs = kArm32QuickCodeUseSoftFloat ? 0 : 16;
+  static constexpr bool kGprFprLockstep = false;
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset =
       arm::ArmCalleeSaveFpr1Offset(Runtime::kRefsAndArgs);  // Offset of first FPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset =
@@ -88,9 +95,12 @@
   // | D0         |
   // |            |    padding
   // | Method*    |  <- sp
+  static constexpr bool kAlignPairRegister = false;
   static constexpr bool kQuickSoftFloatAbi = false;  // This is a hard float ABI.
+  static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false;
   static constexpr size_t kNumQuickGprArgs = 7;  // 7 arguments passed in GPRs.
   static constexpr size_t kNumQuickFprArgs = 8;  // 8 arguments passed in FPRs.
+  static constexpr bool kGprFprLockstep = false;
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset =
       arm64::Arm64CalleeSaveFpr1Offset(Runtime::kRefsAndArgs);  // Offset of first FPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset =
@@ -100,7 +110,7 @@
   static size_t GprIndexToGprOffset(uint32_t gpr_index) {
     return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA);
   }
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
   // The callee save frame is pointed to by SP.
   // | argN       |  |
   // | ...        |  |
@@ -115,15 +125,65 @@
   // | A2         |    arg2
   // | A1         |    arg1
   // | A0/Method* |  <- sp
+  static constexpr bool kAlignPairRegister = false;
   static constexpr bool kQuickSoftFloatAbi = true;  // This is a soft float ABI.
+  static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false;
   static constexpr size_t kNumQuickGprArgs = 3;  // 3 arguments passed in GPRs.
   static constexpr size_t kNumQuickFprArgs = 0;  // 0 arguments passed in FPRs.
+  static constexpr bool kGprFprLockstep = false;
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0;  // Offset of first FPR arg.
-  static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4;  // Offset of first GPR arg.
+  static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 16;  // Offset of first GPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 60;  // Offset of return address.
   static size_t GprIndexToGprOffset(uint32_t gpr_index) {
     return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA);
   }
+#elif defined(__mips__) && defined(__LP64__)
+  // The callee save frame is pointed to by SP.
+  // | argN       |  |
+  // | ...        |  |
+  // | arg4       |  |
+  // | arg3 spill |  |  Caller's frame
+  // | arg2 spill |  |
+  // | arg1 spill |  |
+  // | Method*    | ---
+  // | RA         |
+  // | ...        |    callee saves
+  // | F7         |    f_arg7
+  // | F6         |    f_arg6
+  // | F5         |    f_arg5
+  // | F6         |    f_arg6
+  // | F5         |    f_arg5
+  // | F4         |    f_arg4
+  // | F3         |    f_arg3
+  // | F2         |    f_arg2
+  // | F1         |    f_arg1
+  // | F0         |    f_arg0
+  // | A7         |    arg7
+  // | A6         |    arg6
+  // | A5         |    arg5
+  // | A4         |    arg4
+  // | A3         |    arg3
+  // | A2         |    arg2
+  // | A1         |    arg1
+  // |            |    padding
+  // | A0/Method* |  <- sp
+  // NOTE: for Mip64, when A0 is skipped, F0 is also skipped.
+  static constexpr bool kAlignPairRegister = false;
+  static constexpr bool kQuickSoftFloatAbi = false;
+  static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false;
+  // These values are set to zeros because GPR and FPR register
+  // assignments for Mips64 are interleaved, which the current VisitArguments()
+  // function does not support.
+  static constexpr size_t kNumQuickGprArgs = 7;  // 7 arguments passed in GPRs.
+  static constexpr size_t kNumQuickFprArgs = 7;  // 7 arguments passed in FPRs.
+  static constexpr bool kGprFprLockstep = true;
+
+  static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 24;  // Offset of first FPR arg (F1).
+  static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 80;  // Offset of first GPR arg (A1).
+  static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 200;  // Offset of return address.
+  static size_t GprIndexToGprOffset(uint32_t gpr_index) {
+    return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA);
+  }
 #elif defined(__i386__)
   // The callee save frame is pointed to by SP.
   // | argN        |  |
@@ -139,9 +199,12 @@
   // | EDX         |    arg2
   // | ECX         |    arg1
   // | EAX/Method* |  <- sp
+  static constexpr bool kAlignPairRegister = false;
   static constexpr bool kQuickSoftFloatAbi = true;  // This is a soft float ABI.
+  static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false;
   static constexpr size_t kNumQuickGprArgs = 3;  // 3 arguments passed in GPRs.
   static constexpr size_t kNumQuickFprArgs = 0;  // 0 arguments passed in FPRs.
+  static constexpr bool kGprFprLockstep = false;
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0;  // Offset of first FPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4;  // Offset of first GPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 28;  // Offset of return address.
@@ -176,9 +239,12 @@
   // | XMM0            |    float arg 1
   // | Padding         |
   // | RDI/Method*     |  <- sp
+  static constexpr bool kAlignPairRegister = false;
   static constexpr bool kQuickSoftFloatAbi = false;  // This is a hard float ABI.
+  static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false;
   static constexpr size_t kNumQuickGprArgs = 5;  // 5 arguments passed in GPRs.
   static constexpr size_t kNumQuickFprArgs = 8;  // 8 arguments passed in FPRs.
+  static constexpr bool kGprFprLockstep = false;
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 16;  // Offset of first FPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 80 + 4*8;  // Offset of first GPR arg.
   static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 168 + 4*8;  // Offset of return address.
@@ -199,10 +265,26 @@
 #endif
 
  public:
+  // Special handling for proxy methods. Proxy methods are instance methods so the
+  // 'this' object is the 1st argument. They also have the same frame layout as the
+  // kRefAndArgs runtime method. Since 'this' is a reference, it is located in the
+  // 1st GPR.
+  static mirror::Object* GetProxyThisObject(StackReference<mirror::ArtMethod>* sp)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CHECK(sp->AsMirrorPtr()->IsProxyMethod());
+    CHECK_EQ(kQuickCalleeSaveFrame_RefAndArgs_FrameSize, sp->AsMirrorPtr()->GetFrameSizeInBytes());
+    CHECK_GT(kNumQuickGprArgs, 0u);
+    constexpr uint32_t kThisGprIndex = 0u;  // 'this' is in the 1st GPR.
+    size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset +
+        GprIndexToGprOffset(kThisGprIndex);
+    uint8_t* this_arg_address = reinterpret_cast<uint8_t*>(sp) + this_arg_offset;
+    return reinterpret_cast<StackReference<mirror::Object>*>(this_arg_address)->AsMirrorPtr();
+  }
+
   static mirror::ArtMethod* GetCallingMethod(StackReference<mirror::ArtMethod>* sp)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
-    byte* previous_sp = reinterpret_cast<byte*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize;
+    uint8_t* previous_sp = reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize;
     return reinterpret_cast<StackReference<mirror::ArtMethod>*>(previous_sp)->AsMirrorPtr();
   }
 
@@ -210,19 +292,28 @@
   static uintptr_t GetCallingPc(StackReference<mirror::ArtMethod>* sp)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
-    byte* lr = reinterpret_cast<byte*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_LrOffset;
+    uint8_t* lr = reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_LrOffset;
     return *reinterpret_cast<uintptr_t*>(lr);
   }
 
   QuickArgumentVisitor(StackReference<mirror::ArtMethod>* sp, bool is_static, const char* shorty,
                        uint32_t shorty_len) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
           is_static_(is_static), shorty_(shorty), shorty_len_(shorty_len),
-          gpr_args_(reinterpret_cast<byte*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset),
-          fpr_args_(reinterpret_cast<byte*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset),
-          stack_args_(reinterpret_cast<byte*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize
-                      + StackArgumentStartFromShorty(is_static, shorty, shorty_len)),
-          gpr_index_(0), fpr_index_(0), stack_index_(0), cur_type_(Primitive::kPrimVoid),
-          is_split_long_or_double_(false) {}
+          gpr_args_(reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset),
+          fpr_args_(reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset),
+          stack_args_(reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize
+              + sizeof(StackReference<mirror::ArtMethod>)),  // Skip StackReference<ArtMethod>.
+          gpr_index_(0), fpr_index_(0), fpr_double_index_(0), stack_index_(0),
+          cur_type_(Primitive::kPrimVoid), is_split_long_or_double_(false) {
+    static_assert(kQuickSoftFloatAbi == (kNumQuickFprArgs == 0),
+                  "Number of Quick FPR arguments unexpected");
+    static_assert(!(kQuickSoftFloatAbi && kQuickDoubleRegAlignedFloatBackFilled),
+                  "Double alignment unexpected");
+    // For register alignment, we want to assume that counters(fpr_double_index_) are even if the
+    // next register is even.
+    static_assert(!kQuickDoubleRegAlignedFloatBackFilled || kNumQuickFprArgs % 2 == 0,
+                  "Number of Quick FPR arguments not even");
+  }
 
   virtual ~QuickArgumentVisitor() {}
 
@@ -232,11 +323,15 @@
     return cur_type_;
   }
 
-  byte* GetParamAddress() const {
+  uint8_t* GetParamAddress() const {
     if (!kQuickSoftFloatAbi) {
       Primitive::Type type = GetParamPrimitiveType();
       if (UNLIKELY((type == Primitive::kPrimDouble) || (type == Primitive::kPrimFloat))) {
-        if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
+        if (type == Primitive::kPrimDouble && kQuickDoubleRegAlignedFloatBackFilled) {
+          if (fpr_double_index_ + 2 < kNumQuickFprArgs + 1) {
+            return fpr_args_ + (fpr_double_index_ * GetBytesPerFprSpillLocation(kRuntimeISA));
+          }
+        } else if (fpr_index_ + 1 < kNumQuickFprArgs + 1) {
           return fpr_args_ + (fpr_index_ * GetBytesPerFprSpillLocation(kRuntimeISA));
         }
         return stack_args_ + (stack_index_ * kBytesStackArgLocation);
@@ -266,31 +361,42 @@
   }
 
   uint64_t ReadSplitLongParam() const {
-    DCHECK(IsSplitLongOrDouble());
-    uint64_t low_half = *reinterpret_cast<uint32_t*>(GetParamAddress());
-    uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args_);
-    return (low_half & 0xffffffffULL) | (high_half << 32);
+    // The splitted long is always available through the stack.
+    return *reinterpret_cast<uint64_t*>(stack_args_
+        + stack_index_ * kBytesStackArgLocation);
+  }
+
+  void IncGprIndex() {
+    gpr_index_++;
+    if (kGprFprLockstep) {
+      fpr_index_++;
+    }
+  }
+
+  void IncFprIndex() {
+    fpr_index_++;
+    if (kGprFprLockstep) {
+      gpr_index_++;
+    }
   }
 
   void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // This implementation doesn't support reg-spill area for hard float
-    // ABI targets such as x86_64 and aarch64. So, for those targets whose
-    // 'kQuickSoftFloatAbi' is 'false':
-    //     (a) 'stack_args_' should point to the first method's argument
-    //     (b) whatever the argument type it is, the 'stack_index_' should
-    //         be moved forward along with every visiting.
+    // (a) 'stack_args_' should point to the first method's argument
+    // (b) whatever the argument type it is, the 'stack_index_' should
+    //     be moved forward along with every visiting.
     gpr_index_ = 0;
     fpr_index_ = 0;
+    if (kQuickDoubleRegAlignedFloatBackFilled) {
+      fpr_double_index_ = 0;
+    }
     stack_index_ = 0;
     if (!is_static_) {  // Handle this.
       cur_type_ = Primitive::kPrimNot;
       is_split_long_or_double_ = false;
       Visit();
-      if (!kQuickSoftFloatAbi || kNumQuickGprArgs == 0) {
-        stack_index_++;
-      }
+      stack_index_++;
       if (kNumQuickGprArgs > 0) {
-        gpr_index_++;
+        IncGprIndex();
       }
     }
     for (uint32_t shorty_index = 1; shorty_index < shorty_len_; ++shorty_index) {
@@ -304,71 +410,85 @@
         case Primitive::kPrimInt:
           is_split_long_or_double_ = false;
           Visit();
-          if (!kQuickSoftFloatAbi || kNumQuickGprArgs == gpr_index_) {
-            stack_index_++;
-          }
+          stack_index_++;
           if (gpr_index_ < kNumQuickGprArgs) {
-            gpr_index_++;
+            IncGprIndex();
           }
           break;
         case Primitive::kPrimFloat:
           is_split_long_or_double_ = false;
           Visit();
+          stack_index_++;
           if (kQuickSoftFloatAbi) {
             if (gpr_index_ < kNumQuickGprArgs) {
-              gpr_index_++;
-            } else {
-              stack_index_++;
+              IncGprIndex();
             }
           } else {
-            if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
-              fpr_index_++;
+            if (fpr_index_ + 1 < kNumQuickFprArgs + 1) {
+              IncFprIndex();
+              if (kQuickDoubleRegAlignedFloatBackFilled) {
+                // Double should not overlap with float.
+                // For example, if fpr_index_ = 3, fpr_double_index_ should be at least 4.
+                fpr_double_index_ = std::max(fpr_double_index_, RoundUp(fpr_index_, 2));
+                // Float should not overlap with double.
+                if (fpr_index_ % 2 == 0) {
+                  fpr_index_ = std::max(fpr_double_index_, fpr_index_);
+                }
+              }
             }
-            stack_index_++;
           }
           break;
         case Primitive::kPrimDouble:
         case Primitive::kPrimLong:
           if (kQuickSoftFloatAbi || (cur_type_ == Primitive::kPrimLong)) {
+            if (cur_type_ == Primitive::kPrimLong && kAlignPairRegister && gpr_index_ == 0) {
+              // Currently, this is only for ARM, where the first available parameter register
+              // is R1. So we skip it, and use R2 instead.
+              IncGprIndex();
+            }
             is_split_long_or_double_ = (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) &&
                 ((gpr_index_ + 1) == kNumQuickGprArgs);
             Visit();
-            if (!kQuickSoftFloatAbi || kNumQuickGprArgs == gpr_index_) {
-              if (kBytesStackArgLocation == 4) {
-                stack_index_+= 2;
-              } else {
-                CHECK_EQ(kBytesStackArgLocation, 8U);
-                stack_index_++;
-              }
-            }
-            if (gpr_index_ < kNumQuickGprArgs) {
-              gpr_index_++;
-              if (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) {
-                if (gpr_index_ < kNumQuickGprArgs) {
-                  gpr_index_++;
-                } else if (kQuickSoftFloatAbi) {
-                  stack_index_++;
-                }
-              }
-            }
-          } else {
-            is_split_long_or_double_ = (GetBytesPerFprSpillLocation(kRuntimeISA) == 4) &&
-                ((fpr_index_ + 1) == kNumQuickFprArgs);
-            Visit();
-            if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
-              fpr_index_++;
-              if (GetBytesPerFprSpillLocation(kRuntimeISA) == 4) {
-                if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
-                  fpr_index_++;
-                }
-              }
-            }
             if (kBytesStackArgLocation == 4) {
               stack_index_+= 2;
             } else {
               CHECK_EQ(kBytesStackArgLocation, 8U);
               stack_index_++;
             }
+            if (gpr_index_ < kNumQuickGprArgs) {
+              IncGprIndex();
+              if (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) {
+                if (gpr_index_ < kNumQuickGprArgs) {
+                  IncGprIndex();
+                }
+              }
+            }
+          } else {
+            is_split_long_or_double_ = (GetBytesPerFprSpillLocation(kRuntimeISA) == 4) &&
+                ((fpr_index_ + 1) == kNumQuickFprArgs) && !kQuickDoubleRegAlignedFloatBackFilled;
+            Visit();
+            if (kBytesStackArgLocation == 4) {
+              stack_index_+= 2;
+            } else {
+              CHECK_EQ(kBytesStackArgLocation, 8U);
+              stack_index_++;
+            }
+            if (kQuickDoubleRegAlignedFloatBackFilled) {
+              if (fpr_double_index_ + 2 < kNumQuickFprArgs + 1) {
+                fpr_double_index_ += 2;
+                // Float should not overlap with double.
+                if (fpr_index_ % 2 == 0) {
+                  fpr_index_ = std::max(fpr_double_index_, fpr_index_);
+                }
+              }
+            } else if (fpr_index_ + 1 < kNumQuickFprArgs + 1) {
+              IncFprIndex();
+              if (GetBytesPerFprSpillLocation(kRuntimeISA) == 4) {
+                if (fpr_index_ + 1 < kNumQuickFprArgs + 1) {
+                  IncFprIndex();
+                }
+              }
+            }
           }
           break;
         default:
@@ -377,32 +497,24 @@
     }
   }
 
- private:
-  static size_t StackArgumentStartFromShorty(bool is_static, const char* shorty,
-                                             uint32_t shorty_len) {
-    if (kQuickSoftFloatAbi) {
-      CHECK_EQ(kNumQuickFprArgs, 0U);
-      return (kNumQuickGprArgs * GetBytesPerGprSpillLocation(kRuntimeISA))
-          + sizeof(StackReference<mirror::ArtMethod>) /* StackReference<ArtMethod> */;
-    } else {
-      // For now, there is no reg-spill area for the targets with
-      // hard float ABI. So, the offset pointing to the first method's
-      // parameter ('this' for non-static methods) should be returned.
-      return sizeof(StackReference<mirror::ArtMethod>);  // Skip StackReference<ArtMethod>.
-    }
-  }
-
  protected:
   const bool is_static_;
   const char* const shorty_;
   const uint32_t shorty_len_;
 
  private:
-  byte* const gpr_args_;  // Address of GPR arguments in callee save frame.
-  byte* const fpr_args_;  // Address of FPR arguments in callee save frame.
-  byte* const stack_args_;  // Address of stack arguments in caller's frame.
+  uint8_t* const gpr_args_;  // Address of GPR arguments in callee save frame.
+  uint8_t* const fpr_args_;  // Address of FPR arguments in callee save frame.
+  uint8_t* const stack_args_;  // Address of stack arguments in caller's frame.
   uint32_t gpr_index_;  // Index into spilled GPRs.
-  uint32_t fpr_index_;  // Index into spilled FPRs.
+  // Index into spilled FPRs.
+  // In case kQuickDoubleRegAlignedFloatBackFilled, it may index a hole while fpr_double_index_
+  // holds a higher register number.
+  uint32_t fpr_index_;
+  // Index into spilled FPRs for aligned double.
+  // Only used when kQuickDoubleRegAlignedFloatBackFilled. Next available double register indexed in
+  // terms of singles, may be behind fpr_index.
+  uint32_t fpr_double_index_;
   uint32_t stack_index_;  // Index into arguments on the stack.
   // The current type of argument during VisitArguments.
   Primitive::Type cur_type_;
@@ -410,6 +522,13 @@
   bool is_split_long_or_double_;
 };
 
+// Returns the 'this' object of a proxy method. This function is only used by StackVisitor. It
+// allows to use the QuickArgumentVisitor constants without moving all the code in its own module.
+extern "C" mirror::Object* artQuickGetProxyThisObject(StackReference<mirror::ArtMethod>* sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return QuickArgumentVisitor::GetProxyThisObject(sp);
+}
+
 // Visits arguments on the stack placing them into the shadow frame.
 class BuildQuickShadowFrameVisitor FINAL : public QuickArgumentVisitor {
  public:
@@ -455,7 +574,7 @@
       break;
     case Primitive::kPrimVoid:
       LOG(FATAL) << "UNREACHABLE";
-      break;
+      UNREACHABLE();
   }
   ++cur_reg_;
 }
@@ -465,7 +584,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);
@@ -486,26 +605,25 @@
     BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
                                                       shadow_frame, first_arg_reg);
     shadow_frame_builder.VisitArguments();
+    const bool needs_initialization =
+        method->IsStatic() && !method->GetDeclaringClass()->IsInitialized();
     // Push a transition back into managed code onto the linked list in thread.
     ManagedStack fragment;
     self->PushManagedStackFragment(&fragment);
     self->PushShadowFrame(shadow_frame);
     self->EndAssertNoThreadSuspension(old_cause);
 
-    if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) {
+    if (needs_initialization) {
       // Ensure static method's class is initialized.
       StackHandleScope<1> hs(self);
-      Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
+      Handle<mirror::Class> h_class(hs.NewHandle(shadow_frame->GetMethod()->GetDeclaringClass()));
       if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
-        DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(method);
+        DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(shadow_frame->GetMethod());
         self->PopManagedStackFragment(fragment);
         return 0;
       }
     }
-
-    StackHandleScope<1> hs(self);
-    MethodHelper mh(hs.NewHandle(method));
-    JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
+    JValue result = interpreter::EnterInterpreterFromEntryPoint(self, 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.
@@ -564,8 +682,7 @@
       break;
     case Primitive::kPrimVoid:
       LOG(FATAL) << "UNREACHABLE";
-      val.j = 0;
-      break;
+      UNREACHABLE();
   }
   args_->push_back(val);
 }
@@ -593,7 +710,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);
@@ -620,7 +736,7 @@
 
   // Convert proxy method into expected interface method.
   mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod();
-  DCHECK(interface_method != NULL) << PrettyMethod(proxy_method);
+  DCHECK(interface_method != nullptr) << PrettyMethod(proxy_method);
   DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
   jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
 
@@ -678,7 +794,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);
@@ -689,12 +805,12 @@
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   mirror::ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
   InvokeType invoke_type;
-  const DexFile* dex_file;
-  uint32_t dex_method_idx;
-  if (called->IsRuntimeMethod()) {
+  MethodReference called_method(nullptr, 0);
+  const bool called_method_known_on_entry = !called->IsRuntimeMethod();
+  if (!called_method_known_on_entry) {
     uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
     const DexFile::CodeItem* code;
-    dex_file = caller->GetDexFile();
+    called_method.dex_file = caller->GetDexFile();
     code = caller->GetCodeItem();
     CHECK_LT(dex_pc, code->insns_size_in_code_units_);
     const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
@@ -742,33 +858,33 @@
         is_range = true;
         break;
       default:
-        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
-        // Avoid used uninitialized warnings.
-        invoke_type = kDirect;
-        is_range = false;
+        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(nullptr);
+        UNREACHABLE();
     }
-    dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
+    called_method.dex_method_index = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
   } else {
     invoke_type = kStatic;
-    dex_file = called->GetDexFile();
-    dex_method_idx = called->GetDexMethodIndex();
+    called_method.dex_file = called->GetDexFile();
+    called_method.dex_method_index = called->GetDexMethodIndex();
   }
   uint32_t shorty_len;
   const char* shorty =
-      dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
+      called_method.dex_file->GetMethodShorty(
+          called_method.dex_file->GetMethodId(called_method.dex_method_index), &shorty_len);
   RememberForGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);
   visitor.VisitArguments();
   self->EndAssertNoThreadSuspension(old_cause);
-  bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
+  const bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
   // Resolve method filling in dex cache.
-  if (UNLIKELY(called->IsRuntimeMethod())) {
+  if (!called_method_known_on_entry) {
     StackHandleScope<1> hs(self);
     mirror::Object* dummy = nullptr;
     HandleWrapper<mirror::Object> h_receiver(
         hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));
-    called = linker->ResolveMethod(self, dex_method_idx, &caller, invoke_type);
+    DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
+    called = linker->ResolveMethod(self, called_method.dex_method_index, &caller, invoke_type);
   }
-  const void* code = NULL;
+  const void* code = nullptr;
   if (LIKELY(!self->IsExceptionPending())) {
     // Incompatible class change should have been handled in resolve method.
     CHECK(!called->CheckIncompatibleClassChange(invoke_type))
@@ -789,20 +905,26 @@
                                << invoke_type << " " << orig_called->GetVtableIndex();
 
       // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
-      // of the sharpened method.
-      if (called->HasSameDexCacheResolvedMethods(caller)) {
-        caller->SetDexCacheResolvedMethod(called->GetDexMethodIndex(), called);
-      } else {
+      // of the sharpened method avoiding dirtying the dex cache if possible.
+      // Note, called_method.dex_method_index references the dex method before the
+      // FindVirtualMethodFor... This is ok for FindDexMethodIndexInOtherDexFile that only cares
+      // about the name and signature.
+      uint32_t update_dex_cache_method_index = called->GetDexMethodIndex();
+      if (!called->HasSameDexCacheResolvedMethods(caller)) {
         // Calling from one dex file to another, need to compute the method index appropriate to
         // the caller's dex file. Since we get here only if the original called was a runtime
         // method, we've got the correct dex_file and a dex_method_idx from above.
-        DCHECK_EQ(caller->GetDexFile(), dex_file);
-        StackHandleScope<1> hs(self);
-        MethodHelper mh(hs.NewHandle(called));
-        uint32_t method_index = mh.FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
-        if (method_index != DexFile::kDexNoIndex) {
-          caller->SetDexCacheResolvedMethod(method_index, called);
-        }
+        DCHECK(!called_method_known_on_entry);
+        DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
+        const DexFile* caller_dex_file = called_method.dex_file;
+        uint32_t caller_method_name_and_sig_index = called_method.dex_method_index;
+        update_dex_cache_method_index =
+            called->FindDexMethodIndexInOtherDexFile(*caller_dex_file,
+                                                     caller_method_name_and_sig_index);
+      }
+      if ((update_dex_cache_method_index != DexFile::kDexNoIndex) &&
+          (caller->GetDexCacheResolvedMethod(update_dex_cache_method_index) != called)) {
+        caller->SetDexCacheResolvedMethod(update_dex_cache_method_index, called);
       }
     }
     // Ensure that the called method's class is initialized.
@@ -824,7 +946,7 @@
       DCHECK(called_class->IsErroneous());
     }
   }
-  CHECK_EQ(code == NULL, self->IsExceptionPending());
+  CHECK_EQ(code == nullptr, self->IsExceptionPending());
   // Fixup any locally saved objects may have moved during a GC.
   visitor.FixupReferences();
   // Place called method in callee-save frame to be placed as first argument to quick method.
@@ -883,7 +1005,8 @@
   static constexpr size_t kRegistersNeededForLong = 2;
   static constexpr size_t kRegistersNeededForDouble = 2;
   static constexpr bool kMultiRegistersAligned = true;
-  static constexpr bool kMultiRegistersWidened = false;
+  static constexpr bool kMultiFPRegistersWidened = false;
+  static constexpr bool kMultiGPRegistersWidened = false;
   static constexpr bool kAlignLongOnStack = true;
   static constexpr bool kAlignDoubleOnStack = true;
 #elif defined(__aarch64__)
@@ -894,19 +1017,33 @@
   static constexpr size_t kRegistersNeededForLong = 1;
   static constexpr size_t kRegistersNeededForDouble = 1;
   static constexpr bool kMultiRegistersAligned = false;
-  static constexpr bool kMultiRegistersWidened = false;
+  static constexpr bool kMultiFPRegistersWidened = false;
+  static constexpr bool kMultiGPRegistersWidened = false;
   static constexpr bool kAlignLongOnStack = false;
   static constexpr bool kAlignDoubleOnStack = false;
-#elif defined(__mips__)
-  // TODO: These are all dummy values!
+#elif defined(__mips__) && !defined(__LP64__)
   static constexpr bool kNativeSoftFloatAbi = true;  // This is a hard float ABI.
-  static constexpr size_t kNumNativeGprArgs = 0;  // 6 arguments passed in GPRs.
-  static constexpr size_t kNumNativeFprArgs = 0;  // 8 arguments passed in FPRs.
+  static constexpr size_t kNumNativeGprArgs = 4;  // 4 arguments passed in GPRs.
+  static constexpr size_t kNumNativeFprArgs = 0;  // 0 arguments passed in FPRs.
 
   static constexpr size_t kRegistersNeededForLong = 2;
   static constexpr size_t kRegistersNeededForDouble = 2;
   static constexpr bool kMultiRegistersAligned = true;
-  static constexpr bool kMultiRegistersWidened = true;
+  static constexpr bool kMultiFPRegistersWidened = true;
+  static constexpr bool kMultiGPRegistersWidened = false;
+  static constexpr bool kAlignLongOnStack = true;
+  static constexpr bool kAlignDoubleOnStack = true;
+#elif defined(__mips__) && defined(__LP64__)
+  // Let the code prepare GPRs only and we will load the FPRs with same data.
+  static constexpr bool kNativeSoftFloatAbi = true;
+  static constexpr size_t kNumNativeGprArgs = 8;
+  static constexpr size_t kNumNativeFprArgs = 0;
+
+  static constexpr size_t kRegistersNeededForLong = 1;
+  static constexpr size_t kRegistersNeededForDouble = 1;
+  static constexpr bool kMultiRegistersAligned = false;
+  static constexpr bool kMultiFPRegistersWidened = false;
+  static constexpr bool kMultiGPRegistersWidened = true;
   static constexpr bool kAlignLongOnStack = false;
   static constexpr bool kAlignDoubleOnStack = false;
 #elif defined(__i386__)
@@ -918,7 +1055,8 @@
   static constexpr size_t kRegistersNeededForLong = 2;
   static constexpr size_t kRegistersNeededForDouble = 2;
   static constexpr bool kMultiRegistersAligned = false;  // x86 not using regs, anyways
-  static constexpr bool kMultiRegistersWidened = false;
+  static constexpr bool kMultiFPRegistersWidened = false;
+  static constexpr bool kMultiGPRegistersWidened = false;
   static constexpr bool kAlignLongOnStack = false;
   static constexpr bool kAlignDoubleOnStack = false;
 #elif defined(__x86_64__)
@@ -929,7 +1067,8 @@
   static constexpr size_t kRegistersNeededForLong = 1;
   static constexpr size_t kRegistersNeededForDouble = 1;
   static constexpr bool kMultiRegistersAligned = false;
-  static constexpr bool kMultiRegistersWidened = false;
+  static constexpr bool kMultiFPRegistersWidened = false;
+  static constexpr bool kMultiGPRegistersWidened = false;
   static constexpr bool kAlignLongOnStack = false;
   static constexpr bool kAlignDoubleOnStack = false;
 #else
@@ -944,13 +1083,13 @@
         delegate_(delegate) {
     // For register alignment, we want to assume that counters (gpr_index_, fpr_index_) are even iff
     // the next register is even; counting down is just to make the compiler happy...
-    CHECK_EQ(kNumNativeGprArgs % 2, 0U);
-    CHECK_EQ(kNumNativeFprArgs % 2, 0U);
+    static_assert(kNumNativeGprArgs % 2 == 0U, "Number of native GPR arguments not even");
+    static_assert(kNumNativeFprArgs % 2 == 0U, "Number of native FPR arguments not even");
   }
 
   virtual ~BuildNativeCallFrameStateMachine() {}
 
-  bool HavePointerGpr() {
+  bool HavePointerGpr() const {
     return gpr_index_ > 0;
   }
 
@@ -965,7 +1104,7 @@
     }
   }
 
-  bool HaveHandleScopeGpr() {
+  bool HaveHandleScopeGpr() const {
     return gpr_index_ > 0;
   }
 
@@ -981,32 +1120,42 @@
     }
   }
 
-  bool HaveIntGpr() {
+  bool HaveIntGpr() const {
     return gpr_index_ > 0;
   }
 
   void AdvanceInt(uint32_t val) {
     if (HaveIntGpr()) {
       gpr_index_--;
-      PushGpr(val);
+      if (kMultiGPRegistersWidened) {
+        DCHECK_EQ(sizeof(uintptr_t), sizeof(int64_t));
+        PushGpr(static_cast<int64_t>(bit_cast<uint32_t, int32_t>(val)));
+      } else {
+        PushGpr(val);
+      }
     } else {
       stack_entries_++;
-      PushStack(val);
+      if (kMultiGPRegistersWidened) {
+        DCHECK_EQ(sizeof(uintptr_t), sizeof(int64_t));
+        PushStack(static_cast<int64_t>(bit_cast<uint32_t, int32_t>(val)));
+      } else {
+        PushStack(val);
+      }
       gpr_index_ = 0;
     }
   }
 
-  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
@@ -1042,7 +1191,7 @@
     }
   }
 
-  bool HaveFloatFpr() {
+  bool HaveFloatFpr() const {
     return fpr_index_ > 0;
   }
 
@@ -1053,7 +1202,7 @@
       if (HaveFloatFpr()) {
         fpr_index_--;
         if (kRegistersNeededForDouble == 1) {
-          if (kMultiRegistersWidened) {
+          if (kMultiFPRegistersWidened) {
             PushFpr8(bit_cast<double, uint64_t>(val));
           } else {
             // No widening, just use the bits.
@@ -1064,7 +1213,7 @@
         }
       } else {
         stack_entries_++;
-        if (kRegistersNeededForDouble == 1 && kMultiRegistersWidened) {
+        if (kRegistersNeededForDouble == 1 && kMultiFPRegistersWidened) {
           // Need to widen before storing: Note the "double" in the template instantiation.
           // Note: We need to jump through those hoops to make the compiler happy.
           DCHECK_EQ(sizeof(uintptr_t), sizeof(uint64_t));
@@ -1077,17 +1226,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
@@ -1122,15 +1271,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_;
   }
 
@@ -1155,7 +1304,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
@@ -1169,18 +1318,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);
@@ -1192,7 +1342,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);
@@ -1205,7 +1355,9 @@
   }
 
   virtual void WalkHeader(BuildNativeCallFrameStateMachine<ComputeNativeCallFrameSize>* sm)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {}
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    UNUSED(sm);
+  }
 
   void Walk(const char* shorty, uint32_t shorty_len) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     BuildNativeCallFrameStateMachine<ComputeNativeCallFrameSize> sm(this);
@@ -1216,6 +1368,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;
@@ -1238,10 +1391,11 @@
           break;
         default:
           LOG(FATAL) << "Unexpected type: " << cur_type_ << " in " << shorty;
+          UNREACHABLE();
       }
     }
 
-    num_stack_entries_ = sm.getStackEntries();
+    num_stack_entries_ = sm.GetStackEntries();
   }
 
   void PushGpr(uintptr_t /* val */) {
@@ -1276,8 +1430,8 @@
   // is at *m = sp. Will update to point to the bottom of the save frame.
   //
   // Note: assumes ComputeAll() has been run before.
-  void LayoutCalleeSaveFrame(StackReference<mirror::ArtMethod>** m, void* sp, HandleScope** table,
-                             uint32_t* handle_scope_entries)
+  void LayoutCalleeSaveFrame(Thread* self, StackReference<mirror::ArtMethod>** m, void* sp,
+                             HandleScope** handle_scope)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::ArtMethod* method = (*m)->AsMirrorPtr();
 
@@ -1287,11 +1441,9 @@
     // We have to squeeze in the HandleScope, and relocate the method pointer.
 
     // "Free" the slot for the method.
-    sp8 += kPointerSize;  // In the callee-save frame we use a full pointer.
+    sp8 += sizeof(void*);  // In the callee-save frame we use a full pointer.
 
     // Under the callee saves put handle scope and new method stack reference.
-    *handle_scope_entries = num_handle_scope_references_;
-
     size_t handle_scope_size = HandleScope::SizeOf(num_handle_scope_references_);
     size_t scope_and_method = handle_scope_size + sizeof(StackReference<mirror::ArtMethod>);
 
@@ -1301,8 +1453,8 @@
         reinterpret_cast<uintptr_t>(sp8), kStackAlignment));
 
     uint8_t* sp8_table = sp8 + sizeof(StackReference<mirror::ArtMethod>);
-    *table = reinterpret_cast<HandleScope*>(sp8_table);
-    (*table)->SetNumberOfReferences(num_handle_scope_references_);
+    *handle_scope = HandleScope::Create(sp8_table, self->GetTopHandleScope(),
+                                        num_handle_scope_references_);
 
     // Add a slot for the method pointer, and fill it. Fix the pointer-pointer given to us.
     uint8_t* method_pointer = sp8;
@@ -1313,19 +1465,19 @@
   }
 
   // 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;
   }
 
   // Re-layout the callee-save frame (insert a handle-scope). Then add space for the cookie.
   // Returns the new bottom. Note: this may be unaligned.
-  uint8_t* LayoutJNISaveFrame(StackReference<mirror::ArtMethod>** m, void* sp, HandleScope** table,
-                              uint32_t* handle_scope_entries)
+  uint8_t* LayoutJNISaveFrame(Thread* self, StackReference<mirror::ArtMethod>** m, void* sp,
+                              HandleScope** handle_scope)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // First, fix up the layout of the callee-save frame.
     // We have to squeeze in the HandleScope, and relocate the method pointer.
-    LayoutCalleeSaveFrame(m, sp, table, handle_scope_entries);
+    LayoutCalleeSaveFrame(self, m, sp, handle_scope);
 
     // The bottom of the callee-save frame is now where the method is, *m.
     uint8_t* sp8 = reinterpret_cast<uint8_t*>(*m);
@@ -1337,14 +1489,14 @@
   }
 
   // WARNING: After this, *sp won't be pointing to the method anymore!
-  uint8_t* ComputeLayout(StackReference<mirror::ArtMethod>** m, bool is_static, const char* shorty,
-                         uint32_t shorty_len, HandleScope** table, uint32_t* handle_scope_entries,
+  uint8_t* ComputeLayout(Thread* self, StackReference<mirror::ArtMethod>** m,
+                         const char* shorty, uint32_t shorty_len, HandleScope** handle_scope,
                          uintptr_t** start_stack, uintptr_t** start_gpr, uint32_t** start_fpr)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     Walk(shorty, shorty_len);
 
     // JNI part.
-    uint8_t* sp8 = LayoutJNISaveFrame(m, reinterpret_cast<void*>(*m), table, handle_scope_entries);
+    uint8_t* sp8 = LayoutJNISaveFrame(self, m, reinterpret_cast<void*>(*m), handle_scope);
 
     sp8 = LayoutNativeCall(sp8, start_stack, start_gpr, start_fpr);
 
@@ -1412,9 +1564,9 @@
     cur_stack_arg_++;
   }
 
-  virtual uintptr_t PushHandle(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  virtual uintptr_t PushHandle(mirror::Object*) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     LOG(FATAL) << "(Non-JNI) Native call does not use handles.";
-    return 0U;
+    UNREACHABLE();
   }
 
  private:
@@ -1427,20 +1579,19 @@
 // of transitioning into native code.
 class BuildGenericJniFrameVisitor FINAL : public QuickArgumentVisitor {
  public:
-  BuildGenericJniFrameVisitor(StackReference<mirror::ArtMethod>** sp, bool is_static,
-                              const char* shorty, uint32_t shorty_len, Thread* self)
+  BuildGenericJniFrameVisitor(Thread* self, bool is_static, const char* shorty, uint32_t shorty_len,
+                              StackReference<mirror::ArtMethod>** sp)
      : QuickArgumentVisitor(*sp, is_static, shorty, shorty_len),
        jni_call_(nullptr, nullptr, nullptr, nullptr), sm_(&jni_call_) {
     ComputeGenericJniFrameSize fsc;
     uintptr_t* start_gpr_reg;
     uint32_t* start_fpr_reg;
     uintptr_t* start_stack_arg;
-    uint32_t handle_scope_entries;
-    bottom_of_used_area_ = fsc.ComputeLayout(sp, is_static, shorty, shorty_len, &handle_scope_,
-                                             &handle_scope_entries, &start_stack_arg,
+    bottom_of_used_area_ = fsc.ComputeLayout(self, sp, shorty, shorty_len,
+                                             &handle_scope_,
+                                             &start_stack_arg,
                                              &start_gpr_reg, &start_fpr_reg);
 
-    handle_scope_->SetNumberOfReferences(handle_scope_entries);
     jni_call_.Reset(start_gpr_reg, start_fpr_reg, start_stack_arg, handle_scope_);
 
     // jni environment is always first argument
@@ -1460,11 +1611,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_;
   }
 
@@ -1558,7 +1709,7 @@
       break;
     case Primitive::kPrimVoid:
       LOG(FATAL) << "UNREACHABLE";
-      break;
+      UNREACHABLE();
   }
 }
 
@@ -1611,13 +1762,13 @@
   uint32_t shorty_len = 0;
   const char* shorty = called->GetShorty(&shorty_len);
 
-  // Run the visitor.
-  BuildGenericJniFrameVisitor visitor(&sp, called->IsStatic(), shorty, shorty_len, self);
+  // 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();
 
@@ -1637,7 +1788,7 @@
   *(sp32 - 1) = cookie;
 
   // Retrieve the stored native code.
-  const void* nativeCode = called->GetNativeMethod();
+  void* nativeCode = called->GetEntryPointFromJni();
 
   // There are two cases for the content of nativeCode:
   // 1) Pointer to the native function.
@@ -1746,10 +1897,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);
@@ -1763,7 +1915,7 @@
       visitor.FixupReferences();
     }
 
-    if (UNLIKELY(method == NULL)) {
+    if (UNLIKELY(method == nullptr)) {
       CHECK(self->IsExceptionPending());
       return GetTwoWordFailureValue();  // Failure.
     }
@@ -1772,7 +1924,7 @@
   const void* code = method->GetEntryPointFromQuickCompiledCode();
 
   // When we return, the caller will branch to this address, so it had better not be 0!
-  DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method)
+  DCHECK(code != nullptr) << "Code was null in method: " << PrettyMethod(method)
                           << " location: "
                           << method->GetDexFile()->GetLocation();
 
@@ -1854,22 +2006,21 @@
                                                       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);
+    if (UNLIKELY(method == nullptr)) {
       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);
-    uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + pc_offset);
+    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.
     uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
@@ -1879,7 +2030,7 @@
     Instruction::Code instr_code = instr->Opcode();
     CHECK(instr_code == Instruction::INVOKE_INTERFACE ||
           instr_code == Instruction::INVOKE_INTERFACE_RANGE)
-        << "Unexpected call into interface trampoline: " << instr->DumpString(NULL);
+        << "Unexpected call into interface trampoline: " << instr->DumpString(nullptr);
     uint32_t dex_method_idx;
     if (instr_code == Instruction::INVOKE_INTERFACE) {
       dex_method_idx = instr->VRegB_35c();
@@ -1911,7 +2062,7 @@
   const void* code = method->GetEntryPointFromQuickCompiledCode();
 
   // When we return, the caller will branch to this address, so it had better not be 0!
-  DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method)
+  DCHECK(code != nullptr) << "Code was null in method: " << PrettyMethod(method)
                           << " location: " << method->GetDexFile()->GetLocation();
 
   return GetTwoWordSuccessValue(reinterpret_cast<uintptr_t>(code),
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
index 66ee218..85a0b99 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
@@ -34,7 +34,7 @@
     t->TransitionFromSuspendedToRunnable();  // So we can create callee-save methods.
 
     r->SetInstructionSet(isa);
-    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(type);
+    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod();
     r->SetCalleeSaveMethod(save_method, type);
 
     t->TransitionFromRunnableToSuspended(ThreadState::kNative);  // So we can shut down.
@@ -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;
   }
 };
 
@@ -95,13 +96,13 @@
 TEST_F(QuickTrampolineEntrypointsTest, ReturnPC) {
   // Ensure that the computation in callee_save_frame.h correct.
   // Note: we can only check against the kRuntimeISA, because the ArtMethod computation uses
-  // kPointerSize, which is wrong when the target bitwidth is not the same as the host's.
+  // 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..420e8db
--- /dev/null
+++ b/runtime/entrypoints/runtime_asm_entrypoints.h
@@ -0,0 +1,81 @@
+/*
+ * 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 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 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 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 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 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/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 305e5a2..1313263 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -86,201 +86,190 @@
     // TODO: Better connection. Take alignment into account.
     EXPECT_OFFSET_DIFF_GT3(Thread, tls64_.stats, tlsPtr_.card_table, 8, thread_tls64_to_tlsptr);
 
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, card_table, exception, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, exception, stack_end, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_end, managed_stack, kPointerSize);
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, card_table, exception, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, exception, stack_end, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_end, managed_stack, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, managed_stack, suspend_trigger, sizeof(ManagedStack));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, suspend_trigger, jni_env, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jni_env, self, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, self, opeer, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, opeer, jpeer, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jpeer, stack_begin, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_begin, stack_size, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, throw_location, kPointerSize);
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, suspend_trigger, jni_env, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jni_env, self, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, self, opeer, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, opeer, jpeer, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jpeer, stack_begin, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_begin, stack_size, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, throw_location, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, throw_location, stack_trace_sample, sizeof(ThrowLocation));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_trace_sample, wait_next, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, wait_next, monitor_enter_object, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_handle_scope, class_loader_override, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, class_loader_override, long_jump_context, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, long_jump_context, instrumentation_stack, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, instrumentation_stack, debug_invoke_req, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, debug_invoke_req, single_step_control, kPointerSize);
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_trace_sample, wait_next, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, wait_next, monitor_enter_object, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_handle_scope, class_loader_override, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, class_loader_override, long_jump_context, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, long_jump_context, instrumentation_stack, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, instrumentation_stack, debug_invoke_req, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, debug_invoke_req, single_step_control, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, single_step_control, deoptimization_shadow_frame,
-                        kPointerSize);
+                        sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, deoptimization_shadow_frame,
-                        shadow_frame_under_construction, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, shadow_frame_under_construction, name, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, name, pthread_self, kPointerSize);
+                        shadow_frame_under_construction, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, shadow_frame_under_construction, name, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, name, pthread_self, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, pthread_self, last_no_thread_suspension_cause,
-                        kPointerSize);
+                        sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, last_no_thread_suspension_cause, checkpoint_functions,
-                        kPointerSize);
+                        sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, checkpoint_functions, interpreter_entrypoints,
-                        kPointerSize * 3);
+                        sizeof(void*) * 3);
 
     // Skip across the entrypoints structures.
 
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_pos, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, rosalloc_runs, kPointerSize);
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_pos, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, rosalloc_runs, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, rosalloc_runs, thread_local_alloc_stack_top,
-                        kPointerSize * kNumRosAllocThreadLocalSizeBrackets);
+                        sizeof(void*) * kNumRosAllocThreadLocalSizeBrackets);
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_top, thread_local_alloc_stack_end,
-                        kPointerSize);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, kPointerSize);
+                        sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, sizeof(void*));
     EXPECT_OFFSET_DIFF(Thread, tlsPtr_.held_mutexes, Thread, wait_mutex_,
-                       kPointerSize * kLockLevelCount + kPointerSize, thread_tlsptr_end);
+                       sizeof(void*) * kLockLevelCount + sizeof(void*), thread_tlsptr_end);
   }
 
   void CheckInterpreterEntryPoints() {
     CHECKED(OFFSETOF_MEMBER(InterpreterEntryPoints, pInterpreterToInterpreterBridge) == 0,
             InterpreterEntryPoints_start_with_i2i);
     EXPECT_OFFSET_DIFFNP(InterpreterEntryPoints, pInterpreterToInterpreterBridge,
-                         pInterpreterToCompiledCodeBridge, kPointerSize);
+                         pInterpreterToCompiledCodeBridge, sizeof(void*));
     CHECKED(OFFSETOF_MEMBER(InterpreterEntryPoints, pInterpreterToCompiledCodeBridge)
-            + kPointerSize == sizeof(InterpreterEntryPoints), InterpreterEntryPoints_all);
+            + sizeof(void*) == sizeof(InterpreterEntryPoints), InterpreterEntryPoints_all);
   }
 
   void CheckJniEntryPoints() {
     CHECKED(OFFSETOF_MEMBER(JniEntryPoints, pDlsymLookup) == 0,
             JniEntryPoints_start_with_dlsymlookup);
     CHECKED(OFFSETOF_MEMBER(JniEntryPoints, pDlsymLookup)
-            + kPointerSize == sizeof(JniEntryPoints), JniEntryPoints_all);
-  }
-
-  void CheckPortableEntryPoints() {
-    CHECKED(OFFSETOF_MEMBER(PortableEntryPoints, pPortableImtConflictTrampoline) == 0,
-            PortableEntryPoints_start_with_imt);
-    EXPECT_OFFSET_DIFFNP(PortableEntryPoints, pPortableImtConflictTrampoline,
-                         pPortableResolutionTrampoline, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(PortableEntryPoints, pPortableResolutionTrampoline,
-                         pPortableToInterpreterBridge, kPointerSize);
-    CHECKED(OFFSETOF_MEMBER(PortableEntryPoints, pPortableToInterpreterBridge)
-            + kPointerSize == sizeof(PortableEntryPoints), PortableEntryPoints_all);
+            + sizeof(void*) == sizeof(JniEntryPoints), JniEntryPoints_all);
   }
 
   void CheckQuickEntryPoints() {
     CHECKED(OFFSETOF_MEMBER(QuickEntryPoints, pAllocArray) == 0,
                 QuickEntryPoints_start_with_allocarray);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArray, pAllocArrayResolved, kPointerSize);
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArray, pAllocArrayResolved, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayResolved, pAllocArrayWithAccessCheck,
-                         kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayWithAccessCheck, pAllocObject, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObject, pAllocObjectResolved, kPointerSize);
+                         sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocArrayWithAccessCheck, pAllocObject, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObject, pAllocObjectResolved, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectResolved, pAllocObjectInitialized,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectInitialized, pAllocObjectWithAccessCheck,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAllocObjectWithAccessCheck, pCheckAndAllocArray,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckAndAllocArray, pCheckAndAllocArrayWithAccessCheck,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckAndAllocArrayWithAccessCheck,
-                         pInstanceofNonTrivial, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInstanceofNonTrivial, pCheckCast, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckCast, pInitializeStaticStorage, kPointerSize);
+                         pInstanceofNonTrivial, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInstanceofNonTrivial, pCheckCast, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCheckCast, pInitializeStaticStorage, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeStaticStorage, pInitializeTypeAndVerifyAccess,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeTypeAndVerifyAccess, pInitializeType,
-                         kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeType, pResolveString, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveString, pSet8Instance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Instance, pSet8Static, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Static, pSet16Instance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet16Instance, pSet16Static, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet16Static, pSet32Instance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet32Instance, pSet32Static, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet32Static, pSet64Instance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet64Instance, pSet64Static, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet64Static, pSetObjInstance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSetObjInstance, pSetObjStatic, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSetObjStatic, pGetByteInstance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetByteInstance, pGetBooleanInstance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetBooleanInstance, pGetByteStatic, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetByteStatic, pGetBooleanStatic, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetBooleanStatic, pGetShortInstance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetShortInstance, pGetCharInstance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetCharInstance, pGetShortStatic, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetShortStatic, pGetCharStatic, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetCharStatic, pGet32Instance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet32Instance, pGet32Static, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet32Static, pGet64Instance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet64Instance, pGet64Static, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet64Static, pGetObjInstance, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetObjInstance, pGetObjStatic, kPointerSize);
+                         sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeType, pResolveString, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveString, pSet8Instance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Instance, pSet8Static, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Static, pSet16Instance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet16Instance, pSet16Static, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet16Static, pSet32Instance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet32Instance, pSet32Static, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet32Static, pSet64Instance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet64Instance, pSet64Static, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet64Static, pSetObjInstance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSetObjInstance, pSetObjStatic, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSetObjStatic, pGetByteInstance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetByteInstance, pGetBooleanInstance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetBooleanInstance, pGetByteStatic, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetByteStatic, pGetBooleanStatic, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetBooleanStatic, pGetShortInstance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetShortInstance, pGetCharInstance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetCharInstance, pGetShortStatic, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetShortStatic, pGetCharStatic, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetCharStatic, pGet32Instance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet32Instance, pGet32Static, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet32Static, pGet64Instance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet64Instance, pGet64Static, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGet64Static, pGetObjInstance, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetObjInstance, pGetObjStatic, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pGetObjStatic, pAputObjectWithNullAndBoundCheck,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObjectWithNullAndBoundCheck,
-                         pAputObjectWithBoundCheck, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObjectWithBoundCheck, pAputObject, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObject, pHandleFillArrayData, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pHandleFillArrayData, pJniMethodStart, kPointerSize);
+                         pAputObjectWithBoundCheck, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObjectWithBoundCheck, pAputObject, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAputObject, pHandleFillArrayData, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pHandleFillArrayData, pJniMethodStart, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodStart, pJniMethodStartSynchronized,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodStartSynchronized, pJniMethodEnd,
-                         kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodEnd, pJniMethodEndSynchronized, kPointerSize);
+                         sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodEnd, pJniMethodEndSynchronized, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodEndSynchronized, pJniMethodEndWithReference,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodEndWithReference,
-                         pJniMethodEndWithReferenceSynchronized, kPointerSize);
+                         pJniMethodEndWithReferenceSynchronized, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pJniMethodEndWithReferenceSynchronized,
-                         pQuickGenericJniTrampoline, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pQuickGenericJniTrampoline, pLockObject, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLockObject, pUnlockObject, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pUnlockObject, pCmpgDouble, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgDouble, pCmpgFloat, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgFloat, pCmplDouble, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplDouble, pCmplFloat, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplFloat, pFmod, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmod, pL2d, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pL2d, pFmodf, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmodf, pL2f, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pL2f, pD2iz, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pD2iz, pF2iz, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pF2iz, pIdivmod, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pIdivmod, pD2l, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pD2l, pF2l, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pF2l, pLdiv, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLdiv, pLmod, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLmod, pLmul, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLmul, pShlLong, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pShlLong, pShrLong, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pShrLong, pUshrLong, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pUshrLong, pIndexOf, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pIndexOf, pStringCompareTo, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pStringCompareTo, pMemcpy, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pMemcpy, pQuickImtConflictTrampoline, kPointerSize);
+                         pQuickGenericJniTrampoline, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pQuickGenericJniTrampoline, pLockObject, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLockObject, pUnlockObject, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pUnlockObject, pCmpgDouble, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgDouble, pCmpgFloat, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgFloat, pCmplDouble, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplDouble, pCmplFloat, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplFloat, pFmod, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmod, pL2d, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pL2d, pFmodf, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmodf, pL2f, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pL2f, pD2iz, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pD2iz, pF2iz, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pF2iz, pIdivmod, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pIdivmod, pD2l, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pD2l, pF2l, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pF2l, pLdiv, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLdiv, pLmod, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLmod, pLmul, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLmul, pShlLong, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pShlLong, pShrLong, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pShrLong, pUshrLong, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pUshrLong, pIndexOf, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pIndexOf, pStringCompareTo, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pStringCompareTo, pMemcpy, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pMemcpy, pQuickImtConflictTrampoline, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pQuickImtConflictTrampoline, pQuickResolutionTrampoline,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pQuickResolutionTrampoline, pQuickToInterpreterBridge,
-                         kPointerSize);
+                         sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pQuickToInterpreterBridge,
-                         pInvokeDirectTrampolineWithAccessCheck, kPointerSize);
+                         pInvokeDirectTrampolineWithAccessCheck, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInvokeDirectTrampolineWithAccessCheck,
-                         pInvokeInterfaceTrampolineWithAccessCheck, kPointerSize);
+                         pInvokeInterfaceTrampolineWithAccessCheck, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInvokeInterfaceTrampolineWithAccessCheck,
-                         pInvokeStaticTrampolineWithAccessCheck, kPointerSize);
+                         pInvokeStaticTrampolineWithAccessCheck, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInvokeStaticTrampolineWithAccessCheck,
-                         pInvokeSuperTrampolineWithAccessCheck, kPointerSize);
+                         pInvokeSuperTrampolineWithAccessCheck, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInvokeSuperTrampolineWithAccessCheck,
-                         pInvokeVirtualTrampolineWithAccessCheck, kPointerSize);
+                         pInvokeVirtualTrampolineWithAccessCheck, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInvokeVirtualTrampolineWithAccessCheck,
-                         pTestSuspend, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pTestSuspend, pDeliverException, kPointerSize);
+                         pTestSuspend, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pTestSuspend, pDeliverException, sizeof(void*));
 
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pDeliverException, pThrowArrayBounds, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowArrayBounds, pThrowDivZero, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowDivZero, pThrowNoSuchMethod, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowNoSuchMethod, pThrowNullPointer, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowNullPointer, pThrowStackOverflow, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowStackOverflow, pA64Load, kPointerSize);
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pA64Load, pA64Store, kPointerSize);
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pDeliverException, pThrowArrayBounds, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowArrayBounds, pThrowDivZero, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowDivZero, pThrowNoSuchMethod, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowNoSuchMethod, pThrowNullPointer, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowNullPointer, pThrowStackOverflow, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowStackOverflow, pA64Load, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pA64Load, pA64Store, sizeof(void*));
 
     CHECKED(OFFSETOF_MEMBER(QuickEntryPoints, pA64Store)
-            + kPointerSize == sizeof(QuickEntryPoints), QuickEntryPoints_all);
+            + sizeof(void*) == sizeof(QuickEntryPoints), QuickEntryPoints_all);
   }
 };
 
@@ -296,10 +285,6 @@
   CheckJniEntryPoints();
 }
 
-TEST_F(EntrypointsOrderTest, PortableEntryPoints) {
-  CheckPortableEntryPoints();
-}
-
 TEST_F(EntrypointsOrderTest, QuickEntryPoints) {
   CheckQuickEntryPoints();
 }
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 6033a5f..1770658 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -19,6 +19,7 @@
 #include "class_linker.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
+#include "dex_file-inl.h"
 #include "gtest/gtest.h"
 #include "leb128.h"
 #include "mirror/class-inl.h"
@@ -43,7 +44,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();
@@ -76,31 +77,32 @@
     const std::vector<uint8_t>& fake_mapping_data = fake_mapping_data_.GetData();
     uint32_t vmap_table_offset = sizeof(OatQuickMethodHeader) + fake_vmap_table_data.size();
     uint32_t mapping_table_offset = vmap_table_offset + fake_mapping_data.size();
-    OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
-                                       4 * kPointerSize, 0u, 0u, code_size);
+    uint32_t gc_map_offset = mapping_table_offset + fake_gc_map_.size();
+    OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
+                                       4 * sizeof(void*), 0u, 0u, code_size);
     fake_header_code_and_maps_.resize(sizeof(method_header));
     memcpy(&fake_header_code_and_maps_[0], &method_header, sizeof(method_header));
     fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
                                       fake_vmap_table_data.begin(), fake_vmap_table_data.end());
     fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
                                       fake_mapping_data.begin(), fake_mapping_data.end());
+    fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
+                                      fake_gc_map_.begin(), fake_gc_map_.end());
     fake_header_code_and_maps_.insert(fake_header_code_and_maps_.end(),
                                       fake_code_.begin(), fake_code_.end());
 
     // NOTE: Don't align the code (it will not be executed) but check that the Thumb2
     // adjustment will be a NOP, see ArtMethod::EntryPointToCodePointer().
     CHECK_EQ(mapping_table_offset & 1u, 0u);
-    const uint8_t* code_ptr = &fake_header_code_and_maps_[mapping_table_offset];
+    const uint8_t* code_ptr = &fake_header_code_and_maps_[gc_map_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]);
   }
 
   const DexFile* dex_;
@@ -122,7 +124,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,85 +165,77 @@
   ScopedObjectAccess soa(env);
 
   std::vector<uintptr_t> fake_stack;
+  Runtime* r = Runtime::Current();
+  r->SetInstructionSet(kRuntimeISA);
+  mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod();
+  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.
-    const uint32_t dex_pc = 3;
 
-    // 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
+  // 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/push fake 16byte stack frame for method f
-    fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
+  // 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(0);
-    fake_stack.push_back(0xEBAD6070);  // return pc
-
-    // Pull Method* of NULL to terminate the trace
-    fake_stack.push_back(0);
-
-    // Push null values which will become null incoming arguments.
-    fake_stack.push_back(0);
-    fake_stack.push_back(0);
-    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
-  } else {
-    // Create/push fake 20-byte shadow frame for method g
-    fake_stack.push_back(0);
-    fake_stack.push_back(0);
-    fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_));
-    fake_stack.push_back(3);
-    fake_stack.push_back(0);
-
-    // Create/push fake 20-byte shadow frame for method f
-    fake_stack.push_back(0);
-    fake_stack.push_back(0);
-    fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
-    fake_stack.push_back(3);
-    fake_stack.push_back(0);
-
-    thread->PushShadowFrame(reinterpret_cast<ShadowFrame*>(&fake_stack[5]));
-    thread->PushShadowFrame(reinterpret_cast<ShadowFrame*>(&fake_stack[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_->ToNativeQuickPc(dex_pc));  // return pc
+
+  // Create/push fake 16byte stack frame for method f
+  fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
+  fake_stack.push_back(0);
+  fake_stack.push_back(0);
+  fake_stack.push_back(0xEBAD6070);  // return pc
+
+  // Push Method* of NULL to terminate the trace
+  fake_stack.push_back(0);
+
+  // Push null values which will become null incoming arguments.
+  fake_stack.push_back(0);
+  fake_stack.push_back(0);
+  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]));
+
   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
+  thread->SetTopOfStack(nullptr);  // Disarm the assertion that no code is running when we detach.
 }
 
 }  // namespace art
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index fede2f8..94753d4 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";
@@ -165,8 +177,18 @@
 
   Thread* self = Thread::Current();
 
+  // If ART is not running, or the thread is not attached to ART pass the
+  // signal on to the next handler in the chain.
+  if (self == nullptr || Runtime::Current() == nullptr || !Runtime::Current()->IsStarted()) {
+    InvokeUserSignalHandler(sig, info, context);
+    return;
+  }
   // Now set up the nested signal handler.
 
+  // TODO: add SIGSEGV back to the nested signals when we can handle running out stack gracefully.
+  static const int handled_nested_signals[] = {SIGABRT};
+  constexpr size_t num_handled_nested_signals = arraysize(handled_nested_signals);
+
   // Release the fault manager so that it will remove the signal chain for
   // SIGSEGV and we call the real sigaction.
   fault_manager.Release();
@@ -176,33 +198,40 @@
   // Unblock the signals we allow so that they can be delivered in the signal handler.
   sigset_t sigset;
   sigemptyset(&sigset);
-  sigaddset(&sigset, SIGSEGV);
-  sigaddset(&sigset, SIGABRT);
+  for (int signal : handled_nested_signals) {
+    sigaddset(&sigset, signal);
+  }
   pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
 
   // If we get a signal in this code we want to invoke our nested signal
   // handler.
-  struct sigaction action, oldsegvaction, oldabortaction;
+  struct sigaction action;
+  struct sigaction oldactions[num_handled_nested_signals];
   action.sa_sigaction = art_nested_signal_handler;
 
   // Explicitly mask out SIGSEGV and SIGABRT from the nested signal handler.  This
   // should be the default but we definitely don't want these happening in our
   // nested signal handler.
   sigemptyset(&action.sa_mask);
-  sigaddset(&action.sa_mask, SIGSEGV);
-  sigaddset(&action.sa_mask, SIGABRT);
+  for (int signal : handled_nested_signals) {
+    sigaddset(&action.sa_mask, signal);
+  }
 
   action.sa_flags = SA_SIGINFO | SA_ONSTACK;
 #if !defined(__APPLE__) && !defined(__mips__)
   action.sa_restorer = nullptr;
 #endif
 
-  // Catch SIGSEGV and SIGABRT to invoke our nested handler
-  int e1 = sigaction(SIGSEGV, &action, &oldsegvaction);
-  int e2 = sigaction(SIGABRT, &action, &oldabortaction);
-  if (e1 != 0 || e2 != 0) {
-    LOG(ERROR) << "Unable to set up nested signal handler";
-  } else {
+  // Catch handled signals to invoke our nested handler.
+  bool success = true;
+  for (size_t i = 0; i < num_handled_nested_signals; ++i) {
+    success = sigaction(handled_nested_signals[i], &action, &oldactions[i]) == 0;
+    if (!success) {
+      PLOG(ERROR) << "Unable to set up nested signal handler";
+      break;
+    }
+  }
+  if (success) {
     // Save the current state and call the handlers.  If anything causes a signal
     // our nested signal handler will be invoked and this will longjmp to the saved
     // state.
@@ -211,8 +240,12 @@
         if (handler->Action(sig, info, context)) {
           // Restore the signal handlers, reinit the fault manager and return.  Signal was
           // handled.
-          sigaction(SIGSEGV, &oldsegvaction, nullptr);
-          sigaction(SIGABRT, &oldabortaction, nullptr);
+          for (size_t i = 0; i < num_handled_nested_signals; ++i) {
+            success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0;
+            if (!success) {
+              PLOG(ERROR) << "Unable to restore signal handler";
+            }
+          }
           fault_manager.Init();
           return;
         }
@@ -222,8 +255,12 @@
     }
 
     // Restore the signal handlers.
-    sigaction(SIGSEGV, &oldsegvaction, nullptr);
-    sigaction(SIGABRT, &oldabortaction, nullptr);
+    for (size_t i = 0; i < num_handled_nested_signals; ++i) {
+      success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0;
+      if (!success) {
+        PLOG(ERROR) << "Unable to restore signal handler";
+      }
+    }
   }
 
   // Now put the fault manager back in place.
@@ -329,7 +366,8 @@
   // at the return PC address.
   if (true || kIsDebugBuild) {
     VLOG(signals) << "looking for dex pc for return pc " << std::hex << return_pc;
-    const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method_obj);
+    const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method_obj,
+                                                                                 sizeof(void*));
     uint32_t sought_offset = return_pc - reinterpret_cast<uintptr_t>(code);
     VLOG(signals) << "pc offset: " << std::hex << sought_offset;
   }
@@ -371,7 +409,7 @@
 
 bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) {
   // Make sure that we are in the generated code, but we may not have a dex pc.
-
+  UNUSED(sig);
 #ifdef TEST_NESTED_SIGNAL
   bool in_generated_code = true;
 #else
@@ -388,7 +426,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/field_helper.cc b/runtime/field_helper.cc
deleted file mode 100644
index 5c85c46..0000000
--- a/runtime/field_helper.cc
+++ /dev/null
@@ -1,47 +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 "field_helper.h"
-
-#include "class_linker-inl.h"
-#include "dex_file.h"
-#include "mirror/dex_cache.h"
-#include "runtime.h"
-#include "thread-inl.h"
-
-namespace art {
-
-mirror::Class* FieldHelper::GetType(bool resolve) {
-  uint32_t field_index = field_->GetDexFieldIndex();
-  if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) {
-    return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
-                                                                 field_->GetTypeDescriptor());
-  }
-  const DexFile* dex_file = field_->GetDexFile();
-  const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index);
-  mirror::Class* type = field_->GetDexCache()->GetResolvedType(field_id.type_idx_);
-  if (resolve && (type == nullptr)) {
-    type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, field_.Get());
-    CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
-  }
-  return type;
-}
-
-const char* FieldHelper::GetDeclaringClassDescriptor() {
-  return field_->GetDeclaringClass()->GetDescriptor(&declaring_class_descriptor_);
-}
-
-}  // namespace art
diff --git a/runtime/field_helper.h b/runtime/field_helper.h
deleted file mode 100644
index 8097025..0000000
--- a/runtime/field_helper.h
+++ /dev/null
@@ -1,49 +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.
- */
-
-#ifndef ART_RUNTIME_FIELD_HELPER_H_
-#define ART_RUNTIME_FIELD_HELPER_H_
-
-#include "base/macros.h"
-#include "handle.h"
-#include "mirror/art_field.h"
-
-namespace art {
-
-class FieldHelper {
- public:
-  explicit FieldHelper(Handle<mirror::ArtField> f) : field_(f) {}
-
-  mirror::ArtField* GetField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return field_.Get();
-  }
-
-  mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // The returned const char* is only guaranteed to be valid for the lifetime of the FieldHelper.
-  // If you need it longer, copy it into a std::string.
-  const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
-  Handle<mirror::ArtField> field_;
-  std::string declaring_class_descriptor_;
-
-  DISALLOW_COPY_AND_ASSIGN(FieldHelper);
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_FIELD_HELPER_H_
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index 2c72ba1..929a1d2 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -213,7 +213,7 @@
     mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(T),
                                         PROT_READ | PROT_WRITE, false, &error_msg));
     CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg;
-    byte* addr = mem_map_->Begin();
+    uint8_t* addr = mem_map_->Begin();
     CHECK(addr != NULL);
     debug_is_sorted_ = true;
     begin_ = reinterpret_cast<T*>(addr);
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index 3b06f74..15562e5 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -27,9 +27,9 @@
 namespace gc {
 namespace accounting {
 
-static inline bool byte_cas(byte old_value, byte new_value, byte* address) {
+static inline bool byte_cas(uint8_t old_value, uint8_t new_value, uint8_t* address) {
 #if defined(__i386__) || defined(__x86_64__)
-  Atomic<byte>* byte_atomic = reinterpret_cast<Atomic<byte>*>(address);
+  Atomic<uint8_t>* byte_atomic = reinterpret_cast<Atomic<uint8_t>*>(address);
   return byte_atomic->CompareExchangeWeakRelaxed(old_value, new_value);
 #else
   // Little endian means most significant byte is on the left.
@@ -49,19 +49,19 @@
 }
 
 template <typename Visitor>
-inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, byte* scan_begin, byte* scan_end,
-                              const Visitor& visitor, const byte minimum_age) const {
-  DCHECK_GE(scan_begin, reinterpret_cast<byte*>(bitmap->HeapBegin()));
+inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
+                              const Visitor& visitor, const uint8_t minimum_age) const {
+  DCHECK_GE(scan_begin, reinterpret_cast<uint8_t*>(bitmap->HeapBegin()));
   // scan_end is the byte after the last byte we scan.
-  DCHECK_LE(scan_end, reinterpret_cast<byte*>(bitmap->HeapLimit()));
-  byte* card_cur = CardFromAddr(scan_begin);
-  byte* card_end = CardFromAddr(AlignUp(scan_end, kCardSize));
+  DCHECK_LE(scan_end, reinterpret_cast<uint8_t*>(bitmap->HeapLimit()));
+  uint8_t* card_cur = CardFromAddr(scan_begin);
+  uint8_t* card_end = CardFromAddr(AlignUp(scan_end, kCardSize));
   CheckCardValid(card_cur);
   CheckCardValid(card_end);
   size_t cards_scanned = 0;
 
   // Handle any unaligned cards at the start.
-  while (!IsAligned<sizeof(word)>(card_cur) && card_cur < card_end) {
+  while (!IsAligned<sizeof(intptr_t)>(card_cur) && card_cur < card_end) {
     if (*card_cur >= minimum_age) {
       uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
       bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
@@ -70,7 +70,7 @@
     ++card_cur;
   }
 
-  byte* aligned_end = card_end -
+  uint8_t* aligned_end = card_end -
       (reinterpret_cast<uintptr_t>(card_end) & (sizeof(uintptr_t) - 1));
 
   uintptr_t* word_end = reinterpret_cast<uintptr_t*>(aligned_end);
@@ -85,14 +85,14 @@
 
     // Find the first dirty card.
     uintptr_t start_word = *word_cur;
-    uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(reinterpret_cast<byte*>(word_cur)));
+    uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(reinterpret_cast<uint8_t*>(word_cur)));
     // TODO: Investigate if processing continuous runs of dirty cards with a single bitmap visit is
     // more efficient.
     for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
-      if (static_cast<byte>(start_word) >= minimum_age) {
-        auto* card = reinterpret_cast<byte*>(word_cur) + i;
-        DCHECK(*card == static_cast<byte>(start_word) || *card == kCardDirty)
-            << "card " << static_cast<size_t>(*card) << " word " << (start_word & 0xFF);
+      if (static_cast<uint8_t>(start_word) >= minimum_age) {
+        auto* card = reinterpret_cast<uint8_t*>(word_cur) + i;
+        DCHECK(*card == static_cast<uint8_t>(start_word) || *card == kCardDirty)
+            << "card " << static_cast<size_t>(*card) << " intptr_t " << (start_word & 0xFF);
         bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
         ++cards_scanned;
       }
@@ -103,7 +103,7 @@
   exit_for:
 
   // Handle any unaligned cards at the end.
-  card_cur = reinterpret_cast<byte*>(word_end);
+  card_cur = reinterpret_cast<uint8_t*>(word_end);
   while (card_cur < card_end) {
     if (*card_cur >= minimum_age) {
       uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
@@ -125,16 +125,16 @@
  * us to know which cards got cleared.
  */
 template <typename Visitor, typename ModifiedVisitor>
-inline void CardTable::ModifyCardsAtomic(byte* scan_begin, byte* scan_end, const Visitor& visitor,
+inline void CardTable::ModifyCardsAtomic(uint8_t* scan_begin, uint8_t* scan_end, const Visitor& visitor,
                                          const ModifiedVisitor& modified) {
-  byte* card_cur = CardFromAddr(scan_begin);
-  byte* card_end = CardFromAddr(AlignUp(scan_end, kCardSize));
+  uint8_t* card_cur = CardFromAddr(scan_begin);
+  uint8_t* card_end = CardFromAddr(AlignUp(scan_end, kCardSize));
   CheckCardValid(card_cur);
   CheckCardValid(card_end);
 
   // Handle any unaligned cards at the start.
-  while (!IsAligned<sizeof(word)>(card_cur) && card_cur < card_end) {
-    byte expected, new_value;
+  while (!IsAligned<sizeof(intptr_t)>(card_cur) && card_cur < card_end) {
+    uint8_t expected, new_value;
     do {
       expected = *card_cur;
       new_value = visitor(expected);
@@ -146,9 +146,9 @@
   }
 
   // Handle unaligned cards at the end.
-  while (!IsAligned<sizeof(word)>(card_end) && card_end > card_cur) {
+  while (!IsAligned<sizeof(intptr_t)>(card_end) && card_end > card_cur) {
     --card_end;
-    byte expected, new_value;
+    uint8_t expected, new_value;
     do {
       expected = *card_end;
       new_value = visitor(expected);
@@ -184,10 +184,10 @@
       Atomic<uintptr_t>* atomic_word = reinterpret_cast<Atomic<uintptr_t>*>(word_cur);
       if (LIKELY(atomic_word->CompareExchangeWeakRelaxed(expected_word, new_word))) {
         for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
-          const byte expected_byte = expected_bytes[i];
-          const byte new_byte = new_bytes[i];
+          const uint8_t expected_byte = expected_bytes[i];
+          const uint8_t new_byte = new_bytes[i];
           if (expected_byte != new_byte) {
-            modified(reinterpret_cast<byte*>(word_cur) + i, expected_byte, new_byte);
+            modified(reinterpret_cast<uint8_t*>(word_cur) + i, expected_byte, new_byte);
           }
         }
         break;
@@ -197,7 +197,7 @@
   }
 }
 
-inline void* CardTable::AddrFromCard(const byte *card_addr) const {
+inline void* CardTable::AddrFromCard(const uint8_t *card_addr) const {
   DCHECK(IsValidCard(card_addr))
     << " card_addr: " << reinterpret_cast<const void*>(card_addr)
     << " begin: " << reinterpret_cast<void*>(mem_map_->Begin() + offset_)
@@ -206,15 +206,15 @@
   return reinterpret_cast<void*>(offset << kCardShift);
 }
 
-inline byte* CardTable::CardFromAddr(const void *addr) const {
-  byte *card_addr = biased_begin_ + (reinterpret_cast<uintptr_t>(addr) >> kCardShift);
+inline uint8_t* CardTable::CardFromAddr(const void *addr) const {
+  uint8_t *card_addr = biased_begin_ + (reinterpret_cast<uintptr_t>(addr) >> kCardShift);
   // Sanity check the caller was asking for address covered by the card table
   DCHECK(IsValidCard(card_addr)) << "addr: " << addr
       << " card_addr: " << reinterpret_cast<void*>(card_addr);
   return card_addr;
 }
 
-inline void CardTable::CheckCardValid(byte* card) const {
+inline void CardTable::CheckCardValid(uint8_t* card) const {
   DCHECK(IsValidCard(card))
       << " card_addr: " << reinterpret_cast<const void*>(card)
       << " begin: " << reinterpret_cast<void*>(mem_map_->Begin() + offset_)
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 0498550..b7b6099 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -55,7 +55,7 @@
  * byte is equal to GC_DIRTY_CARD. See CardTable::Create for details.
  */
 
-CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) {
+CardTable* CardTable::Create(const uint8_t* heap_begin, size_t heap_capacity) {
   /* Set up the card table */
   size_t capacity = heap_capacity / kCardSize;
   /* Allocate an extra 256 bytes to allow fixed low-byte of base */
@@ -66,15 +66,15 @@
   CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg;
   // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we
   // don't clear the card table to avoid unnecessary pages being allocated
-  COMPILE_ASSERT(kCardClean == 0, card_clean_must_be_0);
+  static_assert(kCardClean == 0, "kCardClean must be 0");
 
-  byte* cardtable_begin = mem_map->Begin();
+  uint8_t* cardtable_begin = mem_map->Begin();
   CHECK(cardtable_begin != NULL);
 
   // We allocated up to a bytes worth of extra space to allow biased_begin's byte value to equal
   // kCardDirty, compute a offset value to make this the case
   size_t offset = 0;
-  byte* biased_begin = reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(cardtable_begin) -
+  uint8_t* biased_begin = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(cardtable_begin) -
       (reinterpret_cast<uintptr_t>(heap_begin) >> kCardShift));
   uintptr_t biased_byte = reinterpret_cast<uintptr_t>(biased_begin) & 0xff;
   if (biased_byte != kCardDirty) {
@@ -86,19 +86,19 @@
   return new CardTable(mem_map.release(), biased_begin, offset);
 }
 
-CardTable::CardTable(MemMap* mem_map, byte* biased_begin, size_t offset)
+CardTable::CardTable(MemMap* mem_map, uint8_t* biased_begin, size_t offset)
     : mem_map_(mem_map), biased_begin_(biased_begin), offset_(offset) {
 }
 
 void CardTable::ClearSpaceCards(space::ContinuousSpace* space) {
   // TODO: clear just the range of the table that has been modified
-  byte* card_start = CardFromAddr(space->Begin());
-  byte* card_end = CardFromAddr(space->End());  // Make sure to round up.
+  uint8_t* card_start = CardFromAddr(space->Begin());
+  uint8_t* card_end = CardFromAddr(space->End());  // Make sure to round up.
   memset(reinterpret_cast<void*>(card_start), kCardClean, card_end - card_start);
 }
 
 void CardTable::ClearCardTable() {
-  COMPILE_ASSERT(kCardClean == 0, clean_card_must_be_0);
+  static_assert(kCardClean == 0, "kCardClean must be 0");
   mem_map_->MadviseDontNeedAndZero();
 }
 
@@ -106,10 +106,10 @@
   return IsValidCard(biased_begin_ + ((uintptr_t)addr >> kCardShift));
 }
 
-void CardTable::CheckAddrIsInCardTable(const byte* addr) const {
-  byte* card_addr = biased_begin_ + ((uintptr_t)addr >> kCardShift);
-  byte* begin = mem_map_->Begin() + offset_;
-  byte* end = mem_map_->End();
+void CardTable::CheckAddrIsInCardTable(const uint8_t* addr) const {
+  uint8_t* card_addr = biased_begin_ + ((uintptr_t)addr >> kCardShift);
+  uint8_t* begin = mem_map_->Begin() + offset_;
+  uint8_t* end = mem_map_->End();
   CHECK(AddrIsInCardTable(addr))
       << "Card table " << this
       << " begin: " << reinterpret_cast<void*>(begin)
diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h
index fbeea85..9bd3fba 100644
--- a/runtime/gc/accounting/card_table.h
+++ b/runtime/gc/accounting/card_table.h
@@ -51,12 +51,11 @@
   static constexpr uint8_t kCardClean = 0x0;
   static constexpr uint8_t kCardDirty = 0x70;
 
-  static CardTable* Create(const byte* heap_begin, size_t heap_capacity);
+  static CardTable* Create(const uint8_t* heap_begin, size_t heap_capacity);
 
   // Set the card associated with the given address to GC_CARD_DIRTY.
-  void MarkCard(const void *addr) {
-    byte* card_addr = CardFromAddr(addr);
-    *card_addr = kCardDirty;
+  ALWAYS_INLINE void MarkCard(const void *addr) {
+    *CardFromAddr(addr) = kCardDirty;
   }
 
   // Is the object on a dirty card?
@@ -65,16 +64,16 @@
   }
 
   // Return the state of the card at an address.
-  byte GetCard(const mirror::Object* obj) const {
+  uint8_t GetCard(const mirror::Object* obj) const {
     return *CardFromAddr(obj);
   }
 
   // Visit and clear cards within memory range, only visits dirty cards.
   template <typename Visitor>
   void VisitClear(const void* start, const void* end, const Visitor& visitor) {
-    byte* card_start = CardFromAddr(start);
-    byte* card_end = CardFromAddr(end);
-    for (byte* it = card_start; it != card_end; ++it) {
+    uint8_t* card_start = CardFromAddr(start);
+    uint8_t* card_end = CardFromAddr(end);
+    for (uint8_t* it = card_start; it != card_end; ++it) {
       if (*it == kCardDirty) {
         *it = kCardClean;
         visitor(it);
@@ -84,7 +83,7 @@
 
   // Returns a value that when added to a heap address >> GC_CARD_SHIFT will address the appropriate
   // card table byte. For convenience this value is cached in every Thread
-  byte* GetBiasedBegin() const {
+  uint8_t* GetBiasedBegin() const {
     return biased_begin_;
   }
 
@@ -97,20 +96,20 @@
    * us to know which cards got cleared.
    */
   template <typename Visitor, typename ModifiedVisitor>
-  void ModifyCardsAtomic(byte* scan_begin, byte* scan_end, const Visitor& visitor,
+  void ModifyCardsAtomic(uint8_t* scan_begin, uint8_t* scan_end, const Visitor& visitor,
                          const ModifiedVisitor& modified);
 
   // For every dirty at least minumum age between begin and end invoke the visitor with the
   // specified argument. Returns how many cards the visitor was run on.
   template <typename Visitor>
-  size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, byte* scan_begin, byte* scan_end,
+  size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
               const Visitor& visitor,
-              const byte minimum_age = kCardDirty) const
+              const uint8_t minimum_age = kCardDirty) const
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Assertion used to check the given address is covered by the card table
-  void CheckAddrIsInCardTable(const byte* addr) const;
+  void CheckAddrIsInCardTable(const uint8_t* addr) const;
 
   // Resets all of the bytes in the card table to clean.
   void ClearCardTable();
@@ -119,24 +118,24 @@
   void ClearSpaceCards(space::ContinuousSpace* space);
 
   // Returns the first address in the heap which maps to this card.
-  void* AddrFromCard(const byte *card_addr) const ALWAYS_INLINE;
+  void* AddrFromCard(const uint8_t *card_addr) const ALWAYS_INLINE;
 
   // Returns the address of the relevant byte in the card table, given an address on the heap.
-  byte* CardFromAddr(const void *addr) const ALWAYS_INLINE;
+  uint8_t* CardFromAddr(const void *addr) const ALWAYS_INLINE;
 
   bool AddrIsInCardTable(const void* addr) const;
 
  private:
-  CardTable(MemMap* begin, byte* biased_begin, size_t offset);
+  CardTable(MemMap* begin, uint8_t* biased_begin, size_t offset);
 
   // Returns true iff the card table address is within the bounds of the card table.
-  bool IsValidCard(const byte* card_addr) const {
-    byte* begin = mem_map_->Begin() + offset_;
-    byte* end = mem_map_->End();
+  bool IsValidCard(const uint8_t* card_addr) const {
+    uint8_t* begin = mem_map_->Begin() + offset_;
+    uint8_t* end = mem_map_->End();
     return card_addr >= begin && card_addr < end;
   }
 
-  void CheckCardValid(byte* card) const ALWAYS_INLINE;
+  void CheckCardValid(uint8_t* card) const ALWAYS_INLINE;
 
   // Verifies that all gray objects are on a dirty card.
   void VerifyCardTable();
@@ -144,7 +143,7 @@
   // Mmapped pages for the card table
   std::unique_ptr<MemMap> mem_map_;
   // Value used to compute card table addresses from object addresses, see GetBiasedBegin
-  byte* const biased_begin_;
+  uint8_t* const biased_begin_;
   // Card table doesn't begin at the beginning of the mem_map_, instead it is displaced by offset
   // to allow the byte value of biased_begin_ to equal GC_CARD_DIRTY
   const size_t offset_;
diff --git a/runtime/gc/accounting/card_table_test.cc b/runtime/gc/accounting/card_table_test.cc
index 433855a..819cb85 100644
--- a/runtime/gc/accounting/card_table_test.cc
+++ b/runtime/gc/accounting/card_table_test.cc
@@ -49,45 +49,45 @@
     }
   }
   // Default values for the test, not random to avoid undeterministic behaviour.
-  CardTableTest() : heap_begin_(reinterpret_cast<byte*>(0x2000000)), heap_size_(2 * MB) {
+  CardTableTest() : heap_begin_(reinterpret_cast<uint8_t*>(0x2000000)), heap_size_(2 * MB) {
   }
   void ClearCardTable() {
     card_table_->ClearCardTable();
   }
-  byte* HeapBegin() const {
+  uint8_t* HeapBegin() const {
     return heap_begin_;
   }
-  byte* HeapLimit() const {
+  uint8_t* HeapLimit() const {
     return HeapBegin() + heap_size_;
   }
   // Return a pseudo random card for an address.
-  byte PseudoRandomCard(const byte* addr) const {
+  uint8_t PseudoRandomCard(const uint8_t* addr) const {
     size_t offset = RoundDown(addr - heap_begin_, CardTable::kCardSize);
     return 1 + offset % 254;
   }
   void FillRandom() {
-    for (const byte* addr = HeapBegin(); addr != HeapLimit(); addr += CardTable::kCardSize) {
+    for (const uint8_t* addr = HeapBegin(); addr != HeapLimit(); addr += CardTable::kCardSize) {
       EXPECT_TRUE(card_table_->AddrIsInCardTable(addr));
-      byte* card = card_table_->CardFromAddr(addr);
+      uint8_t* card = card_table_->CardFromAddr(addr);
       *card = PseudoRandomCard(addr);
     }
   }
 
  private:
-  byte* const heap_begin_;
+  uint8_t* const heap_begin_;
   const size_t heap_size_;
 };
 
 TEST_F(CardTableTest, TestMarkCard) {
   CommonSetup();
-  for (const byte* addr = HeapBegin(); addr < HeapLimit(); addr += kObjectAlignment) {
+  for (const uint8_t* addr = HeapBegin(); addr < HeapLimit(); addr += kObjectAlignment) {
     auto obj = reinterpret_cast<const mirror::Object*>(addr);
     EXPECT_EQ(card_table_->GetCard(obj), CardTable::kCardClean);
     EXPECT_TRUE(!card_table_->IsDirty(obj));
     card_table_->MarkCard(addr);
     EXPECT_TRUE(card_table_->IsDirty(obj));
     EXPECT_EQ(card_table_->GetCard(obj), CardTable::kCardDirty);
-    byte* card_addr = card_table_->CardFromAddr(addr);
+    uint8_t* card_addr = card_table_->CardFromAddr(addr);
     EXPECT_EQ(*card_addr, CardTable::kCardDirty);
     *card_addr = CardTable::kCardClean;
     EXPECT_EQ(*card_addr, CardTable::kCardClean);
@@ -96,10 +96,10 @@
 
 class UpdateVisitor {
  public:
-  byte operator()(byte c) const {
+  uint8_t operator()(uint8_t c) const {
     return c * 93 + 123;
   }
-  void operator()(byte* /*card*/, byte /*expected_value*/, byte /*new_value*/) const {
+  void operator()(uint8_t* /*card*/, uint8_t /*expected_value*/, uint8_t /*new_value*/) const {
   }
 };
 
@@ -110,32 +110,32 @@
                                 8U * CardTable::kCardSize);
   UpdateVisitor visitor;
   size_t start_offset = 0;
-  for (byte* cstart = HeapBegin(); cstart < HeapBegin() + delta; cstart += CardTable::kCardSize) {
+  for (uint8_t* cstart = HeapBegin(); cstart < HeapBegin() + delta; cstart += CardTable::kCardSize) {
     start_offset = (start_offset + kObjectAlignment) % CardTable::kCardSize;
     size_t end_offset = 0;
-    for (byte* cend = HeapLimit() - delta; cend < HeapLimit(); cend += CardTable::kCardSize) {
+    for (uint8_t* cend = HeapLimit() - delta; cend < HeapLimit(); cend += CardTable::kCardSize) {
       // Don't always start at a card boundary.
-      byte* start = cstart + start_offset;
-      byte* end = cend - end_offset;
+      uint8_t* start = cstart + start_offset;
+      uint8_t* end = cend - end_offset;
       end_offset = (end_offset + kObjectAlignment) % CardTable::kCardSize;
       // Modify cards.
       card_table_->ModifyCardsAtomic(start, end, visitor, visitor);
       // Check adjacent cards not modified.
-      for (byte* cur = start - CardTable::kCardSize; cur >= HeapBegin();
+      for (uint8_t* cur = start - CardTable::kCardSize; cur >= HeapBegin();
           cur -= CardTable::kCardSize) {
         EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)),
                   PseudoRandomCard(cur));
       }
-      for (byte* cur = end + CardTable::kCardSize; cur < HeapLimit();
+      for (uint8_t* cur = end + CardTable::kCardSize; cur < HeapLimit();
           cur += CardTable::kCardSize) {
         EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)),
                   PseudoRandomCard(cur));
       }
       // Verify Range.
-      for (byte* cur = start; cur < AlignUp(end, CardTable::kCardSize);
+      for (uint8_t* cur = start; cur < AlignUp(end, CardTable::kCardSize);
           cur += CardTable::kCardSize) {
-        byte* card = card_table_->CardFromAddr(cur);
-        byte value = PseudoRandomCard(cur);
+        uint8_t* card = card_table_->CardFromAddr(cur);
+        uint8_t value = PseudoRandomCard(cur);
         EXPECT_EQ(visitor(value), *card);
         // Restore for next iteration.
         *card = value;
diff --git a/runtime/gc/accounting/heap_bitmap-inl.h b/runtime/gc/accounting/heap_bitmap-inl.h
index c67542f..34c15c7 100644
--- a/runtime/gc/accounting/heap_bitmap-inl.h
+++ b/runtime/gc/accounting/heap_bitmap-inl.h
@@ -40,9 +40,9 @@
   if (LIKELY(bitmap != nullptr)) {
     return bitmap->Test(obj);
   }
-  for (const auto& bitmap : large_object_bitmaps_) {
-    if (LIKELY(bitmap->HasAddress(obj))) {
-      return bitmap->Test(obj);
+  for (const auto& lo_bitmap : large_object_bitmaps_) {
+    if (LIKELY(lo_bitmap->HasAddress(obj))) {
+      return lo_bitmap->Test(obj);
     }
   }
   LOG(FATAL) << "Invalid object " << obj;
@@ -55,9 +55,9 @@
     bitmap->Clear(obj);
     return;
   }
-  for (const auto& bitmap : large_object_bitmaps_) {
-    if (LIKELY(bitmap->HasAddress(obj))) {
-      bitmap->Clear(obj);
+  for (const auto& lo_bitmap : large_object_bitmaps_) {
+    if (LIKELY(lo_bitmap->HasAddress(obj))) {
+      lo_bitmap->Clear(obj);
     }
   }
   LOG(FATAL) << "Invalid object " << obj;
@@ -70,9 +70,9 @@
     return bitmap->Set(obj);
   }
   visitor(obj);
-  for (const auto& bitmap : large_object_bitmaps_) {
-    if (LIKELY(bitmap->HasAddress(obj))) {
-      return bitmap->Set(obj);
+  for (const auto& lo_bitmap : large_object_bitmaps_) {
+    if (LIKELY(lo_bitmap->HasAddress(obj))) {
+      return lo_bitmap->Set(obj);
     }
   }
   LOG(FATAL) << "Invalid object " << obj;
@@ -87,9 +87,9 @@
     return bitmap->AtomicTestAndSet(obj);
   }
   visitor(obj);
-  for (const auto& bitmap : large_object_bitmaps_) {
-    if (LIKELY(bitmap->HasAddress(obj))) {
-      return bitmap->AtomicTestAndSet(obj);
+  for (const auto& lo_bitmap : large_object_bitmaps_) {
+    if (LIKELY(lo_bitmap->HasAddress(obj))) {
+      return lo_bitmap->AtomicTestAndSet(obj);
     }
   }
   LOG(FATAL) << "Invalid object " << obj;
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index 3acf80d..0a15e9e 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -45,7 +45,8 @@
     : cleared_cards_(cleared_cards) {
   }
 
-  inline void operator()(byte* card, byte expected_value, byte new_value) const {
+  inline void operator()(uint8_t* card, uint8_t expected_value, uint8_t new_value) const {
+    UNUSED(new_value);
     if (expected_value == CardTable::kCardDirty) {
       cleared_cards_->insert(card);
     }
@@ -57,17 +58,18 @@
 
 class ModUnionClearCardVisitor {
  public:
-  explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
+  explicit ModUnionClearCardVisitor(std::vector<uint8_t*>* cleared_cards)
     : cleared_cards_(cleared_cards) {
   }
 
-  void operator()(byte* card, byte expected_card, byte new_card) const {
+  void operator()(uint8_t* card, uint8_t expected_card, uint8_t new_card) const {
+    UNUSED(new_card);
     if (expected_card == CardTable::kCardDirty) {
       cleared_cards_->push_back(card);
     }
   }
  private:
-  std::vector<byte*>* const cleared_cards_;
+  std::vector<uint8_t*>* const cleared_cards_;
 };
 
 class ModUnionUpdateObjectReferencesVisitor {
@@ -242,7 +244,7 @@
   CardTable* card_table = heap_->GetCardTable();
   ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
   for (const auto& ref_pair : references_) {
-    const byte* card = ref_pair.first;
+    const uint8_t* card = ref_pair.first;
     if (*card == CardTable::kCardClean) {
       std::set<const Object*> reference_set;
       for (mirror::HeapReference<Object>* obj_ptr : ref_pair.second) {
@@ -258,14 +260,14 @@
 void ModUnionTableReferenceCache::Dump(std::ostream& os) {
   CardTable* card_table = heap_->GetCardTable();
   os << "ModUnionTable cleared cards: [";
-  for (byte* card_addr : cleared_cards_) {
+  for (uint8_t* card_addr : cleared_cards_) {
     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
     uintptr_t end = start + CardTable::kCardSize;
     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
   }
   os << "]\nModUnionTable references: [";
   for (const auto& ref_pair : references_) {
-    const byte* card_addr = ref_pair.first;
+    const uint8_t* card_addr = ref_pair.first;
     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
     uintptr_t end = start + CardTable::kCardSize;
     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
@@ -349,7 +351,7 @@
 void ModUnionTableCardCache::Dump(std::ostream& os) {
   CardTable* card_table = heap_->GetCardTable();
   os << "ModUnionTable dirty cards: [";
-  for (const byte* card_addr : cleared_cards_) {
+  for (const uint8_t* card_addr : cleared_cards_) {
     auto start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
     auto end = start + CardTable::kCardSize;
     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "\n";
@@ -359,7 +361,7 @@
 
 void ModUnionTableCardCache::SetCards() {
   CardTable* card_table = heap_->GetCardTable();
-  for (byte* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
+  for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
        addr += CardTable::kCardSize) {
     cleared_cards_.insert(card_table->CardFromAddr(addr));
   }
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index d0e11e0..d6342cf 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -50,8 +50,8 @@
 // cleared between GC phases, reducing the number of dirty cards that need to be scanned.
 class ModUnionTable {
  public:
-  typedef std::set<byte*, std::less<byte*>,
-                   TrackingAllocator<byte*, kAllocatorTagModUnionCardSet>> CardSet;
+  typedef std::set<uint8_t*, std::less<uint8_t*>,
+                   TrackingAllocator<uint8_t*, kAllocatorTagModUnionCardSet>> CardSet;
 
   explicit ModUnionTable(const std::string& name, Heap* heap, space::ContinuousSpace* space)
       : name_(name),
@@ -131,7 +131,7 @@
   ModUnionTable::CardSet cleared_cards_;
 
   // Maps from dirty cards to their corresponding alloc space references.
-  AllocationTrackingSafeMap<const byte*, std::vector<mirror::HeapReference<mirror::Object>*>,
+  AllocationTrackingSafeMap<const uint8_t*, std::vector<mirror::HeapReference<mirror::Object>*>,
                             kAllocatorTagModUnionReferenceArray> references_;
 };
 
diff --git a/runtime/gc/accounting/remembered_set.cc b/runtime/gc/accounting/remembered_set.cc
index 3ff5874..b16a146 100644
--- a/runtime/gc/accounting/remembered_set.cc
+++ b/runtime/gc/accounting/remembered_set.cc
@@ -42,7 +42,8 @@
   explicit RememberedSetCardVisitor(RememberedSet::CardSet* const dirty_cards)
       : dirty_cards_(dirty_cards) {}
 
-  void operator()(byte* card, byte expected_value, byte new_value) const {
+  void operator()(uint8_t* card, uint8_t expected_value, uint8_t new_value) const {
+    UNUSED(new_value);
     if (expected_value == CardTable::kCardDirty) {
       dirty_cards_->insert(card);
     }
@@ -129,7 +130,7 @@
                                          &contains_reference_to_target_space, arg);
   ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
   CardSet remove_card_set;
-  for (byte* const card_addr : dirty_cards_) {
+  for (uint8_t* const card_addr : dirty_cards_) {
     contains_reference_to_target_space = false;
     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
     DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)));
@@ -145,7 +146,7 @@
 
   // Remove the cards that didn't contain a reference to the target
   // space from the dirty card set.
-  for (byte* const card_addr : remove_card_set) {
+  for (uint8_t* const card_addr : remove_card_set) {
     DCHECK(dirty_cards_.find(card_addr) != dirty_cards_.end());
     dirty_cards_.erase(card_addr);
   }
@@ -154,7 +155,7 @@
 void RememberedSet::Dump(std::ostream& os) {
   CardTable* card_table = heap_->GetCardTable();
   os << "RememberedSet dirty cards: [";
-  for (const byte* card_addr : dirty_cards_) {
+  for (const uint8_t* card_addr : dirty_cards_) {
     auto start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
     auto end = start + CardTable::kCardSize;
     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "\n";
@@ -164,8 +165,8 @@
 
 void RememberedSet::AssertAllDirtyCardsAreWithinSpace() const {
   CardTable* card_table = heap_->GetCardTable();
-  for (const byte* card_addr : dirty_cards_) {
-    auto start = reinterpret_cast<byte*>(card_table->AddrFromCard(card_addr));
+  for (const uint8_t* card_addr : dirty_cards_) {
+    auto start = reinterpret_cast<uint8_t*>(card_table->AddrFromCard(card_addr));
     auto end = start + CardTable::kCardSize;
     DCHECK_LE(space_->Begin(), start);
     DCHECK_LE(end, space_->Limit());
diff --git a/runtime/gc/accounting/remembered_set.h b/runtime/gc/accounting/remembered_set.h
index 8d66e0e..c51e26d 100644
--- a/runtime/gc/accounting/remembered_set.h
+++ b/runtime/gc/accounting/remembered_set.h
@@ -43,8 +43,8 @@
 // from the free list spaces to the bump pointer spaces.
 class RememberedSet {
  public:
-  typedef std::set<byte*, std::less<byte*>,
-                   TrackingAllocator<byte*, kAllocatorTagRememberedSet>> CardSet;
+  typedef std::set<uint8_t*, std::less<uint8_t*>,
+                   TrackingAllocator<uint8_t*, kAllocatorTagRememberedSet>> CardSet;
 
   explicit RememberedSet(const std::string& name, Heap* heap, space::ContinuousSpace* space)
       : name_(name), heap_(heap), space_(space) {}
diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h
index fc4213e..11347a5 100644
--- a/runtime/gc/accounting/space_bitmap-inl.h
+++ b/runtime/gc/accounting/space_bitmap-inl.h
@@ -35,10 +35,10 @@
   DCHECK_GE(addr, heap_begin_);
   const uintptr_t offset = addr - heap_begin_;
   const size_t index = OffsetToIndex(offset);
-  const uword mask = OffsetToMask(offset);
-  Atomic<uword>* atomic_entry = reinterpret_cast<Atomic<uword>*>(&bitmap_begin_[index]);
-  DCHECK_LT(index, bitmap_size_ / kWordSize) << " bitmap_size_ = " << bitmap_size_;
-  uword old_word;
+  const uintptr_t mask = OffsetToMask(offset);
+  Atomic<uintptr_t>* atomic_entry = reinterpret_cast<Atomic<uintptr_t>*>(&bitmap_begin_[index]);
+  DCHECK_LT(index, bitmap_size_ / sizeof(intptr_t)) << " bitmap_size_ = " << bitmap_size_;
+  uintptr_t old_word;
   do {
     old_word = atomic_entry->LoadRelaxed();
     // Fast path: The bit is already set.
@@ -82,8 +82,8 @@
   const uintptr_t index_start = OffsetToIndex(offset_start);
   const uintptr_t index_end = OffsetToIndex(offset_end);
 
-  const size_t bit_start = (offset_start / kAlignment) % kBitsPerWord;
-  const size_t bit_end = (offset_end / kAlignment) % kBitsPerWord;
+  const size_t bit_start = (offset_start / kAlignment) % kBitsPerIntPtrT;
+  const size_t bit_end = (offset_end / kAlignment) % kBitsPerIntPtrT;
 
   // Index(begin)  ...    Index(end)
   // [xxxxx???][........][????yyyy]
@@ -93,12 +93,12 @@
   //
 
   // Left edge.
-  uword left_edge = bitmap_begin_[index_start];
+  uintptr_t left_edge = bitmap_begin_[index_start];
   // Mark of lower bits that are not in range.
-  left_edge &= ~((static_cast<uword>(1) << bit_start) - 1);
+  left_edge &= ~((static_cast<uintptr_t>(1) << bit_start) - 1);
 
   // Right edge. Either unique, or left_edge.
-  uword right_edge;
+  uintptr_t right_edge;
 
   if (index_start < index_end) {
     // Left edge != right edge.
@@ -110,20 +110,20 @@
         const size_t shift = CTZ(left_edge);
         mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);
         visitor(obj);
-        left_edge ^= (static_cast<uword>(1)) << shift;
+        left_edge ^= (static_cast<uintptr_t>(1)) << shift;
       } while (left_edge != 0);
     }
 
     // Traverse the middle, full part.
     for (size_t i = index_start + 1; i < index_end; ++i) {
-      uword w = bitmap_begin_[i];
+      uintptr_t w = bitmap_begin_[i];
       if (w != 0) {
         const uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;
         do {
           const size_t shift = CTZ(w);
           mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);
           visitor(obj);
-          w ^= (static_cast<uword>(1)) << shift;
+          w ^= (static_cast<uintptr_t>(1)) << shift;
         } while (w != 0);
       }
     }
@@ -142,14 +142,14 @@
   }
 
   // Right edge handling.
-  right_edge &= ((static_cast<uword>(1) << bit_end) - 1);
+  right_edge &= ((static_cast<uintptr_t>(1) << bit_end) - 1);
   if (right_edge != 0) {
     const uintptr_t ptr_base = IndexToOffset(index_end) + heap_begin_;
     do {
       const size_t shift = CTZ(right_edge);
       mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);
       visitor(obj);
-      right_edge ^= (static_cast<uword>(1)) << shift;
+      right_edge ^= (static_cast<uintptr_t>(1)) << shift;
     } while (right_edge != 0);
   }
 #endif
@@ -161,10 +161,10 @@
   DCHECK_GE(addr, heap_begin_);
   const uintptr_t offset = addr - heap_begin_;
   const size_t index = OffsetToIndex(offset);
-  const uword mask = OffsetToMask(offset);
-  DCHECK_LT(index, bitmap_size_ / kWordSize) << " bitmap_size_ = " << bitmap_size_;
-  uword* address = &bitmap_begin_[index];
-  uword old_word = *address;
+  const uintptr_t mask = OffsetToMask(offset);
+  DCHECK_LT(index, bitmap_size_ / sizeof(intptr_t)) << " bitmap_size_ = " << bitmap_size_;
+  uintptr_t* address = &bitmap_begin_[index];
+  uintptr_t old_word = *address;
   if (kSetBit) {
     *address = old_word | mask;
   } else {
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 39d1f9e..f5d3b47 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -17,6 +17,7 @@
 #include "space_bitmap-inl.h"
 
 #include "base/stringprintf.h"
+#include "dex_file-inl.h"
 #include "mem_map.h"
 #include "mirror/object-inl.h"
 #include "mirror/class.h"
@@ -29,21 +30,21 @@
 
 template<size_t kAlignment>
 size_t SpaceBitmap<kAlignment>::ComputeBitmapSize(uint64_t capacity) {
-  const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerWord;
-  return (RoundUp(capacity, kBytesCoveredPerWord) / kBytesCoveredPerWord) * kWordSize;
+  const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerIntPtrT;
+  return (RoundUp(capacity, kBytesCoveredPerWord) / kBytesCoveredPerWord) * sizeof(intptr_t);
 }
 
 template<size_t kAlignment>
 SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::CreateFromMemMap(
-    const std::string& name, MemMap* mem_map, byte* heap_begin, size_t heap_capacity) {
+    const std::string& name, MemMap* mem_map, uint8_t* heap_begin, size_t heap_capacity) {
   CHECK(mem_map != nullptr);
-  uword* bitmap_begin = reinterpret_cast<uword*>(mem_map->Begin());
+  uintptr_t* bitmap_begin = reinterpret_cast<uintptr_t*>(mem_map->Begin());
   const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
   return new SpaceBitmap(name, mem_map, bitmap_begin, bitmap_size, heap_begin);
 }
 
 template<size_t kAlignment>
-SpaceBitmap<kAlignment>::SpaceBitmap(const std::string& name, MemMap* mem_map, uword* bitmap_begin,
+SpaceBitmap<kAlignment>::SpaceBitmap(const std::string& name, MemMap* mem_map, uintptr_t* bitmap_begin,
                                      size_t bitmap_size, const void* heap_begin)
     : mem_map_(mem_map), bitmap_begin_(bitmap_begin), bitmap_size_(bitmap_size),
       heap_begin_(reinterpret_cast<uintptr_t>(heap_begin)),
@@ -57,7 +58,7 @@
 
 template<size_t kAlignment>
 SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create(
-    const std::string& name, byte* heap_begin, size_t heap_capacity) {
+    const std::string& name, uint8_t* heap_begin, size_t heap_capacity) {
   // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord.
   const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
   std::string error_msg;
@@ -72,8 +73,8 @@
 
 template<size_t kAlignment>
 void SpaceBitmap<kAlignment>::SetHeapLimit(uintptr_t new_end) {
-  DCHECK(IsAligned<kBitsPerWord * kAlignment>(new_end));
-  size_t new_size = OffsetToIndex(new_end - heap_begin_) * kWordSize;
+  DCHECK(IsAligned<kBitsPerIntPtrT * kAlignment>(new_end));
+  size_t new_size = OffsetToIndex(new_end - heap_begin_) * sizeof(intptr_t);
   if (new_size < bitmap_size_) {
     bitmap_size_ = new_size;
   }
@@ -97,7 +98,7 @@
 template<size_t kAlignment>
 void SpaceBitmap<kAlignment>::CopyFrom(SpaceBitmap* source_bitmap) {
   DCHECK_EQ(Size(), source_bitmap->Size());
-  std::copy(source_bitmap->Begin(), source_bitmap->Begin() + source_bitmap->Size() / kWordSize, Begin());
+  std::copy(source_bitmap->Begin(), source_bitmap->Begin() + source_bitmap->Size() / sizeof(intptr_t), Begin());
 }
 
 template<size_t kAlignment>
@@ -106,16 +107,16 @@
   CHECK(callback != NULL);
 
   uintptr_t end = OffsetToIndex(HeapLimit() - heap_begin_ - 1);
-  uword* bitmap_begin = bitmap_begin_;
+  uintptr_t* bitmap_begin = bitmap_begin_;
   for (uintptr_t i = 0; i <= end; ++i) {
-    uword w = bitmap_begin[i];
+    uintptr_t w = bitmap_begin[i];
     if (w != 0) {
       uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;
       do {
         const size_t shift = CTZ(w);
         mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);
         (*callback)(obj, arg);
-        w ^= (static_cast<uword>(1)) << shift;
+        w ^= (static_cast<uintptr_t>(1)) << shift;
       } while (w != 0);
     }
   }
@@ -139,7 +140,7 @@
   }
 
   // TODO: rewrite the callbacks to accept a std::vector<mirror::Object*> rather than a mirror::Object**?
-  constexpr size_t buffer_size = kWordSize * kBitsPerWord;
+  constexpr size_t buffer_size = sizeof(intptr_t) * kBitsPerIntPtrT;
 #ifdef __LP64__
   // Heap-allocate for smaller stack frame.
   std::unique_ptr<mirror::Object*[]> pointer_buf_ptr(new mirror::Object*[buffer_size]);
@@ -152,21 +153,21 @@
 
   size_t start = OffsetToIndex(sweep_begin - live_bitmap.heap_begin_);
   size_t end = OffsetToIndex(sweep_end - live_bitmap.heap_begin_ - 1);
-  CHECK_LT(end, live_bitmap.Size() / kWordSize);
-  uword* live = live_bitmap.bitmap_begin_;
-  uword* mark = mark_bitmap.bitmap_begin_;
+  CHECK_LT(end, live_bitmap.Size() / sizeof(intptr_t));
+  uintptr_t* live = live_bitmap.bitmap_begin_;
+  uintptr_t* mark = mark_bitmap.bitmap_begin_;
   for (size_t i = start; i <= end; i++) {
-    uword garbage = live[i] & ~mark[i];
+    uintptr_t garbage = live[i] & ~mark[i];
     if (UNLIKELY(garbage != 0)) {
       uintptr_t ptr_base = IndexToOffset(i) + live_bitmap.heap_begin_;
       do {
         const size_t shift = CTZ(garbage);
-        garbage ^= (static_cast<uword>(1)) << shift;
+        garbage ^= (static_cast<uintptr_t>(1)) << shift;
         *pb++ = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);
       } while (garbage != 0);
       // Make sure that there are always enough slots available for an
       // entire word of one bits.
-      if (pb >= &pointer_buf[buffer_size - kBitsPerWord]) {
+      if (pb >= &pointer_buf[buffer_size - kBitsPerIntPtrT]) {
         (*callback)(pb - &pointer_buf[0], &pointer_buf[0], arg);
         pb = &pointer_buf[0];
       }
@@ -245,21 +246,21 @@
 template<size_t kAlignment>
 void SpaceBitmap<kAlignment>::InOrderWalk(ObjectCallback* callback, void* arg) {
   std::unique_ptr<SpaceBitmap<kAlignment>> visited(
-      Create("bitmap for in-order walk", reinterpret_cast<byte*>(heap_begin_),
-             IndexToOffset(bitmap_size_ / kWordSize)));
+      Create("bitmap for in-order walk", reinterpret_cast<uint8_t*>(heap_begin_),
+             IndexToOffset(bitmap_size_ / sizeof(intptr_t))));
   CHECK(bitmap_begin_ != nullptr);
   CHECK(callback != nullptr);
-  uintptr_t end = Size() / kWordSize;
+  uintptr_t end = Size() / sizeof(intptr_t);
   for (uintptr_t i = 0; i < end; ++i) {
     // Need uint for unsigned shift.
-    uword w = bitmap_begin_[i];
+    uintptr_t w = bitmap_begin_[i];
     if (UNLIKELY(w != 0)) {
       uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;
       while (w != 0) {
         const size_t shift = CTZ(w);
         mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment);
         WalkFieldsInOrder(visited.get(), callback, obj, arg);
-        w ^= (static_cast<uword>(1)) << shift;
+        w ^= (static_cast<uintptr_t>(1)) << shift;
       }
     }
   }
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index f72b30f..7bc83ef 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -45,13 +45,13 @@
 
   // Initialize a space bitmap so that it points to a bitmap large enough to cover a heap at
   // heap_begin of heap_capacity bytes, where objects are guaranteed to be kAlignment-aligned.
-  static SpaceBitmap* Create(const std::string& name, byte* heap_begin, size_t heap_capacity);
+  static SpaceBitmap* Create(const std::string& name, uint8_t* heap_begin, size_t heap_capacity);
 
   // Initialize a space bitmap using the provided mem_map as the live bits. Takes ownership of the
   // mem map. The address range covered starts at heap_begin and is of size equal to heap_capacity.
   // Objects are kAlignement-aligned.
   static SpaceBitmap* CreateFromMemMap(const std::string& name, MemMap* mem_map,
-                                       byte* heap_begin, size_t heap_capacity);
+                                       uint8_t* heap_begin, size_t heap_capacity);
 
   ~SpaceBitmap();
 
@@ -59,17 +59,17 @@
   // <index> is the index of .bits that contains the bit representing
   //         <offset>.
   static constexpr size_t OffsetToIndex(size_t offset) {
-    return offset / kAlignment / kBitsPerWord;
+    return offset / kAlignment / kBitsPerIntPtrT;
   }
 
   template<typename T>
   static constexpr T IndexToOffset(T index) {
-    return static_cast<T>(index * kAlignment * kBitsPerWord);
+    return static_cast<T>(index * kAlignment * kBitsPerIntPtrT);
   }
 
   // Bits are packed in the obvious way.
-  static constexpr uword OffsetToMask(uintptr_t offset) {
-    return (static_cast<size_t>(1)) << ((offset / kAlignment) % kBitsPerWord);
+  static constexpr uintptr_t OffsetToMask(uintptr_t offset) {
+    return (static_cast<size_t>(1)) << ((offset / kAlignment) % kBitsPerIntPtrT);
   }
 
   bool Set(const mirror::Object* obj) ALWAYS_INLINE {
@@ -95,7 +95,7 @@
     // bitmap.
     const uintptr_t offset = reinterpret_cast<uintptr_t>(obj) - heap_begin_;
     const size_t index = OffsetToIndex(offset);
-    return index < bitmap_size_ / kWordSize;
+    return index < bitmap_size_ / sizeof(intptr_t);
   }
 
   void VisitRange(uintptr_t base, uintptr_t max, ObjectCallback* callback, void* arg) const;
@@ -146,7 +146,7 @@
   void CopyFrom(SpaceBitmap* source_bitmap);
 
   // Starting address of our internal storage.
-  uword* Begin() {
+  uintptr_t* Begin() {
     return bitmap_begin_;
   }
 
@@ -157,7 +157,13 @@
 
   // Size in bytes of the memory that the bitmaps spans.
   uint64_t HeapSize() const {
-    return IndexToOffset<uint64_t>(Size() / kWordSize);
+    return IndexToOffset<uint64_t>(Size() / sizeof(intptr_t));
+  }
+
+  void SetHeapSize(size_t bytes) {
+    // TODO: Un-map the end of the mem map.
+    bitmap_size_ = OffsetToIndex(bytes) * sizeof(intptr_t);
+    CHECK_EQ(HeapSize(), bytes);
   }
 
   uintptr_t HeapBegin() const {
@@ -192,7 +198,7 @@
  private:
   // TODO: heap_end_ is initialized so that the heap bitmap is empty, this doesn't require the -1,
   // however, we document that this is expected on heap_end_
-  SpaceBitmap(const std::string& name, MemMap* mem_map, uword* bitmap_begin, size_t bitmap_size,
+  SpaceBitmap(const std::string& name, MemMap* mem_map, uintptr_t* bitmap_begin, size_t bitmap_size,
               const void* heap_begin);
 
   // Helper function for computing bitmap size based on a 64 bit capacity.
@@ -214,7 +220,7 @@
   std::unique_ptr<MemMap> mem_map_;
 
   // This bitmap itself, word sized for efficiency in scanning.
-  uword* const bitmap_begin_;
+  uintptr_t* const bitmap_begin_;
 
   // Size of this bitmap.
   size_t bitmap_size_;
diff --git a/runtime/gc/accounting/space_bitmap_test.cc b/runtime/gc/accounting/space_bitmap_test.cc
index a30bb25..850325a 100644
--- a/runtime/gc/accounting/space_bitmap_test.cc
+++ b/runtime/gc/accounting/space_bitmap_test.cc
@@ -30,7 +30,7 @@
 class SpaceBitmapTest : public CommonRuntimeTest {};
 
 TEST_F(SpaceBitmapTest, Init) {
-  byte* heap_begin = reinterpret_cast<byte*>(0x10000000);
+  uint8_t* heap_begin = reinterpret_cast<uint8_t*>(0x10000000);
   size_t heap_capacity = 16 * MB;
   std::unique_ptr<ContinuousSpaceBitmap> space_bitmap(
       ContinuousSpaceBitmap::Create("test bitmap", heap_begin, heap_capacity));
@@ -51,21 +51,21 @@
     EXPECT_EQ(bitmap_->Test(obj), ((reinterpret_cast<uintptr_t>(obj) & 0xF) != 0));
   }
 
-  ContinuousSpaceBitmap* bitmap_;
+  ContinuousSpaceBitmap* const bitmap_;
   const mirror::Object* begin_;
   const mirror::Object* end_;
 };
 
 TEST_F(SpaceBitmapTest, ScanRange) {
-  byte* heap_begin = reinterpret_cast<byte*>(0x10000000);
+  uint8_t* heap_begin = reinterpret_cast<uint8_t*>(0x10000000);
   size_t heap_capacity = 16 * MB;
 
   std::unique_ptr<ContinuousSpaceBitmap> space_bitmap(
       ContinuousSpaceBitmap::Create("test bitmap", heap_begin, heap_capacity));
   EXPECT_TRUE(space_bitmap.get() != NULL);
 
-  // Set all the odd bits in the first BitsPerWord * 3 to one.
-  for (size_t j = 0; j < kBitsPerWord * 3; ++j) {
+  // Set all the odd bits in the first BitsPerIntPtrT * 3 to one.
+  for (size_t j = 0; j < kBitsPerIntPtrT * 3; ++j) {
     const mirror::Object* obj =
         reinterpret_cast<mirror::Object*>(heap_begin + j * kObjectAlignment);
     if (reinterpret_cast<uintptr_t>(obj) & 0xF) {
@@ -76,10 +76,10 @@
   // possible length up to a maximum of kBitsPerWord * 2 - 1 bits.
   // This handles all the cases, having runs which start and end on the same word, and different
   // words.
-  for (size_t i = 0; i < static_cast<size_t>(kBitsPerWord); ++i) {
+  for (size_t i = 0; i < static_cast<size_t>(kBitsPerIntPtrT); ++i) {
     mirror::Object* start =
         reinterpret_cast<mirror::Object*>(heap_begin + i * kObjectAlignment);
-    for (size_t j = 0; j < static_cast<size_t>(kBitsPerWord * 2); ++j) {
+    for (size_t j = 0; j < static_cast<size_t>(kBitsPerIntPtrT * 2); ++j) {
       mirror::Object* end =
           reinterpret_cast<mirror::Object*>(heap_begin + (i + j) * kObjectAlignment);
       BitmapVerify(space_bitmap.get(), start, end);
@@ -91,11 +91,11 @@
  public:
   explicit SimpleCounter(size_t* counter) : count_(counter) {}
 
-  void operator()(mirror::Object* obj) const {
+  void operator()(mirror::Object* obj ATTRIBUTE_UNUSED) const {
     (*count_)++;
   }
 
-  size_t* count_;
+  size_t* const count_;
 };
 
 class RandGen {
@@ -112,7 +112,7 @@
 
 template <size_t kAlignment>
 void RunTest() NO_THREAD_SAFETY_ANALYSIS {
-  byte* heap_begin = reinterpret_cast<byte*>(0x10000000);
+  uint8_t* heap_begin = reinterpret_cast<uint8_t*>(0x10000000);
   size_t heap_capacity = 16 * MB;
 
   // Seed with 0x1234 for reproducability.
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index a6a3ee7..8558f96 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -19,8 +19,8 @@
 #include "base/logging.h"
 
 // ART specific morecore implementation defined in space.cc.
+static void* art_heap_morecore(void* m, intptr_t increment);
 #define MORECORE(x) art_heap_morecore(m, x)
-extern "C" void* art_heap_morecore(void* m, intptr_t increment);
 
 // Custom heap error handling.
 #define PROCEED_ON_ERROR 0
@@ -31,19 +31,24 @@
 
 // Ugly inclusion of C file so that ART specific #defines configure dlmalloc for our use for
 // mspaces (regular dlmalloc is still declared in bionic).
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
 #pragma GCC diagnostic ignored "-Wempty-body"
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
 #include "../../../bionic/libc/upstream-dlmalloc/malloc.c"
-#pragma GCC diagnostic warning "-Wstrict-aliasing"
-#pragma GCC diagnostic warning "-Wempty-body"
+#pragma GCC diagnostic pop
 
+static void* art_heap_morecore(void* m, intptr_t increment) {
+  return ::art::gc::allocator::ArtDlMallocMoreCore(m, increment);
+}
 
 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,14 +68,16 @@
     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;
   }
 }
 
-extern "C" void DlmallocBytesAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg) {
+extern "C" void DlmallocBytesAllocatedCallback(void* start ATTRIBUTE_UNUSED,
+                                               void* end ATTRIBUTE_UNUSED, size_t used_bytes,
+                                               void* arg) {
   if (used_bytes == 0) {
     return;
   }
@@ -78,7 +85,10 @@
   *bytes_allocated += used_bytes + sizeof(size_t);
 }
 
-extern "C" void DlmallocObjectsAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg) {
+extern "C" void DlmallocObjectsAllocatedCallback(void* start, void* end, size_t used_bytes,
+                                                 void* arg) {
+  UNUSED(start);
+  UNUSED(end);
   if (used_bytes == 0) {
     return;
   }
diff --git a/runtime/gc/allocator/dlmalloc.h b/runtime/gc/allocator/dlmalloc.h
index c820b19..0e91a43 100644
--- a/runtime/gc/allocator/dlmalloc.h
+++ b/runtime/gc/allocator/dlmalloc.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_GC_ALLOCATOR_DLMALLOC_H_
 #define ART_RUNTIME_GC_ALLOCATOR_DLMALLOC_H_
 
+#include <cstdint>
+
 // Configure dlmalloc for mspaces.
 // Avoid a collision with one used in llvm.
 #undef HAVE_MMAP
@@ -28,12 +30,17 @@
 #define ONLY_MSPACES 1
 #define MALLOC_INSPECT_ALL 1
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
 #include "../../bionic/libc/upstream-dlmalloc/malloc.h"
+#pragma GCC diagnostic pop
 
+#ifdef HAVE_ANDROID_OS
 // Define dlmalloc routines from bionic that cannot be included directly because of redefining
 // symbols from the include above.
 extern "C" void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), void* arg);
 extern "C" int  dlmalloc_trim(size_t);
+#endif
 
 // Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
 // pages back to the kernel.
@@ -45,4 +52,16 @@
 extern "C" void DlmallocBytesAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg);
 extern "C" void DlmallocObjectsAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg);
 
+namespace art {
+namespace gc {
+namespace allocator {
+
+// Callback from dlmalloc when it needs to increase the footprint. Must be implemented somewhere
+// else (currently dlmalloc_space.cc).
+void* ArtDlMallocMoreCore(void* mspace, intptr_t increment);
+
+}  // namespace allocator
+}  // namespace gc
+}  // namespace art
+
 #endif  // ART_RUNTIME_GC_ALLOCATOR_DLMALLOC_H_
diff --git a/runtime/gc/allocator/rosalloc-inl.h b/runtime/gc/allocator/rosalloc-inl.h
index c69ca48..f6c9d3c 100644
--- a/runtime/gc/allocator/rosalloc-inl.h
+++ b/runtime/gc/allocator/rosalloc-inl.h
@@ -23,6 +23,10 @@
 namespace gc {
 namespace allocator {
 
+inline ALWAYS_INLINE bool RosAlloc::ShouldCheckZeroMemory() {
+  return kCheckZeroMemory && !running_on_valgrind_;
+}
+
 template<bool kThreadSafe>
 inline ALWAYS_INLINE void* RosAlloc::Alloc(Thread* self, size_t size, size_t* bytes_allocated) {
   if (UNLIKELY(size > kLargeSizeThreshold)) {
@@ -35,8 +39,8 @@
     m = AllocFromRunThreadUnsafe(self, size, bytes_allocated);
   }
   // Check if the returned memory is really all zero.
-  if (kCheckZeroMemory && m != nullptr) {
-    byte* bytes = reinterpret_cast<byte*>(m);
+  if (ShouldCheckZeroMemory() && m != nullptr) {
+    uint8_t* bytes = reinterpret_cast<uint8_t*>(m);
     for (size_t i = 0; i < size; ++i) {
       DCHECK_EQ(bytes[i], 0);
     }
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index a7e5e74..7c2474f 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -14,24 +14,25 @@
  * limitations under the License.
  */
 
+#include "rosalloc.h"
+
 #include "base/mutex-inl.h"
+#include "gc/space/valgrind_settings.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
 #include "mirror/object-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
-#include "rosalloc.h"
 
 #include <map>
 #include <list>
+#include <sstream>
 #include <vector>
 
 namespace art {
 namespace gc {
 namespace allocator {
 
-extern "C" void* art_heap_rosalloc_morecore(RosAlloc* rosalloc, intptr_t increment);
-
 static constexpr bool kUsePrefetchDuringAllocRun = true;
 static constexpr bool kPrefetchNewRunDataByZeroing = false;
 static constexpr size_t kPrefetchStride = 64;
@@ -48,13 +49,15 @@
     reinterpret_cast<RosAlloc::Run*>(dedicated_full_run_storage_);
 
 RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity,
-                   PageReleaseMode page_release_mode, size_t page_release_size_threshold)
-    : base_(reinterpret_cast<byte*>(base)), footprint_(capacity),
+                   PageReleaseMode page_release_mode, bool running_on_valgrind,
+                   size_t page_release_size_threshold)
+    : base_(reinterpret_cast<uint8_t*>(base)), footprint_(capacity),
       capacity_(capacity), max_capacity_(max_capacity),
       lock_("rosalloc global lock", kRosAllocGlobalLock),
       bulk_free_lock_("rosalloc bulk free lock", kRosAllocBulkFreeLock),
       page_release_mode_(page_release_mode),
-      page_release_size_threshold_(page_release_size_threshold) {
+      page_release_size_threshold_(page_release_size_threshold),
+      running_on_valgrind_(running_on_valgrind) {
   DCHECK_EQ(RoundUp(capacity, kPageSize), capacity);
   DCHECK_EQ(RoundUp(max_capacity, kPageSize), max_capacity);
   CHECK_LE(capacity, max_capacity);
@@ -107,7 +110,7 @@
   }
 }
 
-void* RosAlloc::AllocPages(Thread* self, size_t num_pages, byte page_map_type) {
+void* RosAlloc::AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type) {
   lock_.AssertHeld(self);
   DCHECK(page_map_type == kPageMapRun || page_map_type == kPageMapLargeObject);
   FreePageRun* res = NULL;
@@ -128,7 +131,7 @@
       }
       if (req_byte_size < fpr_byte_size) {
         // Split.
-        FreePageRun* remainder = reinterpret_cast<FreePageRun*>(reinterpret_cast<byte*>(fpr) + req_byte_size);
+        FreePageRun* remainder = reinterpret_cast<FreePageRun*>(reinterpret_cast<uint8_t*>(fpr) + req_byte_size);
         if (kIsDebugBuild) {
           remainder->magic_num_ = kMagicNumFree;
         }
@@ -178,7 +181,7 @@
       page_map_size_ = new_num_of_pages;
       DCHECK_LE(page_map_size_, max_page_map_size_);
       free_page_run_size_map_.resize(new_num_of_pages);
-      art_heap_rosalloc_morecore(this, increment);
+      ArtRosAllocMoreCore(this, increment);
       if (last_free_page_run_size > 0) {
         // There was a free page run at the end. Expand its size.
         DCHECK_EQ(last_free_page_run_size, last_free_page_run->ByteSize(this));
@@ -226,7 +229,7 @@
       }
       if (req_byte_size < fpr_byte_size) {
         // Split if there's a remainder.
-        FreePageRun* remainder = reinterpret_cast<FreePageRun*>(reinterpret_cast<byte*>(fpr) + req_byte_size);
+        FreePageRun* remainder = reinterpret_cast<FreePageRun*>(reinterpret_cast<uint8_t*>(fpr) + req_byte_size);
         if (kIsDebugBuild) {
           remainder->magic_num_ = kMagicNumFree;
         }
@@ -264,7 +267,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) {
@@ -290,9 +293,9 @@
   lock_.AssertHeld(self);
   size_t pm_idx = ToPageMapIndex(ptr);
   DCHECK_LT(pm_idx, page_map_size_);
-  byte pm_type = page_map_[pm_idx];
+  uint8_t pm_type = page_map_[pm_idx];
   DCHECK(pm_type == kPageMapRun || pm_type == kPageMapLargeObject);
-  byte pm_part_type;
+  uint8_t pm_part_type;
   switch (pm_type) {
   case kPageMapRun:
     pm_part_type = kPageMapRunPart;
@@ -318,9 +321,9 @@
   }
   const size_t byte_size = num_pages * kPageSize;
   if (already_zero) {
-    if (kCheckZeroMemory) {
-      const uword* word_ptr = reinterpret_cast<uword*>(ptr);
-      for (size_t i = 0; i < byte_size / sizeof(uword); ++i) {
+    if (ShouldCheckZeroMemory()) {
+      const uintptr_t* word_ptr = reinterpret_cast<uintptr_t*>(ptr);
+      for (size_t i = 0; i < byte_size / sizeof(uintptr_t); ++i) {
         CHECK_EQ(word_ptr[i], 0U) << "words don't match at index " << i;
       }
     }
@@ -472,10 +475,10 @@
               << "(" << std::dec << (num_pages * kPageSize) << ")";
   }
   // Check if the returned memory is really all zero.
-  if (kCheckZeroMemory) {
-    CHECK_EQ(total_bytes % sizeof(uword), 0U);
-    const uword* words = reinterpret_cast<uword*>(r);
-    for (size_t i = 0; i < total_bytes / sizeof(uword); ++i) {
+  if (ShouldCheckZeroMemory()) {
+    CHECK_EQ(total_bytes % sizeof(uintptr_t), 0U);
+    const uintptr_t* words = reinterpret_cast<uintptr_t*>(r);
+    for (size_t i = 0; i < total_bytes / sizeof(uintptr_t); ++i) {
       CHECK_EQ(words[i], 0U);
     }
   }
@@ -490,7 +493,7 @@
   {
     MutexLock mu(self, lock_);
     DCHECK_LT(pm_idx, page_map_size_);
-    byte page_map_entry = page_map_[pm_idx];
+    uint8_t page_map_entry = page_map_[pm_idx];
     if (kTraceRosAlloc) {
       LOG(INFO) << "RosAlloc::FreeInternal() : " << std::hex << ptr << ", pm_idx=" << std::dec << pm_idx
                 << ", page_map_entry=" << static_cast<int>(page_map_entry);
@@ -499,7 +502,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.
@@ -507,19 +510,18 @@
           --pm_idx;
           DCHECK_LT(pm_idx, capacity_ / kPageSize);
         } while (page_map_[pm_idx] != kPageMapRun);
-        // Fall-through.
+        FALLTHROUGH_INTENDED;
       case kPageMapRun:
         run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
         DCHECK_EQ(run->magic_num_, kMagicNum);
         break;
       case kPageMapReleased:
-        // Fall-through.
       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;
     }
   }
@@ -557,7 +559,7 @@
         const size_t num_of_slots = numOfSlots[idx];
         const size_t bracket_size = bracketSizes[idx];
         const size_t num_of_bytes = num_of_slots * bracket_size;
-        byte* begin = reinterpret_cast<byte*>(new_run) + headerSizes[idx];
+        uint8_t* begin = reinterpret_cast<uint8_t*>(new_run) + headerSizes[idx];
         for (size_t i = 0; i < num_of_bytes; i += kPrefetchStride) {
           __builtin_prefetch(begin + i);
         }
@@ -745,7 +747,7 @@
   const size_t idx = run->size_bracket_idx_;
   const size_t bracket_size = bracketSizes[idx];
   bool run_was_full = false;
-  MutexLock mu(self, *size_bracket_locks_[idx]);
+  MutexLock brackets_mu(self, *size_bracket_locks_[idx]);
   if (kIsDebugBuild) {
     run_was_full = run->IsFull();
   }
@@ -785,7 +787,7 @@
     DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end());
     run->ZeroHeader();
     {
-      MutexLock mu(self, lock_);
+      MutexLock lock_mu(self, lock_);
       FreePages(self, run, true);
     }
   } else {
@@ -869,7 +871,7 @@
       DCHECK_EQ(*alloc_bitmap_ptr & mask, 0U);
       *alloc_bitmap_ptr |= mask;
       DCHECK_NE(*alloc_bitmap_ptr & mask, 0U);
-      byte* slot_addr = reinterpret_cast<byte*>(this) + headerSizes[idx] + slot_idx * bracketSizes[idx];
+      uint8_t* slot_addr = reinterpret_cast<uint8_t*>(this) + headerSizes[idx] + slot_idx * bracketSizes[idx];
       if (kTraceRosAlloc) {
         LOG(INFO) << "RosAlloc::Run::AllocSlot() : 0x" << std::hex << reinterpret_cast<intptr_t>(slot_addr)
                   << ", bracket_size=" << std::dec << bracketSizes[idx] << ", slot_idx=" << slot_idx;
@@ -889,10 +891,10 @@
 
 void RosAlloc::Run::FreeSlot(void* ptr) {
   DCHECK(!IsThreadLocal());
-  const byte idx = size_bracket_idx_;
+  const uint8_t idx = size_bracket_idx_;
   const size_t bracket_size = bracketSizes[idx];
-  const size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
-      - (reinterpret_cast<byte*>(this) + headerSizes[idx]);
+  const size_t offset_from_slot_base = reinterpret_cast<uint8_t*>(ptr)
+      - (reinterpret_cast<uint8_t*>(this) + headerSizes[idx]);
   DCHECK_EQ(offset_from_slot_base % bracket_size, static_cast<size_t>(0));
   size_t slot_idx = offset_from_slot_base / bracket_size;
   DCHECK_LT(slot_idx, numOfSlots[idx]);
@@ -1001,9 +1003,9 @@
 
 inline size_t RosAlloc::Run::MarkFreeBitMapShared(void* ptr, uint32_t* free_bit_map_base,
                                                   const char* caller_name) {
-  const byte idx = size_bracket_idx_;
-  const size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
-      - (reinterpret_cast<byte*>(this) + headerSizes[idx]);
+  const uint8_t idx = size_bracket_idx_;
+  const size_t offset_from_slot_base = reinterpret_cast<uint8_t*>(ptr)
+      - (reinterpret_cast<uint8_t*>(this) + headerSizes[idx]);
   const size_t bracket_size = bracketSizes[idx];
   memset(ptr, 0, bracket_size);
   DCHECK_EQ(offset_from_slot_base % bracket_size, static_cast<size_t>(0));
@@ -1037,7 +1039,7 @@
 }
 
 inline bool RosAlloc::Run::IsAllFree() {
-  const byte idx = size_bracket_idx_;
+  const uint8_t idx = size_bracket_idx_;
   const size_t num_slots = numOfSlots[idx];
   const size_t num_vec = NumberOfBitmapVectors();
   DCHECK_NE(num_vec, 0U);
@@ -1095,13 +1097,13 @@
 }
 
 inline void RosAlloc::Run::ZeroHeader() {
-  const byte idx = size_bracket_idx_;
+  const uint8_t idx = size_bracket_idx_;
   memset(this, 0, headerSizes[idx]);
 }
 
 inline void RosAlloc::Run::ZeroData() {
-  const byte idx = size_bracket_idx_;
-  byte* slot_begin = reinterpret_cast<byte*>(this) + headerSizes[idx];
+  const uint8_t idx = size_bracket_idx_;
+  uint8_t* slot_begin = reinterpret_cast<uint8_t*>(this) + headerSizes[idx];
   memset(slot_begin, 0, numOfSlots[idx] * bracketSizes[idx]);
 }
 
@@ -1114,10 +1116,10 @@
 void RosAlloc::Run::InspectAllSlots(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg),
                                     void* arg) {
   size_t idx = size_bracket_idx_;
-  byte* slot_base = reinterpret_cast<byte*>(this) + headerSizes[idx];
+  uint8_t* slot_base = reinterpret_cast<uint8_t*>(this) + headerSizes[idx];
   size_t num_slots = numOfSlots[idx];
   size_t bracket_size = IndexToBracketSize(idx);
-  DCHECK_EQ(slot_base + num_slots * bracket_size, reinterpret_cast<byte*>(this) + numOfPages[idx] * kPageSize);
+  DCHECK_EQ(slot_base + num_slots * bracket_size, reinterpret_cast<uint8_t*>(this) + numOfPages[idx] * kPageSize);
   size_t num_vec = RoundUp(num_slots, 32) / 32;
   size_t slots = 0;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
@@ -1126,7 +1128,7 @@
     size_t end = std::min(num_slots - slots, static_cast<size_t>(32));
     for (size_t i = 0; i < end; ++i) {
       bool is_allocated = ((vec >> i) & 0x1) != 0;
-      byte* slot_addr = slot_base + (slots + i) * bracket_size;
+      uint8_t* slot_addr = slot_base + (slots + i) * bracket_size;
       if (is_allocated) {
         handler(slot_addr, slot_addr + bracket_size, bracket_size, arg);
       } else {
@@ -1144,7 +1146,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]);
@@ -1169,7 +1171,7 @@
     Run* run = nullptr;
     if (kReadPageMapEntryWithoutLockInBulkFree) {
       // Read the page map entries without locking the lock.
-      byte page_map_entry = page_map_[pm_idx];
+      uint8_t page_map_entry = page_map_[pm_idx];
       if (kTraceRosAlloc) {
         LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
                   << std::dec << pm_idx
@@ -1190,13 +1192,13 @@
         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.
       MutexLock mu(self, lock_);
       DCHECK_LT(pm_idx, page_map_size_);
-      byte page_map_entry = page_map_[pm_idx];
+      uint8_t page_map_entry = page_map_[pm_idx];
       if (kTraceRosAlloc) {
         LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
                   << std::dec << pm_idx
@@ -1216,7 +1218,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);
@@ -1243,7 +1245,7 @@
     run->to_be_bulk_freed_ = false;
 #endif
     size_t idx = run->size_bracket_idx_;
-    MutexLock mu(self, *size_bracket_locks_[idx]);
+    MutexLock brackets_mu(self, *size_bracket_locks_[idx]);
     if (run->IsThreadLocal()) {
       DCHECK_LT(run->size_bracket_idx_, kNumThreadLocalSizeBrackets);
       DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
@@ -1303,7 +1305,7 @@
         }
         if (!run_was_current) {
           run->ZeroHeader();
-          MutexLock mu(self, lock_);
+          MutexLock lock_mu(self, lock_);
           FreePages(self, run, true);
         }
       } else {
@@ -1354,7 +1356,7 @@
   size_t remaining_curr_fpr_size = 0;
   size_t num_running_empty_pages = 0;
   for (size_t i = 0; i < end; ++i) {
-    byte pm = page_map_[i];
+    uint8_t pm = page_map_[i];
     switch (pm) {
       case kPageMapReleased:
         // Fall-through.
@@ -1435,7 +1437,7 @@
   return stream.str();
 }
 
-size_t RosAlloc::UsableSize(void* ptr) {
+size_t RosAlloc::UsableSize(const void* ptr) {
   DCHECK_LE(base_, ptr);
   DCHECK_LT(ptr, base_ + footprint_);
   size_t pm_idx = RoundDownToPageMapIndex(ptr);
@@ -1472,13 +1474,13 @@
       Run* run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
       DCHECK_EQ(run->magic_num_, kMagicNum);
       size_t idx = run->size_bracket_idx_;
-      size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
-          - (reinterpret_cast<byte*>(run) + headerSizes[idx]);
+      size_t offset_from_slot_base = reinterpret_cast<const uint8_t*>(ptr)
+          - (reinterpret_cast<uint8_t*>(run) + headerSizes[idx]);
       DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0));
       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;
     }
   }
@@ -1503,8 +1505,8 @@
     size_t new_num_of_pages = new_footprint / kPageSize;
     DCHECK_GE(page_map_size_, new_num_of_pages);
     // Zero out the tail of the page map.
-    byte* zero_begin = const_cast<byte*>(page_map_) + new_num_of_pages;
-    byte* madvise_begin = AlignUp(zero_begin, kPageSize);
+    uint8_t* zero_begin = const_cast<uint8_t*>(page_map_) + new_num_of_pages;
+    uint8_t* madvise_begin = AlignUp(zero_begin, kPageSize);
     DCHECK_LE(madvise_begin, page_map_mem_map_->End());
     size_t madvise_size = page_map_mem_map_->End() - madvise_begin;
     if (madvise_size > 0) {
@@ -1521,7 +1523,7 @@
     page_map_size_ = new_num_of_pages;
     free_page_run_size_map_.resize(new_num_of_pages);
     DCHECK_EQ(free_page_run_size_map_.size(), new_num_of_pages);
-    art_heap_rosalloc_morecore(this, -(static_cast<intptr_t>(decrement)));
+    ArtRosAllocMoreCore(this, -(static_cast<intptr_t>(decrement)));
     if (kTraceRosAlloc) {
       LOG(INFO) << "RosAlloc::Trim() : decreased the footprint from "
                 << footprint_ << " to " << new_footprint;
@@ -1544,7 +1546,7 @@
   size_t pm_end = page_map_size_;
   size_t i = 0;
   while (i < pm_end) {
-    byte pm = page_map_[i];
+    uint8_t pm = page_map_[i];
     switch (pm) {
       case kPageMapReleased:
         // Fall-through.
@@ -1558,9 +1560,9 @@
         if (kIsDebugBuild) {
           // In the debug build, the first page of a free page run
           // contains a magic number for debugging. Exclude it.
-          start = reinterpret_cast<byte*>(fpr) + kPageSize;
+          start = reinterpret_cast<uint8_t*>(fpr) + kPageSize;
         }
-        void* end = reinterpret_cast<byte*>(fpr) + fpr_size;
+        void* end = reinterpret_cast<uint8_t*>(fpr) + fpr_size;
         handler(start, end, 0, arg);
         size_t num_pages = fpr_size / kPageSize;
         if (kIsDebugBuild) {
@@ -1594,7 +1596,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.
@@ -1614,10 +1616,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;
     }
   }
@@ -1737,14 +1739,14 @@
 void RosAlloc::AssertAllThreadLocalRunsAreRevoked() {
   if (kIsDebugBuild) {
     Thread* self = Thread::Current();
-    MutexLock mu(self, *Locks::runtime_shutdown_lock_);
-    MutexLock mu2(self, *Locks::thread_list_lock_);
+    MutexLock shutdown_mu(self, *Locks::runtime_shutdown_lock_);
+    MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
     std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
     for (Thread* t : thread_list) {
       AssertThreadLocalRunsAreRevoked(t);
     }
     for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; ++idx) {
-      MutexLock mu(self, *size_bracket_locks_[idx]);
+      MutexLock brackets_mu(self, *size_bracket_locks_[idx]);
       CHECK_EQ(current_runs_[idx], dedicated_full_run_);
     }
   }
@@ -1770,7 +1772,7 @@
     if (i < 4) {
       numOfPages[i] = 1;
     } else if (i < 8) {
-      numOfPages[i] = 2;
+      numOfPages[i] = 1;
     } else if (i < 16) {
       numOfPages[i] = 4;
     } else if (i < 32) {
@@ -1851,7 +1853,8 @@
   dedicated_full_run_->SetIsThreadLocal(true);
 }
 
-void RosAlloc::BytesAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg) {
+void RosAlloc::BytesAllocatedCallback(void* start ATTRIBUTE_UNUSED, void* end ATTRIBUTE_UNUSED,
+                                      size_t used_bytes, void* arg) {
   if (used_bytes == 0) {
     return;
   }
@@ -1859,7 +1862,8 @@
   *bytes_allocated += used_bytes;
 }
 
-void RosAlloc::ObjectsAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg) {
+void RosAlloc::ObjectsAllocatedCallback(void* start ATTRIBUTE_UNUSED, void* end ATTRIBUTE_UNUSED,
+                                        size_t used_bytes, void* arg) {
   if (used_bytes == 0) {
     return;
   }
@@ -1871,15 +1875,15 @@
   Thread* self = Thread::Current();
   CHECK(Locks::mutator_lock_->IsExclusiveHeld(self))
       << "The mutator locks isn't exclusively locked at " << __PRETTY_FUNCTION__;
-  MutexLock mu(self, *Locks::thread_list_lock_);
+  MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
   ReaderMutexLock wmu(self, bulk_free_lock_);
   std::vector<Run*> runs;
   {
-    MutexLock mu(self, lock_);
+    MutexLock lock_mu(self, lock_);
     size_t pm_end = page_map_size_;
     size_t i = 0;
     while (i < pm_end) {
-      byte pm = page_map_[i];
+      uint8_t pm = page_map_[i];
       switch (pm) {
         case kPageMapReleased:
           // Fall-through.
@@ -1915,10 +1919,15 @@
             num_pages++;
             idx++;
           }
-          void* start = base_ + i * kPageSize;
+          uint8_t* start = base_ + i * kPageSize;
+          if (running_on_valgrind_) {
+            start += ::art::gc::space::kDefaultValgrindRedZoneBytes;
+          }
           mirror::Object* obj = reinterpret_cast<mirror::Object*>(start);
           size_t obj_size = obj->SizeOf();
-          CHECK_GT(obj_size, kLargeSizeThreshold)
+          CHECK_GT(obj_size +
+                   (running_on_valgrind_ ? 2 * ::art::gc::space::kDefaultValgrindRedZoneBytes : 0),
+                   kLargeSizeThreshold)
               << "A rosalloc large object size must be > " << kLargeSizeThreshold;
           CHECK_EQ(num_pages, RoundUp(obj_size, kPageSize) / kPageSize)
               << "A rosalloc large object size " << obj_size
@@ -1930,7 +1939,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.
@@ -1958,7 +1967,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;
       }
     }
@@ -1966,7 +1975,7 @@
   std::list<Thread*> threads = Runtime::Current()->GetThreadList()->GetList();
   for (Thread* thread : threads) {
     for (size_t i = 0; i < kNumThreadLocalSizeBrackets; ++i) {
-      MutexLock mu(self, *size_bracket_locks_[i]);
+      MutexLock brackets_mu(self, *size_bracket_locks_[i]);
       Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(i));
       CHECK(thread_local_run != nullptr);
       CHECK(thread_local_run->IsThreadLocal());
@@ -1975,7 +1984,7 @@
     }
   }
   for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
-    MutexLock mu(self, *size_bracket_locks_[i]);
+    MutexLock brackets_mu(self, *size_bracket_locks_[i]);
     Run* current_run = current_runs_[i];
     CHECK(current_run != nullptr);
     if (current_run != dedicated_full_run_) {
@@ -1986,21 +1995,21 @@
   }
   // Call Verify() here for the lock order.
   for (auto& run : runs) {
-    run->Verify(self, this);
+    run->Verify(self, this, running_on_valgrind_);
   }
 }
 
-void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc) {
+void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc, bool running_on_valgrind) {
   DCHECK_EQ(magic_num_, kMagicNum) << "Bad magic number : " << Dump();
   const size_t idx = size_bracket_idx_;
   CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump();
-  byte* slot_base = reinterpret_cast<byte*>(this) + headerSizes[idx];
+  uint8_t* slot_base = reinterpret_cast<uint8_t*>(this) + headerSizes[idx];
   const size_t num_slots = numOfSlots[idx];
   const size_t num_vec = RoundUp(num_slots, 32) / 32;
   CHECK_GT(num_vec, 0U);
   size_t bracket_size = IndexToBracketSize(idx);
   CHECK_EQ(slot_base + num_slots * bracket_size,
-           reinterpret_cast<byte*>(this) + numOfPages[idx] * kPageSize)
+           reinterpret_cast<uint8_t*>(this) + numOfPages[idx] * kPageSize)
       << "Mismatch in the end address of the run " << Dump();
   // Check that the bulk free bitmap is clean. It's only used during BulkFree().
   CHECK(IsBulkFreeBitmapClean()) << "The bulk free bit map isn't clean " << Dump();
@@ -2073,6 +2082,9 @@
   }
   // Check each slot.
   size_t slots = 0;
+  size_t valgrind_modifier = running_on_valgrind ?
+      2 * ::art::gc::space::kDefaultValgrindRedZoneBytes :
+      0U;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
     DCHECK_GE(num_slots, slots) << "Out of bounds";
     uint32_t vec = alloc_bit_map_[v];
@@ -2084,15 +2096,18 @@
       // thread local free bitmap.
       bool is_thread_local_freed = IsThreadLocal() && ((thread_local_free_vec >> i) & 0x1) != 0;
       if (is_allocated && !is_thread_local_freed) {
-        byte* slot_addr = slot_base + (slots + i) * bracket_size;
+        uint8_t* slot_addr = slot_base + (slots + i) * bracket_size;
+        if (running_on_valgrind) {
+          slot_addr += ::art::gc::space::kDefaultValgrindRedZoneBytes;
+        }
         mirror::Object* obj = reinterpret_cast<mirror::Object*>(slot_addr);
         size_t obj_size = obj->SizeOf();
-        CHECK_LE(obj_size, kLargeSizeThreshold)
+        CHECK_LE(obj_size + valgrind_modifier, kLargeSizeThreshold)
             << "A run slot contains a large object " << Dump();
-        CHECK_EQ(SizeToIndex(obj_size), idx)
+        CHECK_EQ(SizeToIndex(obj_size + valgrind_modifier), idx)
             << PrettyTypeOf(obj) << " "
-            << "obj_size=" << obj_size << ", idx=" << idx << " "
-            << "A run slot contains an object with wrong size " << Dump();
+            << "obj_size=" << obj_size << "(" << obj_size + valgrind_modifier << "), idx=" << idx
+            << " A run slot contains an object with wrong size " << Dump();
       }
     }
   }
@@ -2108,7 +2123,7 @@
   while (i < page_map_size_) {
     // Reading the page map without a lock is racy but the race is benign since it should only
     // result in occasionally not releasing pages which we could release.
-    byte pm = page_map_[i];
+    uint8_t pm = page_map_[i];
     switch (pm) {
       case kPageMapReleased:
         // Fall through.
@@ -2129,7 +2144,7 @@
           if (free_page_runs_.find(fpr) != free_page_runs_.end()) {
             size_t fpr_size = fpr->ByteSize(this);
             DCHECK(IsAligned<kPageSize>(fpr_size));
-            byte* start = reinterpret_cast<byte*>(fpr);
+            uint8_t* start = reinterpret_cast<uint8_t*>(fpr);
             reclaimed_bytes += ReleasePageRange(start, start + fpr_size);
             size_t pages = fpr_size / kPageSize;
             CHECK_GT(pages, 0U) << "Infinite loop probable";
@@ -2138,7 +2153,7 @@
             break;
           }
         }
-        // Fall through.
+        FALLTHROUGH_INTENDED;
       }
       case kPageMapLargeObject:      // Fall through.
       case kPageMapLargeObjectPart:  // Fall through.
@@ -2147,14 +2162,14 @@
         ++i;
         break;  // Skip.
       default:
-        LOG(FATAL) << "Unreachable - page map type: " << pm;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
         break;
     }
   }
   return reclaimed_bytes;
 }
 
-size_t RosAlloc::ReleasePageRange(byte* start, byte* end) {
+size_t RosAlloc::ReleasePageRange(uint8_t* start, uint8_t* end) {
   DCHECK_ALIGNED(start, kPageSize);
   DCHECK_ALIGNED(end, kPageSize);
   DCHECK_LT(start, end);
@@ -2162,6 +2177,11 @@
     // In the debug build, the first page of a free page run
     // contains a magic number for debugging. Exclude it.
     start += kPageSize;
+
+    // Single pages won't be released.
+    if (start == end) {
+      return 0;
+    }
   }
   if (!kMadviseZeroes) {
     // TODO: Do this when we resurrect the page instead.
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 2fbd97a..3269e10 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -44,13 +44,13 @@
   // Represents a run of free pages.
   class FreePageRun {
    public:
-    byte magic_num_;  // The magic number used for debugging only.
+    uint8_t magic_num_;  // The magic number used for debugging only.
 
     bool IsFree() const {
       return !kIsDebugBuild || magic_num_ == kMagicNumFree;
     }
     size_t ByteSize(RosAlloc* rosalloc) const EXCLUSIVE_LOCKS_REQUIRED(rosalloc->lock_) {
-      const byte* fpr_base = reinterpret_cast<const byte*>(this);
+      const uint8_t* fpr_base = reinterpret_cast<const uint8_t*>(this);
       size_t pm_idx = rosalloc->ToPageMapIndex(fpr_base);
       size_t byte_size = rosalloc->free_page_run_size_map_[pm_idx];
       DCHECK_GE(byte_size, static_cast<size_t>(0));
@@ -60,7 +60,7 @@
     void SetByteSize(RosAlloc* rosalloc, size_t byte_size)
         EXCLUSIVE_LOCKS_REQUIRED(rosalloc->lock_) {
       DCHECK_EQ(byte_size % kPageSize, static_cast<size_t>(0));
-      byte* fpr_base = reinterpret_cast<byte*>(this);
+      uint8_t* fpr_base = reinterpret_cast<uint8_t*>(this);
       size_t pm_idx = rosalloc->ToPageMapIndex(fpr_base);
       rosalloc->free_page_run_size_map_[pm_idx] = byte_size;
     }
@@ -68,8 +68,8 @@
       return reinterpret_cast<void*>(this);
     }
     void* End(RosAlloc* rosalloc) EXCLUSIVE_LOCKS_REQUIRED(rosalloc->lock_) {
-      byte* fpr_base = reinterpret_cast<byte*>(this);
-      byte* end = fpr_base + ByteSize(rosalloc);
+      uint8_t* fpr_base = reinterpret_cast<uint8_t*>(this);
+      uint8_t* end = fpr_base + ByteSize(rosalloc);
       return end;
     }
     bool IsLargerThanPageReleaseThreshold(RosAlloc* rosalloc)
@@ -78,7 +78,7 @@
     }
     bool IsAtEndOfSpace(RosAlloc* rosalloc)
         EXCLUSIVE_LOCKS_REQUIRED(rosalloc->lock_) {
-      return reinterpret_cast<byte*>(this) + ByteSize(rosalloc) == rosalloc->base_ + rosalloc->footprint_;
+      return reinterpret_cast<uint8_t*>(this) + ByteSize(rosalloc) == rosalloc->base_ + rosalloc->footprint_;
     }
     bool ShouldReleasePages(RosAlloc* rosalloc) EXCLUSIVE_LOCKS_REQUIRED(rosalloc->lock_) {
       switch (rosalloc->page_release_mode_) {
@@ -98,13 +98,16 @@
       }
     }
     void ReleasePages(RosAlloc* rosalloc) EXCLUSIVE_LOCKS_REQUIRED(rosalloc->lock_) {
-      byte* start = reinterpret_cast<byte*>(this);
+      uint8_t* start = reinterpret_cast<uint8_t*>(this);
       size_t byte_size = ByteSize(rosalloc);
       DCHECK_EQ(byte_size % kPageSize, static_cast<size_t>(0));
       if (ShouldReleasePages(rosalloc)) {
         rosalloc->ReleasePageRange(start, start + byte_size);
       }
     }
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(FreePageRun);
   };
 
   // Represents a run of memory slots of the same size.
@@ -151,10 +154,10 @@
   //
   class Run {
    public:
-    byte magic_num_;                 // The magic number used for debugging.
-    byte size_bracket_idx_;          // The index of the size bracket of this run.
-    byte is_thread_local_;           // True if this run is used as a thread-local run.
-    byte to_be_bulk_freed_;          // Used within BulkFree() to flag a run that's involved with a bulk free.
+    uint8_t magic_num_;                 // The magic number used for debugging.
+    uint8_t size_bracket_idx_;          // The index of the size bracket of this run.
+    uint8_t is_thread_local_;           // True if this run is used as a thread-local run.
+    uint8_t to_be_bulk_freed_;          // Used within BulkFree() to flag a run that's involved with a bulk free.
     uint32_t first_search_vec_idx_;  // The index of the first bitmap vector which may contain an available slot.
     uint32_t alloc_bit_map_[0];      // The bit map that allocates if each slot is in use.
 
@@ -175,20 +178,20 @@
     // Returns the byte size of the header except for the bit maps.
     static size_t fixed_header_size() {
       Run temp;
-      size_t size = reinterpret_cast<byte*>(&temp.alloc_bit_map_) - reinterpret_cast<byte*>(&temp);
+      size_t size = reinterpret_cast<uint8_t*>(&temp.alloc_bit_map_) - reinterpret_cast<uint8_t*>(&temp);
       DCHECK_EQ(size, static_cast<size_t>(8));
       return size;
     }
     // Returns the base address of the free bit map.
     uint32_t* BulkFreeBitMap() {
-      return reinterpret_cast<uint32_t*>(reinterpret_cast<byte*>(this) + bulkFreeBitMapOffsets[size_bracket_idx_]);
+      return reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(this) + bulkFreeBitMapOffsets[size_bracket_idx_]);
     }
     // Returns the base address of the thread local free bit map.
     uint32_t* ThreadLocalFreeBitMap() {
-      return reinterpret_cast<uint32_t*>(reinterpret_cast<byte*>(this) + threadLocalFreeBitMapOffsets[size_bracket_idx_]);
+      return reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(this) + threadLocalFreeBitMapOffsets[size_bracket_idx_]);
     }
     void* End() {
-      return reinterpret_cast<byte*>(this) + kPageSize * numOfPages[size_bracket_idx_];
+      return reinterpret_cast<uint8_t*>(this) + kPageSize * numOfPages[size_bracket_idx_];
     }
     // Returns the number of bitmap words per run.
     size_t NumberOfBitmapVectors() const {
@@ -246,7 +249,7 @@
     // Dump the run metadata for debugging.
     std::string Dump();
     // Verify for debugging.
-    void Verify(Thread* self, RosAlloc* rosalloc)
+    void Verify(Thread* self, RosAlloc* rosalloc, bool running_on_valgrind)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_);
 
@@ -256,16 +259,18 @@
     size_t MarkFreeBitMapShared(void* ptr, uint32_t* free_bit_map_base, const char* caller_name);
     // Turns the bit map into a string for debugging.
     static std::string BitMapToStr(uint32_t* bit_map_base, size_t num_vec);
+
+    // TODO: DISALLOW_COPY_AND_ASSIGN(Run);
   };
 
   // The magic number for a run.
-  static const byte kMagicNum = 42;
+  static constexpr uint8_t kMagicNum = 42;
   // The magic number for free pages.
-  static const byte kMagicNumFree = 43;
+  static constexpr uint8_t kMagicNumFree = 43;
   // The number of size brackets. Sync this with the length of Thread::rosalloc_runs_.
-  static const size_t kNumOfSizeBrackets = kNumRosAllocThreadLocalSizeBrackets;
+  static constexpr size_t kNumOfSizeBrackets = kNumRosAllocThreadLocalSizeBrackets;
   // The number of smaller size brackets that are 16 bytes apart.
-  static const size_t kNumOfQuantumSizeBrackets = 32;
+  static constexpr size_t kNumOfQuantumSizeBrackets = 32;
   // The sizes (the slot sizes, in bytes) of the size brackets.
   static size_t bracketSizes[kNumOfSizeBrackets];
   // The numbers of pages that are used for runs for each size bracket.
@@ -285,7 +290,7 @@
 
   // Returns the byte size of the bracket size from the index.
   static size_t IndexToBracketSize(size_t idx) {
-    DCHECK(idx < kNumOfSizeBrackets);
+    DCHECK_LT(idx, kNumOfSizeBrackets);
     return bracketSizes[idx];
   }
   // Returns the index of the size bracket from the bracket size.
@@ -355,14 +360,15 @@
   // Returns the page map index from an address. Requires that the
   // address is page size aligned.
   size_t ToPageMapIndex(const void* addr) const {
-    DCHECK(base_ <= addr && addr < base_ + capacity_);
-    size_t byte_offset = reinterpret_cast<const byte*>(addr) - base_;
+    DCHECK_LE(base_, addr);
+    DCHECK_LT(addr, base_ + capacity_);
+    size_t byte_offset = reinterpret_cast<const uint8_t*>(addr) - base_;
     DCHECK_EQ(byte_offset % static_cast<size_t>(kPageSize), static_cast<size_t>(0));
     return byte_offset / kPageSize;
   }
   // Returns the page map index from an address with rounding.
-  size_t RoundDownToPageMapIndex(void* addr) const {
-    DCHECK(base_ <= addr && addr < reinterpret_cast<byte*>(base_) + capacity_);
+  size_t RoundDownToPageMapIndex(const void* addr) const {
+    DCHECK(base_ <= addr && addr < reinterpret_cast<uint8_t*>(base_) + capacity_);
     return (reinterpret_cast<uintptr_t>(addr) - reinterpret_cast<uintptr_t>(base_)) / kPageSize;
   }
 
@@ -372,6 +378,10 @@
 
   // If true, check that the returned memory is actually zero.
   static constexpr bool kCheckZeroMemory = kIsDebugBuild;
+  // Valgrind protects memory, so do not check memory when running under valgrind. In a normal
+  // build with kCheckZeroMemory the whole test should be optimized away.
+  // TODO: Unprotect before checks.
+  ALWAYS_INLINE bool ShouldCheckZeroMemory();
 
   // If true, log verbose details of operations.
   static constexpr bool kTraceRosAlloc = false;
@@ -404,12 +414,11 @@
 
   // We use thread-local runs for the size Brackets whose indexes
   // are less than this index. We use shared (current) runs for the rest.
-
-  static const size_t kNumThreadLocalSizeBrackets = 11;
+  static const size_t kNumThreadLocalSizeBrackets = 8;
 
  private:
   // The base address of the memory region that's managed by this allocator.
-  byte* base_;
+  uint8_t* base_;
 
   // The footprint in bytes of the currently allocated portion of the
   // memory region.
@@ -446,7 +455,7 @@
   // Bracket lock names (since locks only have char* names).
   std::string size_bracket_lock_names_[kNumOfSizeBrackets];
   // The types of page map entries.
-  enum {
+  enum PageMapKind {
     kPageMapReleased = 0,     // Zero and released back to the OS.
     kPageMapEmpty,            // Zero but probably dirty.
     kPageMapRun,              // The beginning of a run.
@@ -455,7 +464,7 @@
     kPageMapLargeObjectPart,  // The non-beginning part of a large object.
   };
   // The table that indicates what pages are currently used for.
-  volatile byte* page_map_;  // No GUARDED_BY(lock_) for kReadPageMapEntryWithoutLockInBulkFree.
+  volatile uint8_t* page_map_;  // No GUARDED_BY(lock_) for kReadPageMapEntryWithoutLockInBulkFree.
   size_t page_map_size_;
   size_t max_page_map_size_;
   std::unique_ptr<MemMap> page_map_mem_map_;
@@ -480,13 +489,16 @@
   // greater than or equal to this value, release pages.
   const size_t page_release_size_threshold_;
 
+  // Whether this allocator is running under Valgrind.
+  bool running_on_valgrind_;
+
   // The base address of the memory region that's managed by this allocator.
-  byte* Begin() { return base_; }
+  uint8_t* Begin() { return base_; }
   // The end address of the memory region that's managed by this allocator.
-  byte* End() { return base_ + capacity_; }
+  uint8_t* End() { return base_ + capacity_; }
 
   // Page-granularity alloc/free
-  void* AllocPages(Thread* self, size_t num_pages, byte page_map_type)
+  void* AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
   // Returns how many bytes were freed.
   size_t FreePages(Thread* self, void* ptr, bool already_zero) EXCLUSIVE_LOCKS_REQUIRED(lock_);
@@ -524,13 +536,18 @@
   void RevokeThreadUnsafeCurrentRuns();
 
   // Release a range of pages.
-  size_t ReleasePageRange(byte* start, byte* end) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  size_t ReleasePageRange(uint8_t* start, uint8_t* end) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  // Dumps the page map for debugging.
+  std::string DumpPageMap() EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
  public:
   RosAlloc(void* base, size_t capacity, size_t max_capacity,
            PageReleaseMode page_release_mode,
+           bool running_on_valgrind,
            size_t page_release_size_threshold = kDefaultPageReleaseSizeThreshold);
   ~RosAlloc();
+
   // If kThreadUnsafe is true then the allocator may avoid acquiring some locks as an optimization.
   // If used, this may cause race conditions if multiple threads are allocating at the same time.
   template<bool kThreadSafe = true>
@@ -540,8 +557,9 @@
       LOCKS_EXCLUDED(bulk_free_lock_);
   size_t BulkFree(Thread* self, void** ptrs, size_t num_ptrs)
       LOCKS_EXCLUDED(bulk_free_lock_);
+
   // Returns the size of the allocated slot for a given allocated memory chunk.
-  size_t UsableSize(void* ptr);
+  size_t UsableSize(const void* ptr);
   // Returns the size of the allocated slot for a given size.
   size_t UsableSize(size_t bytes) {
     if (UNLIKELY(bytes > kLargeSizeThreshold)) {
@@ -557,6 +575,7 @@
   void InspectAll(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg),
                   void* arg)
       LOCKS_EXCLUDED(lock_);
+
   // Release empty pages.
   size_t ReleasePages() LOCKS_EXCLUDED(lock_);
   // Returns the current footprint.
@@ -565,6 +584,7 @@
   size_t FootprintLimit() LOCKS_EXCLUDED(lock_);
   // Update the current capacity.
   void SetFootprintLimit(size_t bytes) LOCKS_EXCLUDED(lock_);
+
   // Releases the thread-local runs assigned to the given thread back to the common set of runs.
   void RevokeThreadLocalRuns(Thread* thread);
   // Releases the thread-local runs assigned to all the threads back to the common set of runs.
@@ -573,14 +593,13 @@
   void AssertThreadLocalRunsAreRevoked(Thread* thread);
   // Assert all the thread local runs are revoked.
   void AssertAllThreadLocalRunsAreRevoked() LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  // Dumps the page map for debugging.
-  std::string DumpPageMap() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
   static Run* GetDedicatedFullRun() {
     return dedicated_full_run_;
   }
   bool IsFreePage(size_t idx) const {
     DCHECK_LT(idx, capacity_ / kPageSize);
-    byte pm_type = page_map_[idx];
+    uint8_t pm_type = page_map_[idx];
     return pm_type == kPageMapReleased || pm_type == kPageMapEmpty;
   }
 
@@ -597,7 +616,17 @@
   void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes);
+
+ private:
+  friend std::ostream& operator<<(std::ostream& os, const RosAlloc::PageMapKind& rhs);
+
+  DISALLOW_COPY_AND_ASSIGN(RosAlloc);
 };
+std::ostream& operator<<(std::ostream& os, const RosAlloc::PageMapKind& rhs);
+
+// Callback from rosalloc when it needs to increase the footprint. Must be implemented somewhere
+// else (currently rosalloc_space.cc).
+void* ArtRosAllocMoreCore(allocator::RosAlloc* rosalloc, intptr_t increment);
 
 }  // namespace allocator
 }  // namespace gc
diff --git a/runtime/gc/allocator_type.h b/runtime/gc/allocator_type.h
index 938b0f1..c6ebc73 100644
--- a/runtime/gc/allocator_type.h
+++ b/runtime/gc/allocator_type.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_GC_ALLOCATOR_TYPE_H_
 #define ART_RUNTIME_GC_ALLOCATOR_TYPE_H_
 
+#include <ostream>
+
 namespace art {
 namespace gc {
 
@@ -29,6 +31,7 @@
   kAllocatorTypeNonMoving,  // Special allocator for non moving objects, doesn't have entrypoints.
   kAllocatorTypeLOS,  // Large object space, also doesn't have entrypoints.
 };
+std::ostream& operator<<(std::ostream& os, const AllocatorType& rhs);
 
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index ce7c75a..ee5a785 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -29,7 +29,9 @@
                              const std::string& name_prefix = "")
       : GarbageCollector(heap,
                          name_prefix + (name_prefix.empty() ? "" : " ") +
-                         "concurrent copying + mark sweep") {}
+                         "concurrent copying + mark sweep") {
+    UNUSED(generational);
+  }
 
   ~ConcurrentCopying() {}
 
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 07b61e6..8be18be 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"
@@ -98,7 +102,7 @@
   total_time_ns_ += current_iteration->GetDurationNs();
   for (uint64_t pause_time : current_iteration->GetPauseTimes()) {
     MutexLock mu(self, pause_histogram_lock_);
-    pause_histogram_.AddValue(pause_time / 1000);
+    pause_histogram_.AdjustAndAddValue(pause_time);
   }
   ATRACE_END();
 }
@@ -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_compact.cc b/runtime/gc/collector/mark_compact.cc
index b3bed64..18af005 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -120,7 +120,7 @@
 void MarkCompact::CalculateObjectForwardingAddresses() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // The bump pointer in the space where the next forwarding address will be.
-  bump_pointer_ = reinterpret_cast<byte*>(space_->Begin());
+  bump_pointer_ = reinterpret_cast<uint8_t*>(space_->Begin());
   // Visit all the marked objects in the bitmap.
   CalculateObjectForwardingAddressVisitor visitor(this);
   objects_before_forwarding_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space_->Begin()),
@@ -239,7 +239,7 @@
       accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
       if (table != nullptr) {
         // TODO: Improve naming.
-        TimingLogger::ScopedTiming t(
+        TimingLogger::ScopedTiming t2(
             space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
                                      "UpdateAndMarkImageModUnionTable", GetTimings());
         table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
@@ -300,22 +300,20 @@
 }
 
 void MarkCompact::MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* obj_ptr,
-                                          void* arg) {
+                                            void* arg) {
   reinterpret_cast<MarkCompact*>(arg)->MarkObject(obj_ptr->AsMirrorPtr());
 }
 
 void MarkCompact::DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
-                                               void* arg) {
+                                                 void* arg) {
   reinterpret_cast<MarkCompact*>(arg)->DelayReferenceReferent(klass, ref);
 }
 
-void MarkCompact::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
-                                   RootType /*root_type*/) {
+void MarkCompact::MarkRootCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
   reinterpret_cast<MarkCompact*>(arg)->MarkObject(*root);
 }
 
-void MarkCompact::UpdateRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
-                                     RootType /*root_type*/) {
+void MarkCompact::UpdateRootCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
   mirror::Object* obj = *root;
   mirror::Object* new_obj = reinterpret_cast<MarkCompact*>(arg)->GetMarkedForwardAddress(obj);
   if (obj != new_obj) {
@@ -348,7 +346,7 @@
     accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
     if (table != nullptr) {
       // TODO: Improve naming.
-      TimingLogger::ScopedTiming t(
+      TimingLogger::ScopedTiming t2(
           space->IsZygoteSpace() ? "UpdateZygoteModUnionTableReferences" :
                                    "UpdateImageModUnionTableReferences",
                                    GetTimings());
@@ -538,7 +536,7 @@
       if (!ShouldSweepSpace(alloc_space)) {
         continue;
       }
-      TimingLogger::ScopedTiming t(
+      TimingLogger::ScopedTiming t2(
           alloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepAllocSpace", GetTimings());
       RecordFree(alloc_space->Sweep(swap_bitmaps));
     }
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index bb85fa0..f6d473d 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -24,6 +24,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "garbage_collector.h"
+#include "gc_root.h"
 #include "gc/accounting/heap_bitmap.h"
 #include "immune_region.h"
 #include "lock_word.h"
@@ -113,8 +114,7 @@
   void SweepSystemWeaks()
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
-  static void MarkRootCallback(mirror::Object** root, void* arg, uint32_t /*tid*/,
-                               RootType /*root_type*/)
+  static void MarkRootCallback(mirror::Object** root, void* arg, const RootInfo& root_info)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
   static mirror::Object* MarkObjectCallback(mirror::Object* root, void* arg)
@@ -180,8 +180,7 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
   // Update the references of objects by using the forwarding addresses.
   void UpdateReferences() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
-  static void UpdateRootCallback(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
-                                 RootType /*root_type*/)
+  static void UpdateRootCallback(mirror::Object** root, void* arg, const RootInfo& /*root_info*/)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
   // Move objects and restore lock words.
@@ -227,7 +226,7 @@
   std::string collector_name_;
 
   // The bump pointer in the space where the next forwarding address will be.
-  byte* bump_pointer_;
+  uint8_t* bump_pointer_;
   // How many live objects we have in the space.
   size_t live_objects_in_space_;
 
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 930499a..80f7968 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"
@@ -457,42 +460,35 @@
   }
 }
 
-void MarkSweep::MarkRootParallelCallback(Object** root, void* arg, uint32_t /*thread_id*/,
-                                         RootType /*root_type*/) {
+void MarkSweep::MarkRootParallelCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
   reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNullParallel(*root);
 }
 
-void MarkSweep::VerifyRootMarked(Object** root, void* arg, uint32_t /*thread_id*/,
-                                 RootType /*root_type*/) {
+void MarkSweep::VerifyRootMarked(Object** root, void* arg, const RootInfo& /*root_info*/) {
   CHECK(reinterpret_cast<MarkSweep*>(arg)->IsMarked(*root));
 }
 
-void MarkSweep::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
-                                 RootType /*root_type*/) {
+void MarkSweep::MarkRootCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
   reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNull(*root);
 }
 
-void MarkSweep::VerifyRootCallback(const Object* root, void* arg, size_t vreg,
-                                   const StackVisitor* visitor, RootType root_type) {
-  reinterpret_cast<MarkSweep*>(arg)->VerifyRoot(root, vreg, visitor, root_type);
+void MarkSweep::VerifyRootCallback(Object** root, void* arg, const RootInfo& root_info) {
+  reinterpret_cast<MarkSweep*>(arg)->VerifyRoot(*root, root_info);
 }
 
-void MarkSweep::VerifyRoot(const Object* root, size_t vreg, const StackVisitor* visitor,
-                           RootType root_type) {
+void MarkSweep::VerifyRoot(const Object* root, const RootInfo& root_info) {
   // See if the root is on any space bitmap.
   if (heap_->GetLiveBitmap()->GetContinuousSpaceBitmap(root) == nullptr) {
     space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
     if (large_object_space != nullptr && !large_object_space->Contains(root)) {
-      LOG(ERROR) << "Found invalid root: " << root << " with type " << root_type;
-      if (visitor != NULL) {
-        LOG(ERROR) << visitor->DescribeLocation() << " in VReg: " << vreg;
-      }
+      LOG(ERROR) << "Found invalid root: " << root << " ";
+      root_info.Describe(LOG(ERROR));
     }
   }
 }
 
 void MarkSweep::VerifyRoots() {
-  Runtime::Current()->GetThreadList()->VerifyRoots(VerifyRootCallback, this);
+  Runtime::Current()->GetThreadList()->VisitRoots(VerifyRootCallback, this);
 }
 
 void MarkSweep::MarkRoots(Thread* self) {
@@ -655,6 +651,7 @@
   // Scans all of the objects
   virtual void Run(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    UNUSED(self);
     ScanObjectParallelVisitor visitor(this);
     // TODO: Tune this.
     static const size_t kFifoSize = 4;
@@ -663,10 +660,10 @@
       Object* obj = nullptr;
       if (kUseMarkStackPrefetch) {
         while (mark_stack_pos_ != 0 && prefetch_fifo.size() < kFifoSize) {
-          Object* obj = mark_stack_[--mark_stack_pos_];
-          DCHECK(obj != nullptr);
-          __builtin_prefetch(obj);
-          prefetch_fifo.push_back(obj);
+          Object* mark_stack_obj = mark_stack_[--mark_stack_pos_];
+          DCHECK(mark_stack_obj != nullptr);
+          __builtin_prefetch(mark_stack_obj);
+          prefetch_fifo.push_back(mark_stack_obj);
         }
         if (UNLIKELY(prefetch_fifo.empty())) {
           break;
@@ -689,7 +686,7 @@
  public:
   CardScanTask(ThreadPool* thread_pool, MarkSweep* mark_sweep,
                accounting::ContinuousSpaceBitmap* bitmap,
-               byte* begin, byte* end, byte minimum_age, size_t mark_stack_size,
+               uint8_t* begin, uint8_t* end, uint8_t minimum_age, size_t mark_stack_size,
                Object** mark_stack_obj)
       : MarkStackTask<false>(thread_pool, mark_sweep, mark_stack_size, mark_stack_obj),
         bitmap_(bitmap),
@@ -700,9 +697,9 @@
 
  protected:
   accounting::ContinuousSpaceBitmap* const bitmap_;
-  byte* const begin_;
-  byte* const end_;
-  const byte minimum_age_;
+  uint8_t* const begin_;
+  uint8_t* const end_;
+  const uint8_t minimum_age_;
 
   virtual void Finalize() {
     delete this;
@@ -730,7 +727,7 @@
   }
 }
 
-void MarkSweep::ScanGrayObjects(bool paused, byte minimum_age) {
+void MarkSweep::ScanGrayObjects(bool paused, uint8_t minimum_age) {
   accounting::CardTable* card_table = GetHeap()->GetCardTable();
   ThreadPool* thread_pool = GetHeap()->GetThreadPool();
   size_t thread_count = GetThreadCount(paused);
@@ -754,8 +751,8 @@
       if (space->GetMarkBitmap() == nullptr) {
         continue;
       }
-      byte* card_begin = space->Begin();
-      byte* card_end = space->End();
+      uint8_t* card_begin = space->Begin();
+      uint8_t* card_end = space->End();
       // Align up the end address. For example, the image space's end
       // may not be card-size-aligned.
       card_end = AlignUp(card_end, accounting::CardTable::kCardSize);
@@ -810,6 +807,7 @@
           break;
         default:
           LOG(FATAL) << "Unreachable";
+          UNREACHABLE();
         }
         TimingLogger::ScopedTiming t(name, GetTimings());
         ScanObjectVisitor visitor(this);
@@ -910,7 +908,7 @@
   return nullptr;
 }
 
-void MarkSweep::RecursiveMarkDirtyObjects(bool paused, byte minimum_age) {
+void MarkSweep::RecursiveMarkDirtyObjects(bool paused, uint8_t minimum_age) {
   ScanGrayObjects(paused, minimum_age);
   ProcessMarkStack(paused);
 }
@@ -923,7 +921,7 @@
                                                           kVisitRootFlagStopLoggingNewRoots |
                                                           kVisitRootFlagClearRootLog));
   if (kVerifyRootsMarked) {
-    TimingLogger::ScopedTiming t("(Paused)VerifyRoots", GetTimings());
+    TimingLogger::ScopedTiming t2("(Paused)VerifyRoots", GetTimings());
     Runtime::Current()->VisitRoots(VerifyRootMarked, this);
   }
 }
@@ -1052,7 +1050,7 @@
         // if needed.
         if (!mark_bitmap->Test(obj)) {
           if (chunk_free_pos >= kSweepArrayChunkFreeSize) {
-            TimingLogger::ScopedTiming t("FreeList", GetTimings());
+            TimingLogger::ScopedTiming t2("FreeList", GetTimings());
             freed.objects += chunk_free_pos;
             freed.bytes += alloc_space->FreeList(self, chunk_free_pos, chunk_free_buffer);
             chunk_free_pos = 0;
@@ -1064,7 +1062,7 @@
       }
     }
     if (chunk_free_pos > 0) {
-      TimingLogger::ScopedTiming t("FreeList", GetTimings());
+      TimingLogger::ScopedTiming t2("FreeList", GetTimings());
       freed.objects += chunk_free_pos;
       freed.bytes += alloc_space->FreeList(self, chunk_free_pos, chunk_free_buffer);
       chunk_free_pos = 0;
@@ -1094,10 +1092,10 @@
     }
   }
   {
-    TimingLogger::ScopedTiming t("RecordFree", GetTimings());
+    TimingLogger::ScopedTiming t2("RecordFree", GetTimings());
     RecordFree(freed);
     RecordFreeLOS(freed_los);
-    t.NewTiming("ResetStack");
+    t2.NewTiming("ResetStack");
     allocations->Reset();
   }
   sweep_array_free_buffer_mem_map_->MadviseDontNeedAndZero();
@@ -1213,10 +1211,10 @@
       Object* obj = NULL;
       if (kUseMarkStackPrefetch) {
         while (!mark_stack_->IsEmpty() && prefetch_fifo.size() < kFifoSize) {
-          Object* obj = mark_stack_->PopBack();
-          DCHECK(obj != NULL);
-          __builtin_prefetch(obj);
-          prefetch_fifo.push_back(obj);
+          Object* mark_stack_obj = mark_stack_->PopBack();
+          DCHECK(mark_stack_obj != NULL);
+          __builtin_prefetch(mark_stack_obj);
+          prefetch_fifo.push_back(mark_stack_obj);
         }
         if (prefetch_fifo.empty()) {
           break;
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 2780099..b787327 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -24,6 +24,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "garbage_collector.h"
+#include "gc_root.h"
 #include "gc/accounting/heap_bitmap.h"
 #include "immune_region.h"
 #include "object_callbacks.h"
@@ -112,7 +113,7 @@
   virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Builds a mark stack with objects on dirty cards and recursively mark until it empties.
-  void RecursiveMarkDirtyObjects(bool paused, byte minimum_age)
+  void RecursiveMarkDirtyObjects(bool paused, uint8_t minimum_age)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -182,13 +183,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static void MarkRootCallback(mirror::Object** root, void* arg, uint32_t thread_id,
-                               RootType root_type)
+  static void MarkRootCallback(mirror::Object** root, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static void VerifyRootMarked(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
-                               RootType /*root_type*/)
+  static void VerifyRootMarked(mirror::Object** root, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -196,8 +195,7 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static void MarkRootParallelCallback(mirror::Object** root, void* arg, uint32_t thread_id,
-                                       RootType root_type)
+  static void MarkRootParallelCallback(mirror::Object** root, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Marks an object.
@@ -247,17 +245,15 @@
   // whether or not we care about pauses.
   size_t GetThreadCount(bool paused) const;
 
-  static void VerifyRootCallback(const mirror::Object* root, void* arg, size_t vreg,
-                                 const StackVisitor *visitor, RootType root_type);
+  static void VerifyRootCallback(mirror::Object** root, void* arg, const RootInfo& root_info);
 
-  void VerifyRoot(const mirror::Object* root, size_t vreg, const StackVisitor* visitor,
-                  RootType root_type) NO_THREAD_SAFETY_ANALYSIS;
+  void VerifyRoot(const mirror::Object* root, const RootInfo& root_info) NO_THREAD_SAFETY_ANALYSIS;
 
   // Push a single reference on a mark stack.
   void PushOnMarkStack(mirror::Object* obj);
 
   // Blackens objects grayed during a garbage collection.
-  void ScanGrayObjects(bool paused, byte minimum_age)
+  void ScanGrayObjects(bool paused, uint8_t minimum_age)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index c8fa869..fcc601f 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"
@@ -223,7 +224,7 @@
   // Need to do this before the checkpoint since we don't want any threads to add references to
   // the live stack during the recursive mark.
   if (kUseThreadLocalAllocationStack) {
-    TimingLogger::ScopedTiming t("RevokeAllThreadLocalAllocationStacks", GetTimings());
+    TimingLogger::ScopedTiming t2("RevokeAllThreadLocalAllocationStacks", GetTimings());
     heap_->RevokeAllThreadLocalAllocationStacks(self_);
   }
   heap_->SwapStacks(self_);
@@ -252,8 +253,17 @@
   RecordFree(ObjectBytePair(from_objects - to_objects, from_bytes - to_bytes));
   // Clear and protect the from space.
   from_space_->Clear();
-  VLOG(heap) << "Protecting from_space_: " << *from_space_;
-  from_space_->GetMemMap()->Protect(kProtectFromSpace ? PROT_NONE : PROT_READ);
+  if (kProtectFromSpace && !from_space_->IsRosAllocSpace()) {
+    // Protect with PROT_NONE.
+    VLOG(heap) << "Protecting from_space_ : " << *from_space_;
+    from_space_->GetMemMap()->Protect(PROT_NONE);
+  } else {
+    // If RosAllocSpace, we'll leave it as PROT_READ here so the
+    // rosaloc verification can read the metadata magic number and
+    // protect it with PROT_NONE later in FinishPhase().
+    VLOG(heap) << "Protecting from_space_ with PROT_READ : " << *from_space_;
+    from_space_->GetMemMap()->Protect(PROT_READ);
+  }
   heap_->PreSweepingGcVerification(this);
   if (swap_semi_spaces_) {
     heap_->SwapSemiSpaces();
@@ -367,7 +377,7 @@
   CHECK_EQ(is_large_object_space_immune_, collect_from_space_only_);
   space::LargeObjectSpace* los = GetHeap()->GetLargeObjectsSpace();
   if (is_large_object_space_immune_ && los != nullptr) {
-    TimingLogger::ScopedTiming t("VisitLargeObjects", GetTimings());
+    TimingLogger::ScopedTiming t2("VisitLargeObjects", GetTimings());
     DCHECK(collect_from_space_only_);
     // Delay copying the live set to the marked set until here from
     // BindBitmaps() as the large objects on the allocation stack may
@@ -437,15 +447,15 @@
     return 0;
   }
   size_t saved_bytes = 0;
-  byte* byte_dest = reinterpret_cast<byte*>(dest);
+  uint8_t* byte_dest = reinterpret_cast<uint8_t*>(dest);
   if (kIsDebugBuild) {
     for (size_t i = 0; i < size; ++i) {
       CHECK_EQ(byte_dest[i], 0U);
     }
   }
   // Process the start of the page. The page must already be dirty, don't bother with checking.
-  const byte* byte_src = reinterpret_cast<const byte*>(src);
-  const byte* limit = byte_src + size;
+  const uint8_t* byte_src = reinterpret_cast<const uint8_t*>(src);
+  const uint8_t* limit = byte_src + size;
   size_t page_remain = AlignUp(byte_dest, kPageSize) - byte_dest;
   // Copy the bytes until the start of the next page.
   memcpy(dest, src, page_remain);
@@ -481,7 +491,7 @@
   const size_t object_size = obj->SizeOf();
   size_t bytes_allocated;
   mirror::Object* forward_address = nullptr;
-  if (generational_ && reinterpret_cast<byte*>(obj) < last_gc_to_space_end_) {
+  if (generational_ && reinterpret_cast<uint8_t*>(obj) < last_gc_to_space_end_) {
     // If it's allocated before the last GC (older), move
     // (pseudo-promote) it to the main free list space (as sort
     // of an old generation.)
@@ -590,8 +600,7 @@
   reinterpret_cast<SemiSpace*>(arg)->DelayReferenceReferent(klass, ref);
 }
 
-void SemiSpace::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
-                                 RootType /*root_type*/) {
+void SemiSpace::MarkRootCallback(Object** root, void* arg, const RootInfo& /*root_info*/) {
   auto ref = StackReference<mirror::Object>::FromMirrorPtr(*root);
   reinterpret_cast<SemiSpace*>(arg)->MarkObject(&ref);
   if (*root != ref.AsMirrorPtr()) {
@@ -748,6 +757,10 @@
 
 void SemiSpace::FinishPhase() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
+  if (kProtectFromSpace && from_space_->IsRosAllocSpace()) {
+    VLOG(heap) << "Protecting from_space_ with PROT_NONE : " << *from_space_;
+    from_space_->GetMemMap()->Protect(PROT_NONE);
+  }
   // Null the "to" and "from" spaces since compacting from one to the other isn't valid until
   // further action is done by the heap.
   to_space_ = nullptr;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 71a83f2..f8fced8 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "garbage_collector.h"
+#include "gc_root.h"
 #include "gc/accounting/heap_bitmap.h"
 #include "immune_region.h"
 #include "mirror/object_reference.h"
@@ -132,8 +133,7 @@
   void SweepSystemWeaks()
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
-  static void MarkRootCallback(mirror::Object** root, void* arg, uint32_t /*tid*/,
-                               RootType /*root_type*/)
+  static void MarkRootCallback(mirror::Object** root, void* arg, const RootInfo& root_info)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
   static mirror::Object* MarkObjectCallback(mirror::Object* root, void* arg)
@@ -228,7 +228,7 @@
 
   // Used for the generational mode. the end/top of the bump
   // pointer space at the end of the last collection.
-  byte* last_gc_to_space_end_;
+  uint8_t* last_gc_to_space_end_;
 
   // Used for the generational mode. During a collection, keeps track
   // of how many bytes of objects have been copied so far from the
diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc
index 4ed6abc..5be3db7 100644
--- a/runtime/gc/collector/sticky_mark_sweep.cc
+++ b/runtime/gc/collector/sticky_mark_sweep.cc
@@ -58,6 +58,7 @@
 }
 
 void StickyMarkSweep::Sweep(bool swap_bitmaps) {
+  UNUSED(swap_bitmaps);
   SweepArray(GetHeap()->GetLiveStack(), false);
 }
 
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index f0e1512..6be683d 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -35,8 +35,8 @@
     case kGcCauseTrim: return "HeapTrim";
     default:
       LOG(FATAL) << "Unreachable";
+      UNREACHABLE();
   }
-  return "";
 }
 
 std::ostream& operator<<(std::ostream& os, const GcCause& gc_cause) {
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 3101c68..9d2f6d1 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -48,11 +48,20 @@
   }
   // Need to check that we arent the large object allocator since the large object allocation code
   // path this function. If we didn't check we would have an infinite loop.
-  if (kCheckLargeObject && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
-    return AllocLargeObject<kInstrumented, PreFenceVisitor>(self, klass, byte_count,
-                                                            pre_fence_visitor);
-  }
   mirror::Object* obj;
+  if (kCheckLargeObject && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
+    obj = AllocLargeObject<kInstrumented, PreFenceVisitor>(self, &klass, byte_count,
+                                                           pre_fence_visitor);
+    if (obj != nullptr) {
+      return obj;
+    } else {
+      // There should be an OOM exception, since we are retrying, clear it.
+      self->ClearException();
+    }
+    // If the large object allocation failed, try to use the normal spaces (main space,
+    // non moving space). This can happen if there is significant virtual address space
+    // fragmentation.
+  }
   AllocationTimer alloc_timer(this, &obj);
   size_t bytes_allocated;
   size_t usable_size;
@@ -171,10 +180,13 @@
 }
 
 template <bool kInstrumented, typename PreFenceVisitor>
-inline mirror::Object* Heap::AllocLargeObject(Thread* self, mirror::Class* klass,
+inline mirror::Object* Heap::AllocLargeObject(Thread* self, mirror::Class** klass,
                                               size_t byte_count,
                                               const PreFenceVisitor& pre_fence_visitor) {
-  return AllocObjectWithAllocator<kInstrumented, false, PreFenceVisitor>(self, klass, byte_count,
+  // Save and restore the class in case it moves.
+  StackHandleScope<1> hs(self);
+  auto klass_wrapper = hs.NewHandleWrapper(klass);
+  return AllocObjectWithAllocator<kInstrumented, false, PreFenceVisitor>(self, *klass, byte_count,
                                                                          kAllocatorTypeLOS,
                                                                          pre_fence_visitor);
 }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d672510..eed9352 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -24,11 +24,13 @@
 #include <vector>
 
 #include "base/allocator.h"
+#include "base/dumpable.h"
 #include "base/histogram-inl.h"
 #include "base/stl_util.h"
 #include "common_throws.h"
 #include "cutils/sched_policy.h"
 #include "debugger.h"
+#include "dex_file-inl.h"
 #include "gc/accounting/atomic_stack.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap-inl.h"
@@ -50,9 +52,11 @@
 #include "gc/space/rosalloc_space-inl.h"
 #include "gc/space/space-inl.h"
 #include "gc/space/zygote_space.h"
+#include "gc/task_processor.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "heap-inl.h"
 #include "image.h"
+#include "intern_table.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
@@ -74,8 +78,6 @@
 
 static constexpr size_t kCollectorTransitionStressIterations = 0;
 static constexpr size_t kCollectorTransitionStressWait = 10 * 1000;  // Microseconds
-static constexpr bool kGCALotMode = false;
-static constexpr size_t kGcAlotInterval = KB;
 // Minimum amount of remaining bytes before a concurrent GC is triggered.
 static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB;
 static constexpr size_t kMaxConcurrentRemainingBytes = 512 * KB;
@@ -94,7 +96,18 @@
 static const char* kDlMallocSpaceName[2] = {"main dlmalloc space", "main dlmalloc space 1"};
 static const char* kRosAllocSpaceName[2] = {"main rosalloc space", "main rosalloc space 1"};
 static const char* kMemMapSpaceName[2] = {"main space", "main space 1"};
+static const char* kNonMovingSpaceName = "non moving space";
+static const char* kZygoteSpaceName = "zygote space";
 static constexpr size_t kGSSBumpPointerSpaceCapacity = 32 * MB;
+static constexpr bool kGCALotMode = false;
+// GC alot mode uses a small allocation stack to stress test a lot of GC.
+static constexpr size_t kGcAlotAllocationStackSize = 4 * KB /
+    sizeof(mirror::HeapReference<mirror::Object>);
+// Verify objet has a small allocation stack size since searching the allocation stack is slow.
+static constexpr size_t kVerifyObjectAllocationStackSize = 16 * KB /
+    sizeof(mirror::HeapReference<mirror::Object>);
+static constexpr size_t kDefaultAllocationStackSize = 8 * MB /
+    sizeof(mirror::HeapReference<mirror::Object>);
 
 Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
            double target_utilization, double foreground_heap_growth_multiplier,
@@ -117,10 +130,7 @@
       foreground_collector_type_(foreground_collector_type),
       background_collector_type_(background_collector_type),
       desired_collector_type_(foreground_collector_type_),
-      heap_trim_request_lock_(nullptr),
-      last_trim_time_(0),
-      heap_transition_or_trim_target_time_(0),
-      heap_trim_request_pending_(false),
+      pending_task_lock_(nullptr),
       parallel_gc_threads_(parallel_gc_threads),
       conc_gc_threads_(conc_gc_threads),
       low_memory_mode_(low_memory_mode),
@@ -154,15 +164,14 @@
       verify_pre_gc_rosalloc_(verify_pre_gc_rosalloc),
       verify_pre_sweeping_rosalloc_(verify_pre_sweeping_rosalloc),
       verify_post_gc_rosalloc_(verify_post_gc_rosalloc),
-      last_gc_time_ns_(NanoTime()),
-      allocation_rate_(0),
       /* For GC a lot mode, we limit the allocations stacks to be kGcAlotInterval allocations. This
        * causes a lot of GC since we do a GC for alloc whenever the stack is full. When heap
        * verification is enabled, we limit the size of allocation stacks to speed up their
        * searching.
        */
-      max_allocation_stack_size_(kGCALotMode ? kGcAlotInterval
-          : (kVerifyObjectSupport > kVerifyObjectModeFast) ? KB : MB),
+      max_allocation_stack_size_(kGCALotMode ? kGcAlotAllocationStackSize
+          : (kVerifyObjectSupport > kVerifyObjectModeFast) ? kVerifyObjectAllocationStackSize :
+          kDefaultAllocationStackSize),
       current_allocator_(kAllocatorTypeDlMalloc),
       current_non_moving_allocator_(kAllocatorTypeNonMoving),
       bump_pointer_space_(nullptr),
@@ -181,6 +190,8 @@
       min_interval_homogeneous_space_compaction_by_oom_(
           min_interval_homogeneous_space_compaction_by_oom),
       last_time_homogeneous_space_compaction_by_oom_(NanoTime()),
+      pending_collector_transition_(nullptr),
+      pending_heap_trim_(nullptr),
       use_homogeneous_space_compaction_for_oom_(use_homogeneous_space_compaction_for_oom) {
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "Heap() entering";
@@ -199,7 +210,7 @@
   live_bitmap_.reset(new accounting::HeapBitmap(this));
   mark_bitmap_.reset(new accounting::HeapBitmap(this));
   // Requested begin for the alloc space, to follow the mapped image and oat files
-  byte* requested_alloc_space_begin = nullptr;
+  uint8_t* requested_alloc_space_begin = nullptr;
   if (!image_file_name.empty()) {
     std::string error_msg;
     space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str(),
@@ -209,7 +220,7 @@
       AddSpace(image_space);
       // Oat files referenced by image files immediately follow them in memory, ensure alloc space
       // isn't going to get in the middle
-      byte* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
+      uint8_t* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
       CHECK_GT(oat_file_end_addr, image_space->End());
       requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
     } else {
@@ -230,9 +241,13 @@
                                      +-main alloc space2 / bump space 2 (capacity_)+-
                                      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
   */
+  // We don't have hspace compaction enabled with GSS.
+  if (foreground_collector_type_ == kCollectorTypeGSS) {
+    use_homogeneous_space_compaction_for_oom_ = false;
+  }
   bool support_homogeneous_space_compaction =
       background_collector_type_ == gc::kCollectorTypeHomogeneousSpaceCompact ||
-      use_homogeneous_space_compaction_for_oom;
+      use_homogeneous_space_compaction_for_oom_;
   // We may use the same space the main space for the non moving space if we don't need to compact
   // from the main space.
   // This is not the case if we support homogeneous compaction or have a moving background
@@ -245,32 +260,35 @@
   }
   std::unique_ptr<MemMap> main_mem_map_1;
   std::unique_ptr<MemMap> main_mem_map_2;
-  byte* request_begin = requested_alloc_space_begin;
+  uint8_t* request_begin = requested_alloc_space_begin;
   if (request_begin != nullptr && separate_non_moving_space) {
     request_begin += non_moving_space_capacity;
   }
   std::string error_str;
   std::unique_ptr<MemMap> non_moving_space_mem_map;
   if (separate_non_moving_space) {
+    // If we are the zygote, the non moving space becomes the zygote space when we run
+    // PreZygoteFork the first time. In this case, call the map "zygote space" since we can't
+    // rename the mem map later.
+    const char* space_name = is_zygote ? kZygoteSpaceName: kNonMovingSpaceName;
     // Reserve the non moving mem map before the other two since it needs to be at a specific
     // address.
     non_moving_space_mem_map.reset(
-        MemMap::MapAnonymous("non moving space", requested_alloc_space_begin,
+        MemMap::MapAnonymous(space_name, requested_alloc_space_begin,
                              non_moving_space_capacity, PROT_READ | PROT_WRITE, true, &error_str));
     CHECK(non_moving_space_mem_map != nullptr) << error_str;
     // Try to reserve virtual memory at a lower address if we have a separate non moving space.
-    request_begin = reinterpret_cast<byte*>(300 * MB);
+    request_begin = reinterpret_cast<uint8_t*>(300 * MB);
   }
   // Attempt to create 2 mem maps at or after the requested begin.
   main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0], request_begin, capacity_,
-                                                    PROT_READ | PROT_WRITE, &error_str));
+                                                    &error_str));
   CHECK(main_mem_map_1.get() != nullptr) << error_str;
   if (support_homogeneous_space_compaction ||
       background_collector_type_ == kCollectorTypeSS ||
       foreground_collector_type_ == kCollectorTypeSS) {
     main_mem_map_2.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[1], main_mem_map_1->End(),
-                                                      capacity_, PROT_READ | PROT_WRITE,
-                                                      &error_str));
+                                                      capacity_, &error_str));
     CHECK(main_mem_map_2.get() != nullptr) << error_str;
   }
   // Create the non moving space first so that bitmaps don't take up the address range.
@@ -350,10 +368,11 @@
   // Compute heap capacity. Continuous spaces are sorted in order of Begin().
   CHECK(!continuous_spaces_.empty());
   // Relies on the spaces being sorted.
-  byte* heap_begin = continuous_spaces_.front()->Begin();
-  byte* heap_end = continuous_spaces_.back()->Limit();
+  uint8_t* heap_begin = continuous_spaces_.front()->Begin();
+  uint8_t* heap_end = continuous_spaces_.back()->Limit();
   size_t heap_capacity = heap_end - heap_begin;
   // Remove the main backup space since it slows down the GC to have unused extra spaces.
+  // TODO: Avoid needing to do this.
   if (main_space_backup_.get() != nullptr) {
     RemoveSpace(main_space_backup_.get());
   }
@@ -388,8 +407,8 @@
   gc_complete_lock_ = new Mutex("GC complete lock");
   gc_complete_cond_.reset(new ConditionVariable("GC complete condition variable",
                                                 *gc_complete_lock_));
-  heap_trim_request_lock_ = new Mutex("Heap trim request lock");
-  last_gc_size_ = GetBytesAllocated();
+  task_processor_.reset(new TaskProcessor());
+  pending_task_lock_ = new Mutex("Pending task lock");
   if (ignore_max_footprint_) {
     SetIdealFootprint(std::numeric_limits<size_t>::max());
     concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
@@ -433,10 +452,10 @@
   }
 }
 
-MemMap* Heap::MapAnonymousPreferredAddress(const char* name, byte* request_begin, size_t capacity,
-                                           int prot_flags, std::string* out_error_str) {
+MemMap* Heap::MapAnonymousPreferredAddress(const char* name, uint8_t* request_begin,
+                                           size_t capacity, 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;
@@ -598,8 +617,8 @@
       }
     }
     // Unprotect all the spaces.
-    for (const auto& space : continuous_spaces_) {
-      mprotect(space->Begin(), space->Capacity(), PROT_READ | PROT_WRITE);
+    for (const auto& con_space : continuous_spaces_) {
+      mprotect(con_space->Begin(), con_space->Capacity(), PROT_READ | PROT_WRITE);
     }
     stream << "Object " << obj;
     if (space != nullptr) {
@@ -685,8 +704,29 @@
 }
 
 void Heap::VisitObjects(ObjectCallback callback, void* arg) {
-  // GCs can move objects, so don't allow this.
-  ScopedAssertNoThreadSuspension ants(Thread::Current(), "Visiting objects");
+  Thread* self = Thread::Current();
+  if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
+    // Threads are already suspended.
+    VisitObjectsInternal(callback, arg);
+  } else if (IsGcConcurrent() && IsMovingGc(collector_type_)) {
+    // Concurrent moving GC. Suspend all threads and visit objects.
+    DCHECK_EQ(collector_type_, foreground_collector_type_);
+    DCHECK_EQ(foreground_collector_type_, background_collector_type_)
+        << "Assume no transition such that collector_type_ won't change";
+    self->TransitionFromRunnableToSuspended(kWaitingForVisitObjects);
+    ThreadList* tl = Runtime::Current()->GetThreadList();
+    tl->SuspendAll();
+    VisitObjectsInternal(callback, arg);
+    tl->ResumeAll();
+    self->TransitionFromSuspendedToRunnable();
+  } else {
+    // GCs can move objects, so don't allow this.
+    ScopedAssertNoThreadSuspension ants(self, "Visiting objects");
+    VisitObjectsInternal(callback, arg);
+  }
+}
+
+void Heap::VisitObjectsInternal(ObjectCallback callback, void* arg) {
   if (bump_pointer_space_ != nullptr) {
     // Visit objects in bump pointer space.
     bump_pointer_space_->Walk(callback, arg);
@@ -697,12 +737,15 @@
     mirror::Object* obj = *it;
     if (obj != nullptr && obj->GetClass() != nullptr) {
       // Avoid the race condition caused by the object not yet being written into the allocation
-      // stack or the class not yet being written in the object. Or, if kUseThreadLocalAllocationStack,
-      // there can be nulls on the allocation stack.
+      // stack or the class not yet being written in the object. Or, if
+      // kUseThreadLocalAllocationStack, there can be nulls on the allocation stack.
       callback(obj, arg);
     }
   }
-  GetLiveBitmap()->Walk(callback, arg);
+  {
+    ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+    GetLiveBitmap()->Walk(callback, arg);
+  }
 }
 
 void Heap::MarkAllocStackAsLive(accounting::ObjectStack* stack) {
@@ -835,7 +878,7 @@
     os << "Zygote space size " << PrettySize(zygote_space_->Size()) << "\n";
   }
   os << "Total mutator paused time: " << PrettyDuration(total_paused_time) << "\n";
-  os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_) << "\n";
+  os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_);
   BaseMutex::DumpAll(os);
 }
 
@@ -850,7 +893,7 @@
   STLDeleteElements(&continuous_spaces_);
   STLDeleteElements(&discontinuous_spaces_);
   delete gc_complete_lock_;
-  delete heap_trim_request_lock_;
+  delete pending_task_lock_;
   VLOG(heap) << "Finished ~Heap()";
 }
 
@@ -885,7 +928,7 @@
   if (result != NULL) {
     return result;
   }
-  return FindDiscontinuousSpaceFromObject(obj, true);
+  return FindDiscontinuousSpaceFromObject(obj, fail_ok);
 }
 
 space::ImageSpace* Heap::GetImageSpace() const {
@@ -921,37 +964,23 @@
   self->ThrowOutOfMemoryError(oss.str().c_str());
 }
 
-void Heap::DoPendingTransitionOrTrim() {
-  Thread* self = Thread::Current();
-  CollectorType desired_collector_type;
-  // Wait until we reach the desired transition time.
-  while (true) {
-    uint64_t wait_time;
-    {
-      MutexLock mu(self, *heap_trim_request_lock_);
-      desired_collector_type = desired_collector_type_;
-      uint64_t current_time = NanoTime();
-      if (current_time >= heap_transition_or_trim_target_time_) {
-        break;
-      }
-      wait_time = heap_transition_or_trim_target_time_ - current_time;
-    }
-    ScopedThreadStateChange tsc(self, kSleeping);
-    usleep(wait_time / 1000);  // Usleep takes microseconds.
-  }
+void Heap::DoPendingCollectorTransition() {
+  CollectorType desired_collector_type = desired_collector_type_;
   // Launch homogeneous space compaction if it is desired.
   if (desired_collector_type == kCollectorTypeHomogeneousSpaceCompact) {
     if (!CareAboutPauseTimes()) {
       PerformHomogeneousSpaceCompact();
+    } else {
+      VLOG(gc) << "Homogeneous compaction ignored due to jank perceptible process state";
     }
-    // No need to Trim(). Homogeneous space compaction may free more virtual and physical memory.
-    desired_collector_type = collector_type_;
-    return;
+  } else {
+    TransitionCollector(desired_collector_type);
   }
-  // Transition the collector if the desired collector type is not the same as the current
-  // collector type.
-  TransitionCollector(desired_collector_type);
+}
+
+void Heap::Trim(Thread* self) {
   if (!CareAboutPauseTimes()) {
+    ATRACE_BEGIN("Deflating monitors");
     // Deflate the monitors, this can cause a pause but shouldn't matter since we don't care
     // about pauses.
     Runtime* runtime = Runtime::Current();
@@ -961,21 +990,43 @@
     VLOG(heap) << "Deflating " << count << " monitors took "
         << PrettyDuration(NanoTime() - start_time);
     runtime->GetThreadList()->ResumeAll();
+    ATRACE_END();
   }
-  // Do a heap trim if it is needed.
-  Trim();
+  TrimIndirectReferenceTables(self);
+  TrimSpaces(self);
 }
 
-void Heap::Trim() {
-  Thread* self = Thread::Current();
-  {
-    MutexLock mu(self, *heap_trim_request_lock_);
-    if (!heap_trim_request_pending_ || last_trim_time_ + kHeapTrimWait >= NanoTime()) {
-      return;
-    }
-    last_trim_time_ = NanoTime();
-    heap_trim_request_pending_ = false;
+class TrimIndirectReferenceTableClosure : public Closure {
+ public:
+  explicit TrimIndirectReferenceTableClosure(Barrier* barrier) : barrier_(barrier) {
   }
+  virtual void Run(Thread* thread) OVERRIDE NO_THREAD_SAFETY_ANALYSIS {
+    ATRACE_BEGIN("Trimming reference table");
+    thread->GetJniEnv()->locals.Trim();
+    ATRACE_END();
+    barrier_->Pass(Thread::Current());
+  }
+
+ private:
+  Barrier* const barrier_;
+};
+
+void Heap::TrimIndirectReferenceTables(Thread* self) {
+  ScopedObjectAccess soa(self);
+  ATRACE_BEGIN(__FUNCTION__);
+  JavaVMExt* vm = soa.Vm();
+  // Trim globals indirect reference table.
+  vm->TrimGlobals();
+  // Trim locals indirect reference tables.
+  Barrier barrier(0);
+  TrimIndirectReferenceTableClosure closure(&barrier);
+  ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+  size_t barrier_count = Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
+  barrier.Increment(self, barrier_count);
+  ATRACE_END();
+}
+
+void Heap::TrimSpaces(Thread* self) {
   {
     // Need to do this before acquiring the locks since we don't want to get suspended while
     // holding any locks.
@@ -987,7 +1038,8 @@
     WaitForGcToCompleteLocked(kGcCauseTrim, self);
     collector_type_running_ = kCollectorTypeHeapTrim;
   }
-  uint64_t start_ns = NanoTime();
+  ATRACE_BEGIN(__FUNCTION__);
+  const uint64_t start_ns = NanoTime();
   // Trim the managed spaces.
   uint64_t total_alloc_space_allocated = 0;
   uint64_t total_alloc_space_size = 0;
@@ -1016,6 +1068,8 @@
   // We never move things in the native heap, so we can finish the GC at this point.
   FinishGC(self, collector::kGcTypeNone);
   size_t native_reclaimed = 0;
+
+#ifdef HAVE_ANDROID_OS
   // Only trim the native heap if we don't care about pauses.
   if (!CareAboutPauseTimes()) {
 #if defined(USE_DLMALLOC)
@@ -1028,12 +1082,14 @@
     UNIMPLEMENTED(WARNING) << "Add trimming support";
 #endif
   }
+#endif  // HAVE_ANDROID_OS
   uint64_t end_ns = NanoTime();
   VLOG(heap) << "Heap trim of managed (duration=" << PrettyDuration(gc_heap_end_ns - start_ns)
       << ", advised=" << PrettySize(managed_reclaimed) << ") and native (duration="
       << PrettyDuration(end_ns - gc_heap_end_ns) << ", advised=" << PrettySize(native_reclaimed)
       << ") heaps. Managed heap utilization of " << static_cast<int>(100 * managed_utilization)
       << "%.";
+  ATRACE_END();
 }
 
 bool Heap::IsValidObjectAddress(const mirror::Object* obj) const {
@@ -1262,12 +1318,12 @@
       continue;
     }
     // Attempt to run the collector, if we succeed, re-try the allocation.
-    const bool gc_ran =
+    const bool plan_gc_ran =
         CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
     if (was_default_allocator && allocator != GetCurrentAllocator()) {
       return nullptr;
     }
-    if (gc_ran) {
+    if (plan_gc_ran) {
       // Did we free sufficient memory for the allocation to succeed?
       mirror::Object* ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated,
                                                        usable_size);
@@ -1324,8 +1380,9 @@
               // Throw OOM by default.
               break;
             default: {
-              LOG(FATAL) << "Unimplemented homogeneous space compaction result "
-                         << static_cast<size_t>(result);
+              UNIMPLEMENTED(FATAL) << "homogeneous space compaction result: "
+                  << static_cast<size_t>(result);
+              UNREACHABLE();
             }
           }
           // Always print that we ran homogeneous space compation since this can cause jank.
@@ -1426,10 +1483,7 @@
 
 void Heap::CountInstances(const std::vector<mirror::Class*>& classes, bool use_is_assignable_from,
                           uint64_t* counts) {
-  // Can't do any GC in this function since this may move classes.
-  ScopedAssertNoThreadSuspension ants(Thread::Current(), "CountInstances");
   InstanceCounter counter(classes, use_is_assignable_from, counts);
-  ReaderMutexLock mu(ants.Self(), *Locks::heap_bitmap_lock_);
   VisitObjects(InstanceCounter::Callback, &counter);
 }
 
@@ -1460,10 +1514,7 @@
 
 void Heap::GetInstances(mirror::Class* c, int32_t max_count,
                         std::vector<mirror::Object*>& instances) {
-  // Can't do any GC in this function since this may move classes.
-  ScopedAssertNoThreadSuspension ants(Thread::Current(), "GetInstances");
   InstanceCollector collector(c, max_count, instances);
-  ReaderMutexLock mu(ants.Self(), *Locks::heap_bitmap_lock_);
   VisitObjects(&InstanceCollector::Callback, &collector);
 }
 
@@ -1505,10 +1556,7 @@
 
 void Heap::GetReferringObjects(mirror::Object* o, int32_t max_count,
                                std::vector<mirror::Object*>& referring_objects) {
-  // Can't do any GC in this function since this may move the object o.
-  ScopedAssertNoThreadSuspension ants(Thread::Current(), "GetReferringObjects");
   ReferringObjectsFinder finder(o, max_count, referring_objects);
-  ReaderMutexLock mu(ants.Self(), *Locks::heap_bitmap_lock_);
   VisitObjects(&ReferringObjectsFinder::Callback, &finder);
 }
 
@@ -1527,7 +1575,7 @@
   ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
   Locks::mutator_lock_->AssertNotHeld(self);
   {
-    ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+    ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
     MutexLock mu(self, *gc_complete_lock_);
     // Ensure there is only one GC at a time.
     WaitForGcToCompleteLocked(kGcCauseHomogeneousSpaceCompact, self);
@@ -1556,9 +1604,9 @@
   to_space->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
   const uint64_t space_size_before_compaction = from_space->Size();
   AddSpace(to_space);
+  // Make sure that we will have enough room to copy.
+  CHECK_GE(to_space->GetFootprintLimit(), from_space->GetFootprintLimit());
   Compact(to_space, from_space, kGcCauseHomogeneousSpaceCompact);
-  // Leave as prot read so that we can still run ROSAlloc verification on this space.
-  from_space->GetMemMap()->Protect(PROT_READ);
   const uint64_t space_size_after_compaction = to_space->Size();
   main_space_ = to_space;
   main_space_backup_.reset(from_space);
@@ -1581,7 +1629,6 @@
   return HomogeneousSpaceCompactResult::kSuccess;
 }
 
-
 void Heap::TransitionCollector(CollectorType collector_type) {
   if (collector_type == collector_type_) {
     return;
@@ -1599,7 +1646,7 @@
   // compacting_gc_disable_count_, this should rarely occurs).
   for (;;) {
     {
-      ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+      ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
       MutexLock mu(self, *gc_complete_lock_);
       // Ensure there is only one GC at a time.
       WaitForGcToCompleteLocked(kGcCauseCollectorTransition, self);
@@ -1674,8 +1721,8 @@
         RemoveSpace(temp_space_);
         temp_space_ = nullptr;
         mem_map->Protect(PROT_READ | PROT_WRITE);
-        CreateMainMallocSpace(mem_map.get(), kDefaultInitialSize, mem_map->Size(),
-                              mem_map->Size());
+        CreateMainMallocSpace(mem_map.get(), kDefaultInitialSize,
+                              std::min(mem_map->Size(), growth_limit_), mem_map->Size());
         mem_map.release();
         // Compact to the main space from the bump pointer space, don't need to swap semispaces.
         AddSpace(main_space_);
@@ -1688,9 +1735,9 @@
         if (kIsDebugBuild && kUseRosAlloc) {
           mem_map->Protect(PROT_READ | PROT_WRITE);
         }
-        main_space_backup_.reset(CreateMallocSpaceFromMemMap(mem_map.get(), kDefaultInitialSize,
-                                                             mem_map->Size(), mem_map->Size(),
-                                                             name, true));
+        main_space_backup_.reset(CreateMallocSpaceFromMemMap(
+            mem_map.get(), kDefaultInitialSize, std::min(mem_map->Size(), growth_limit_),
+            mem_map->Size(), name, true));
         if (kIsDebugBuild && kUseRosAlloc) {
           mem_map->Protect(PROT_NONE);
         }
@@ -1760,7 +1807,8 @@
         break;
       }
       default: {
-        LOG(FATAL) << "Unimplemented";
+        UNIMPLEMENTED(FATAL);
+        UNREACHABLE();
       }
     }
     if (IsGcConcurrent()) {
@@ -1825,6 +1873,7 @@
   virtual bool ShouldSweepSpace(space::ContinuousSpace* space) const {
     // Don't sweep any spaces since we probably blasted the internal accounting of the free list
     // allocator.
+    UNUSED(space);
     return false;
   }
 
@@ -1891,6 +1940,8 @@
     LOG(WARNING) << __FUNCTION__ << " called when we already have a zygote space.";
     return;
   }
+  Runtime::Current()->GetInternTable()->SwapPostZygoteWithPreZygote();
+  Runtime::Current()->GetClassLinker()->MoveClassTableToPreZygote();
   VLOG(heap) << "Starting PreZygoteFork";
   // Trim the pages at the end of the non moving space.
   non_moving_space_->Trim();
@@ -1928,7 +1979,8 @@
       MemMap* mem_map = main_space_->ReleaseMemMap();
       RemoveSpace(main_space_);
       space::Space* old_main_space = main_space_;
-      CreateMainMallocSpace(mem_map, kDefaultInitialSize, mem_map->Size(), mem_map->Size());
+      CreateMainMallocSpace(mem_map, kDefaultInitialSize, std::min(mem_map->Size(), growth_limit_),
+                            mem_map->Size());
       delete old_main_space;
       AddSpace(main_space_);
     } else {
@@ -1963,7 +2015,8 @@
     // from this point on.
     RemoveRememberedSet(old_alloc_space);
   }
-  zygote_space_ = old_alloc_space->CreateZygoteSpace("alloc space", low_memory_mode_,
+  // Remaining space becomes the new non moving space.
+  zygote_space_ = old_alloc_space->CreateZygoteSpace(kNonMovingSpaceName, low_memory_mode_,
                                                      &non_moving_space_);
   CHECK(!non_moving_space_->CanMoveObjects());
   if (same_space) {
@@ -2066,12 +2119,14 @@
   ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
   Locks::mutator_lock_->AssertNotHeld(self);
   if (self->IsHandlingStackOverflow()) {
-    LOG(WARNING) << "Performing GC on a thread that is handling a stack overflow.";
+    // If we are throwing a stack overflow error we probably don't have enough remaining stack
+    // space to run the GC.
+    return collector::kGcTypeNone;
   }
   bool compacting_gc;
   {
     gc_complete_lock_->AssertNotHeld(self);
-    ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+    ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
     MutexLock mu(self, *gc_complete_lock_);
     // Ensure there is only one GC at a time.
     WaitForGcToCompleteLocked(gc_cause, self);
@@ -2088,16 +2143,9 @@
     ++runtime->GetStats()->gc_for_alloc_count;
     ++self->GetStats()->gc_for_alloc_count;
   }
-  uint64_t gc_start_time_ns = NanoTime();
-  uint64_t gc_start_size = GetBytesAllocated();
-  // Approximate allocation rate in bytes / second.
-  uint64_t ms_delta = NsToMs(gc_start_time_ns - last_gc_time_ns_);
-  // Back to back GCs can cause 0 ms of wait time in between GC invocations.
-  if (LIKELY(ms_delta != 0)) {
-    allocation_rate_ = ((gc_start_size - last_gc_size_) * 1000) / ms_delta;
-    ATRACE_INT("Allocation rate KB/s", allocation_rate_ / KB);
-    VLOG(heap) << "Allocation rate: " << PrettySize(allocation_rate_) << "/s";
-  }
+  const uint64_t bytes_allocated_before_gc = GetBytesAllocated();
+  // Approximate heap size.
+  ATRACE_INT("Heap size (KB)", bytes_allocated_before_gc / KB);
 
   DCHECK_LT(gc_type, collector::kGcTypeMax);
   DCHECK_NE(gc_type, collector::kGcTypeNone);
@@ -2137,17 +2185,24 @@
   } 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;
   collector->Run(gc_cause, clear_soft_references || runtime->IsZygote());
   total_objects_freed_ever_ += GetCurrentGcIteration()->GetFreedObjects();
   total_bytes_freed_ever_ += GetCurrentGcIteration()->GetFreedBytes();
-  RequestHeapTrim();
+  RequestTrim(self);
   // Enqueue cleared references.
   reference_processor_.EnqueueClearedReferences(self);
   // Grow the heap so that we know when to perform the next GC.
-  GrowForUtilization(collector);
+  GrowForUtilization(collector, bytes_allocated_before_gc);
   const size_t duration = GetCurrentGcIteration()->GetDurationNs();
   const std::vector<uint64_t>& pause_times = GetCurrentGcIteration()->GetPauseTimes();
   // Print the GC if it is an explicit GC (e.g. Runtime.gc()) or a slow GC
@@ -2178,7 +2233,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.
@@ -2196,8 +2251,8 @@
   gc_complete_cond_->Broadcast(self);
 }
 
-static void RootMatchesObjectVisitor(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
-                                     RootType /*root_type*/) {
+static void RootMatchesObjectVisitor(mirror::Object** root, void* arg,
+                                     const RootInfo& /*root_info*/) {
   mirror::Object* obj = reinterpret_cast<mirror::Object*>(arg);
   if (*root == obj) {
     LOG(INFO) << "Object " << obj << " is a root";
@@ -2224,6 +2279,7 @@
 
   void operator()(mirror::Class* klass, mirror::Reference* ref) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    UNUSED(klass);
     if (verify_referent_) {
       VerifyReference(ref, ref->GetReferent(), mirror::Reference::ReferentOffset());
     }
@@ -2238,12 +2294,12 @@
     return heap_->IsLiveObjectLocked(obj, true, false, true);
   }
 
-  static void VerifyRootCallback(mirror::Object** root, void* arg, uint32_t thread_id,
-                                 RootType root_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  static void VerifyRootCallback(mirror::Object** root, void* arg, const RootInfo& root_info)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     VerifyReferenceVisitor* visitor = reinterpret_cast<VerifyReferenceVisitor*>(arg);
     if (!visitor->VerifyReference(nullptr, *root, MemberOffset(0))) {
       LOG(ERROR) << "Root " << *root << " is dead with type " << PrettyTypeOf(*root)
-          << " thread_id= " << thread_id << " root_type= " << root_type;
+          << " thread_id= " << root_info.GetThreadId() << " root_type= " << root_info.GetType();
     }
   }
 
@@ -2265,7 +2321,7 @@
       accounting::CardTable* card_table = heap_->GetCardTable();
       accounting::ObjectStack* alloc_stack = heap_->allocation_stack_.get();
       accounting::ObjectStack* live_stack = heap_->live_stack_.get();
-      byte* card_addr = card_table->CardFromAddr(obj);
+      uint8_t* card_addr = card_table->CardFromAddr(obj);
       LOG(ERROR) << "Object " << obj << " references dead object " << ref << " at offset "
                  << offset << "\n card value = " << static_cast<int>(*card_addr);
       if (heap_->IsValidObjectAddress(obj->GetClass())) {
@@ -2295,7 +2351,7 @@
                    << ") is not a valid heap address";
       }
 
-      card_table->CheckAddrIsInCardTable(reinterpret_cast<const byte*>(obj));
+      card_table->CheckAddrIsInCardTable(reinterpret_cast<const uint8_t*>(obj));
       void* cover_begin = card_table->AddrFromCard(card_addr);
       void* cover_end = reinterpret_cast<void*>(reinterpret_cast<size_t>(cover_begin) +
           accounting::CardTable::kCardSize);
@@ -2328,7 +2384,7 @@
         }
         // Attempt to see if the card table missed the reference.
         ScanVisitor scan_visitor;
-        byte* byte_cover_begin = reinterpret_cast<byte*>(card_table->AddrFromCard(card_addr));
+        uint8_t* byte_cover_begin = reinterpret_cast<uint8_t*>(card_table->AddrFromCard(card_addr));
         card_table->Scan(bitmap, byte_cover_begin,
                          byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
       }
@@ -2568,6 +2624,7 @@
 }
 
 void Heap::SwapStacks(Thread* self) {
+  UNUSED(self);
   if (kUseThreadLocalAllocationStack) {
     live_stack_->AssertAllZero();
   }
@@ -2629,15 +2686,15 @@
     if (table != nullptr) {
       const char* name = space->IsZygoteSpace() ? "ZygoteModUnionClearCards" :
           "ImageModUnionClearCards";
-      TimingLogger::ScopedTiming t(name, timings);
+      TimingLogger::ScopedTiming t2(name, timings);
       table->ClearCards();
     } else if (use_rem_sets && rem_set != nullptr) {
       DCHECK(collector::SemiSpace::kUseRememberedSet && collector_type_ == kCollectorTypeGSS)
           << static_cast<int>(collector_type_);
-      TimingLogger::ScopedTiming t("AllocSpaceRemSetClearCards", timings);
+      TimingLogger::ScopedTiming t2("AllocSpaceRemSetClearCards", timings);
       rem_set->ClearCards();
     } else if (space->GetType() != space::kSpaceTypeBumpPointerSpace) {
-      TimingLogger::ScopedTiming t("AllocSpaceClearCards", timings);
+      TimingLogger::ScopedTiming t2("AllocSpaceClearCards", timings);
       // No mod union table for the AllocSpace. Age the cards so that the GC knows that these cards
       // were dirty before the GC started.
       // TODO: Need to use atomic for the case where aged(cleaning thread) -> dirty(other thread)
@@ -2659,8 +2716,7 @@
   TimingLogger* const timings = current_gc_iteration_.GetTimings();
   TimingLogger::ScopedTiming t(__FUNCTION__, timings);
   if (verify_pre_gc_heap_) {
-    TimingLogger::ScopedTiming t("(Paused)PreGcVerifyHeapReferences", timings);
-    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    TimingLogger::ScopedTiming t2("(Paused)PreGcVerifyHeapReferences", timings);
     size_t failures = VerifyHeapReferences();
     if (failures > 0) {
       LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed with " << failures
@@ -2669,7 +2725,7 @@
   }
   // Check that all objects which reference things in the live stack are on dirty cards.
   if (verify_missing_card_marks_) {
-    TimingLogger::ScopedTiming t("(Paused)PreGcVerifyMissingCardMarks", timings);
+    TimingLogger::ScopedTiming t2("(Paused)PreGcVerifyMissingCardMarks", timings);
     ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
     SwapStacks(self);
     // Sort the live stack so that we can quickly binary search it later.
@@ -2678,7 +2734,7 @@
     SwapStacks(self);
   }
   if (verify_mod_union_table_) {
-    TimingLogger::ScopedTiming t("(Paused)PreGcVerifyModUnionTables", timings);
+    TimingLogger::ScopedTiming t2("(Paused)PreGcVerifyModUnionTables", timings);
     ReaderMutexLock reader_lock(self, *Locks::heap_bitmap_lock_);
     for (const auto& table_pair : mod_union_tables_) {
       accounting::ModUnionTable* mod_union_table = table_pair.second;
@@ -2696,6 +2752,7 @@
 }
 
 void Heap::PrePauseRosAllocVerification(collector::GarbageCollector* gc) {
+  UNUSED(gc);
   // TODO: Add a new runtime option for this?
   if (verify_pre_gc_rosalloc_) {
     RosAllocVerification(current_gc_iteration_.GetTimings(), "PreGcRosAllocVerification");
@@ -2709,11 +2766,13 @@
   // Called before sweeping occurs since we want to make sure we are not going so reclaim any
   // reachable objects.
   if (verify_pre_sweeping_heap_) {
-    TimingLogger::ScopedTiming t("(Paused)PostSweepingVerifyHeapReferences", timings);
+    TimingLogger::ScopedTiming t2("(Paused)PostSweepingVerifyHeapReferences", timings);
     CHECK_NE(self->GetState(), kRunnable);
-    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    // Swapping bound bitmaps does nothing.
-    gc->SwapBitmaps();
+    {
+      WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+      // Swapping bound bitmaps does nothing.
+      gc->SwapBitmaps();
+    }
     // Pass in false since concurrent reference processing can mean that the reference referents
     // may point to dead objects at the point which PreSweepingGcVerification is called.
     size_t failures = VerifyHeapReferences(false);
@@ -2721,7 +2780,10 @@
       LOG(FATAL) << "Pre sweeping " << gc->GetName() << " GC verification failed with " << failures
           << " failures";
     }
-    gc->SwapBitmaps();
+    {
+      WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+      gc->SwapBitmaps();
+    }
   }
   if (verify_pre_sweeping_rosalloc_) {
     RosAllocVerification(timings, "PreSweepingRosAllocVerification");
@@ -2742,8 +2804,7 @@
     RosAllocVerification(timings, "(Paused)PostGcRosAllocVerification");
   }
   if (verify_post_gc_heap_) {
-    TimingLogger::ScopedTiming t("(Paused)PostGcVerifyHeapReferences", timings);
-    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    TimingLogger::ScopedTiming t2("(Paused)PostGcVerifyHeapReferences", timings);
     size_t failures = VerifyHeapReferences();
     if (failures > 0) {
       LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed with " << failures
@@ -2854,25 +2915,24 @@
   return foreground_heap_growth_multiplier_;
 }
 
-void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran) {
+void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran,
+                              uint64_t bytes_allocated_before_gc) {
   // We know what our utilization is at this moment.
   // This doesn't actually resize any memory. It just lets the heap grow more when necessary.
   const uint64_t bytes_allocated = GetBytesAllocated();
-  last_gc_size_ = bytes_allocated;
-  last_gc_time_ns_ = NanoTime();
   uint64_t target_size;
   collector::GcType gc_type = collector_ran->GetGcType();
+  const double multiplier = HeapGrowthMultiplier();  // Use the multiplier to grow more for
+  // foreground.
+  const uint64_t adjusted_min_free = static_cast<uint64_t>(min_free_ * multiplier);
+  const uint64_t adjusted_max_free = static_cast<uint64_t>(max_free_ * multiplier);
   if (gc_type != collector::kGcTypeSticky) {
     // Grow the heap for non sticky GC.
-    const float multiplier = HeapGrowthMultiplier();  // Use the multiplier to grow more for
-    // foreground.
-    intptr_t delta = bytes_allocated / GetTargetHeapUtilization() - bytes_allocated;
+    ssize_t delta = bytes_allocated / GetTargetHeapUtilization() - bytes_allocated;
     CHECK_GE(delta, 0);
     target_size = bytes_allocated + delta * multiplier;
-    target_size = std::min(target_size,
-                           bytes_allocated + static_cast<uint64_t>(max_free_ * multiplier));
-    target_size = std::max(target_size,
-                           bytes_allocated + static_cast<uint64_t>(min_free_ * multiplier));
+    target_size = std::min(target_size, bytes_allocated + adjusted_max_free);
+    target_size = std::max(target_size, bytes_allocated + adjusted_min_free);
     native_need_to_run_finalization_ = true;
     next_gc_type_ = collector::kGcTypeSticky;
   } else {
@@ -2894,8 +2954,8 @@
       next_gc_type_ = non_sticky_gc_type;
     }
     // If we have freed enough memory, shrink the heap back down.
-    if (bytes_allocated + max_free_ < max_allowed_footprint_) {
-      target_size = bytes_allocated + max_free_;
+    if (bytes_allocated + adjusted_max_free < max_allowed_footprint_) {
+      target_size = bytes_allocated + adjusted_max_free;
     } else {
       target_size = std::max(bytes_allocated, static_cast<uint64_t>(max_allowed_footprint_));
     }
@@ -2903,11 +2963,18 @@
   if (!ignore_max_footprint_) {
     SetIdealFootprint(target_size);
     if (IsGcConcurrent()) {
+      const uint64_t freed_bytes = current_gc_iteration_.GetFreedBytes() +
+          current_gc_iteration_.GetFreedLargeObjectBytes();
+      // Bytes allocated will shrink by freed_bytes after the GC runs, so if we want to figure out
+      // how many bytes were allocated during the GC we need to add freed_bytes back on.
+      CHECK_GE(bytes_allocated + freed_bytes, bytes_allocated_before_gc);
+      const uint64_t bytes_allocated_during_gc = bytes_allocated + freed_bytes -
+          bytes_allocated_before_gc;
       // Calculate when to perform the next ConcurrentGC.
       // Calculate the estimated GC duration.
       const double gc_duration_seconds = NsToMs(current_gc_iteration_.GetDurationNs()) / 1000.0;
       // Estimate how many remaining bytes we will have when we need to start the next GC.
-      size_t remaining_bytes = allocation_rate_ * gc_duration_seconds;
+      size_t remaining_bytes = bytes_allocated_during_gc * gc_duration_seconds;
       remaining_bytes = std::min(remaining_bytes, kMaxConcurrentRemainingBytes);
       remaining_bytes = std::max(remaining_bytes, kMinConcurrentRemainingBytes);
       if (UNLIKELY(remaining_bytes > max_allowed_footprint_)) {
@@ -2927,9 +2994,34 @@
   }
 }
 
+void Heap::ClampGrowthLimit() {
+  capacity_ = growth_limit_;
+  for (const auto& space : continuous_spaces_) {
+    if (space->IsMallocSpace()) {
+      gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
+      malloc_space->ClampGrowthLimit();
+    }
+  }
+  // This space isn't added for performance reasons.
+  if (main_space_backup_.get() != nullptr) {
+    main_space_backup_->ClampGrowthLimit();
+  }
+}
+
 void Heap::ClearGrowthLimit() {
   growth_limit_ = capacity_;
-  non_moving_space_->ClearGrowthLimit();
+  for (const auto& space : continuous_spaces_) {
+    if (space->IsMallocSpace()) {
+      gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
+      malloc_space->ClearGrowthLimit();
+      malloc_space->SetFootprintLimit(malloc_space->Capacity());
+    }
+  }
+  // This space isn't added for performance reasons.
+  if (main_space_backup_.get() != nullptr) {
+    main_space_backup_->ClearGrowthLimit();
+    main_space_backup_->SetFootprintLimit(main_space_backup_->Capacity());
+  }
 }
 
 void Heap::AddFinalizerReference(Thread* self, mirror::Object** object) {
@@ -2948,60 +3040,109 @@
   RequestConcurrentGC(self);
 }
 
-void Heap::RequestConcurrentGC(Thread* self) {
-  // Make sure that we can do a concurrent GC.
-  Runtime* runtime = Runtime::Current();
-  if (runtime == nullptr || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self) ||
-      self->IsHandlingStackOverflow()) {
-    return;
+class Heap::ConcurrentGCTask : public HeapTask {
+ public:
+  explicit ConcurrentGCTask(uint64_t target_time) : HeapTask(target_time) { }
+  virtual void Run(Thread* self) OVERRIDE {
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    heap->ConcurrentGC(self);
+    heap->ClearConcurrentGCRequest();
   }
-  // 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);
-  env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
-                            WellKnownClasses::java_lang_Daemons_requestGC);
-  CHECK(!env->ExceptionCheck());
+};
+
+static bool CanAddHeapTask(Thread* self) LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_) {
+  Runtime* runtime = Runtime::Current();
+  return runtime != nullptr && runtime->IsFinishedStarting() && !runtime->IsShuttingDown(self) &&
+      !self->IsHandlingStackOverflow();
+}
+
+void Heap::ClearConcurrentGCRequest() {
+  concurrent_gc_pending_.StoreRelaxed(false);
+}
+
+void Heap::RequestConcurrentGC(Thread* self) {
+  if (CanAddHeapTask(self) &&
+      concurrent_gc_pending_.CompareExchangeStrongSequentiallyConsistent(false, true)) {
+    task_processor_->AddTask(self, new ConcurrentGCTask(NanoTime()));  // Start straight away.
+  }
 }
 
 void Heap::ConcurrentGC(Thread* self) {
-  if (Runtime::Current()->IsShuttingDown(self)) {
-    return;
-  }
-  // Wait for any GCs currently running to finish.
-  if (WaitForGcToComplete(kGcCauseBackground, self) == collector::kGcTypeNone) {
-    // If the we can't run the GC type we wanted to run, find the next appropriate one and try that
-    // instead. E.g. can't do partial, so do full instead.
-    if (CollectGarbageInternal(next_gc_type_, kGcCauseBackground, false) ==
-        collector::kGcTypeNone) {
-      for (collector::GcType gc_type : gc_plan_) {
-        // Attempt to run the collector, if we succeed, we are done.
-        if (gc_type > next_gc_type_ &&
-            CollectGarbageInternal(gc_type, kGcCauseBackground, false) != collector::kGcTypeNone) {
-          break;
+  if (!Runtime::Current()->IsShuttingDown(self)) {
+    // Wait for any GCs currently running to finish.
+    if (WaitForGcToComplete(kGcCauseBackground, self) == collector::kGcTypeNone) {
+      // If the we can't run the GC type we wanted to run, find the next appropriate one and try that
+      // instead. E.g. can't do partial, so do full instead.
+      if (CollectGarbageInternal(next_gc_type_, kGcCauseBackground, false) ==
+          collector::kGcTypeNone) {
+        for (collector::GcType gc_type : gc_plan_) {
+          // Attempt to run the collector, if we succeed, we are done.
+          if (gc_type > next_gc_type_ &&
+              CollectGarbageInternal(gc_type, kGcCauseBackground, false) !=
+                  collector::kGcTypeNone) {
+            break;
+          }
         }
       }
     }
   }
 }
 
-void Heap::RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time) {
-  Thread* self = Thread::Current();
-  {
-    MutexLock mu(self, *heap_trim_request_lock_);
-    if (desired_collector_type_ == desired_collector_type) {
-      return;
-    }
-    heap_transition_or_trim_target_time_ =
-        std::max(heap_transition_or_trim_target_time_, NanoTime() + delta_time);
-    desired_collector_type_ = desired_collector_type;
+class Heap::CollectorTransitionTask : public HeapTask {
+ public:
+  explicit CollectorTransitionTask(uint64_t target_time) : HeapTask(target_time) { }
+  virtual void Run(Thread* self) OVERRIDE {
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    heap->DoPendingCollectorTransition();
+    heap->ClearPendingCollectorTransition(self);
   }
-  SignalHeapTrimDaemon(self);
+};
+
+void Heap::ClearPendingCollectorTransition(Thread* self) {
+  MutexLock mu(self, *pending_task_lock_);
+  pending_collector_transition_ = nullptr;
 }
 
-void Heap::RequestHeapTrim() {
+void Heap::RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time) {
+  Thread* self = Thread::Current();
+  desired_collector_type_ = desired_collector_type;
+  if (desired_collector_type_ == collector_type_ || !CanAddHeapTask(self)) {
+    return;
+  }
+  CollectorTransitionTask* added_task = nullptr;
+  const uint64_t target_time = NanoTime() + delta_time;
+  {
+    MutexLock mu(self, *pending_task_lock_);
+    // If we have an existing collector transition, update the targe time to be the new target.
+    if (pending_collector_transition_ != nullptr) {
+      task_processor_->UpdateTargetRunTime(self, pending_collector_transition_, target_time);
+      return;
+    }
+    added_task = new CollectorTransitionTask(target_time);
+    pending_collector_transition_ = added_task;
+  }
+  task_processor_->AddTask(self, added_task);
+}
+
+class Heap::HeapTrimTask : public HeapTask {
+ public:
+  explicit HeapTrimTask(uint64_t delta_time) : HeapTask(NanoTime() + delta_time) { }
+  virtual void Run(Thread* self) OVERRIDE {
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    heap->Trim(self);
+    heap->ClearPendingTrim(self);
+  }
+};
+
+void Heap::ClearPendingTrim(Thread* self) {
+  MutexLock mu(self, *pending_task_lock_);
+  pending_heap_trim_ = nullptr;
+}
+
+void Heap::RequestTrim(Thread* self) {
+  if (!CanAddHeapTask(self)) {
+    return;
+  }
   // GC completed and now we must decide whether to request a heap trim (advising pages back to the
   // kernel) or not. Issuing a request will also cause trimming of the libc heap. As a trim scans
   // a space it will hold its lock and can become a cause of jank.
@@ -3014,42 +3155,17 @@
   // to utilization (which is probably inversely proportional to how much benefit we can expect).
   // We could try mincore(2) but that's only a measure of how many pages we haven't given away,
   // not how much use we're making of those pages.
-
-  Thread* self = Thread::Current();
-  Runtime* runtime = Runtime::Current();
-  if (runtime == nullptr || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self) ||
-      runtime->IsZygote()) {
-    // Ignore the request if we are the zygote to prevent app launching lag due to sleep in heap
-    // trimmer daemon. b/17310019
-    // Heap trimming isn't supported without a Java runtime or Daemons (such as at dex2oat time)
-    // Also: we do not wish to start a heap trim if the runtime is shutting down (a racy check
-    // as we don't hold the lock while requesting the trim).
-    return;
-  }
+  HeapTrimTask* added_task = nullptr;
   {
-    MutexLock mu(self, *heap_trim_request_lock_);
-    if (last_trim_time_ + kHeapTrimWait >= NanoTime()) {
-      // We have done a heap trim in the last kHeapTrimWait nanosecs, don't request another one
-      // just yet.
+    MutexLock mu(self, *pending_task_lock_);
+    if (pending_heap_trim_ != nullptr) {
+      // Already have a heap trim request in task processor, ignore this request.
       return;
     }
-    heap_trim_request_pending_ = true;
-    uint64_t current_time = NanoTime();
-    if (heap_transition_or_trim_target_time_ < current_time) {
-      heap_transition_or_trim_target_time_ = current_time + kHeapTrimWait;
-    }
+    added_task = new HeapTrimTask(kHeapTrimWait);
+    pending_heap_trim_ = added_task;
   }
-  // Notify the daemon thread which will actually do the heap trim.
-  SignalHeapTrimDaemon(self);
-}
-
-void Heap::SignalHeapTrimDaemon(Thread* self) {
-  JNIEnv* env = self->GetJniEnv();
-  DCHECK(WellKnownClasses::java_lang_Daemons != nullptr);
-  DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != nullptr);
-  env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
-                            WellKnownClasses::java_lang_Daemons_requestHeapTrim);
-  CHECK(!env->ExceptionCheck());
+  task_processor_->AddTask(self, added_task);
 }
 
 void Heap::RevokeThreadLocalBuffers(Thread* thread) {
@@ -3077,7 +3193,7 @@
 }
 
 bool Heap::IsGCRequestPending() const {
-  return concurrent_start_bytes_ != std::numeric_limits<size_t>::max();
+  return concurrent_gc_pending_.LoadRelaxed();
 }
 
 void Heap::RunFinalization(JNIEnv* env) {
@@ -3159,7 +3275,7 @@
 }
 
 void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) {
-  CHECK(c == NULL || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
+  CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
         (c->IsVariableSize() || c->GetObjectSize() == byte_count));
   CHECK_GE(byte_count, sizeof(mirror::Object));
 }
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index faaea40..36a3767 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "allocator_type.h"
+#include "arch/instruction_set.h"
 #include "atomic.h"
 #include "base/timing_logger.h"
 #include "gc/accounting/atomic_stack.h"
@@ -32,8 +33,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"
 #include "offsets.h"
@@ -58,6 +57,7 @@
 namespace gc {
 
 class ReferenceProcessor;
+class TaskProcessor;
 
 namespace accounting {
   class HeapBitmap;
@@ -94,7 +94,7 @@
 
 class AgeCardVisitor {
  public:
-  byte operator()(byte card) const {
+  uint8_t operator()(uint8_t card) const {
     if (card == accounting::CardTable::kCardDirty) {
       return card - 1;
     } else {
@@ -216,7 +216,11 @@
 
   // Visit all of the live objects in the heap.
   void VisitObjects(ObjectCallback callback, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+  void VisitObjectsInternal(ObjectCallback callback, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
 
   void CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -245,7 +249,7 @@
   void VerifyHeap() LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
   // Returns how many failures occured.
   size_t VerifyHeapReferences(bool verify_referents = true)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool VerifyMissingCardMarks()
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
@@ -302,6 +306,10 @@
   // implement dalvik.system.VMRuntime.clearGrowthLimit.
   void ClearGrowthLimit();
 
+  // Make the current growth limit the new maximum capacity, unmaps pages at the end of spaces
+  // which will never be used. Used to implement dalvik.system.VMRuntime.clampGrowthLimit.
+  void ClampGrowthLimit();
+
   // Target ideal heap utilization ratio, implements
   // dalvik.system.VMRuntime.getTargetHeapUtilization.
   double GetTargetHeapUtilization() const {
@@ -383,18 +391,18 @@
 
   // Must be called if a field of an Object in the heap changes, and before any GC safe-point.
   // The call is not needed if NULL is stored in the field.
-  void WriteBarrierField(const mirror::Object* dst, MemberOffset /*offset*/,
-                         const mirror::Object* /*new_value*/) {
+  ALWAYS_INLINE void WriteBarrierField(const mirror::Object* dst, MemberOffset /*offset*/,
+                                       const mirror::Object* /*new_value*/) {
     card_table_->MarkCard(dst);
   }
 
   // Write barrier for array operations that update many field positions
-  void WriteBarrierArray(const mirror::Object* dst, int /*start_offset*/,
-                         size_t /*length TODO: element_count or byte_count?*/) {
+  ALWAYS_INLINE void WriteBarrierArray(const mirror::Object* dst, int /*start_offset*/,
+                                       size_t /*length TODO: element_count or byte_count?*/) {
     card_table_->MarkCard(dst);
   }
 
-  void WriteBarrierEveryFieldOf(const mirror::Object* obj) {
+  ALWAYS_INLINE void WriteBarrierEveryFieldOf(const mirror::Object* obj) {
     card_table_->MarkCard(obj);
   }
 
@@ -471,11 +479,11 @@
 
   void DumpForSigQuit(std::ostream& os);
 
-  // Do a pending heap transition or trim.
-  void DoPendingTransitionOrTrim() LOCKS_EXCLUDED(heap_trim_request_lock_);
+  // Do a pending collector transition.
+  void DoPendingCollectorTransition();
 
-  // Trim the managed and native heaps by releasing unused memory back to the OS.
-  void Trim() LOCKS_EXCLUDED(heap_trim_request_lock_);
+  // Deflate monitors, ... and trim the spaces.
+  void Trim(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
 
   void RevokeThreadLocalBuffers(Thread* thread);
   void RevokeRosAllocThreadLocalBuffers(Thread* thread);
@@ -602,20 +610,30 @@
   void RemoveRememberedSet(space::Space* space);
 
   bool IsCompilingBoot() const;
-  bool RunningOnValgrind() const {
-    return running_on_valgrind_;
-  }
   bool HasImageSpace() const;
 
   ReferenceProcessor* GetReferenceProcessor() {
     return &reference_processor_;
   }
+  TaskProcessor* GetTaskProcessor() {
+    return task_processor_.get();
+  }
 
   bool HasZygoteSpace() const {
     return zygote_space_ != nullptr;
   }
 
+  // Request an asynchronous trim.
+  void RequestTrim(Thread* self) LOCKS_EXCLUDED(pending_task_lock_);
+
+  // Request asynchronous GC.
+  void RequestConcurrentGC(Thread* self) LOCKS_EXCLUDED(pending_task_lock_);
+
  private:
+  class ConcurrentGCTask;
+  class CollectorTransitionTask;
+  class HeapTrimTask;
+
   // Compact source space to target space.
   void Compact(space::ContinuousMemMapAllocSpace* target_space,
                space::ContinuousMemMapAllocSpace* source_space,
@@ -625,9 +643,8 @@
   void FinishGC(Thread* self, collector::GcType gc_type) LOCKS_EXCLUDED(gc_complete_lock_);
 
   // Create a mem map with a preferred base address.
-  static MemMap* MapAnonymousPreferredAddress(const char* name, byte* request_begin,
-                                              size_t capacity, int prot_flags,
-                                              std::string* out_error_str);
+  static MemMap* MapAnonymousPreferredAddress(const char* name, uint8_t* request_begin,
+                                              size_t capacity, std::string* out_error_str);
 
   bool SupportHSpaceCompaction() const {
     // Returns true if we can do hspace compaction
@@ -659,7 +676,7 @@
 
   // We don't force this to be inlined since it is a slow path.
   template <bool kInstrumented, typename PreFenceVisitor>
-  mirror::Object* AllocLargeObject(Thread* self, mirror::Class* klass, size_t byte_count,
+  mirror::Object* AllocLargeObject(Thread* self, mirror::Class** klass, size_t byte_count,
                                    const PreFenceVisitor& pre_fence_visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -707,12 +724,10 @@
       EXCLUSIVE_LOCKS_REQUIRED(gc_complete_lock_);
 
   void RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time)
-      LOCKS_EXCLUDED(heap_trim_request_lock_);
-  void RequestHeapTrim() LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
+      LOCKS_EXCLUDED(pending_task_lock_);
+
   void RequestConcurrentGCAndSaveObject(Thread* self, mirror::Object** obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void RequestConcurrentGC(Thread* self)
-      LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
   bool IsGCRequestPending() const;
 
   // Sometimes CollectGarbageInternal decides to run a different Gc than you requested. Returns
@@ -730,7 +745,8 @@
   void PrePauseRosAllocVerification(collector::GarbageCollector* gc)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void PreSweepingGcVerification(collector::GarbageCollector* gc)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
   void PostGcVerification(collector::GarbageCollector* gc)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void PostGcVerificationPaused(collector::GarbageCollector* gc)
@@ -757,8 +773,10 @@
 
   // Given the current contents of the alloc space, increase the allowed heap footprint to match
   // the target utilization ratio.  This should only be called immediately after a full garbage
-  // collection.
-  void GrowForUtilization(collector::GarbageCollector* collector_ran);
+  // collection. bytes_allocated_before_gc is used to measure bytes / second for the period which
+  // the GC was run.
+  void GrowForUtilization(collector::GarbageCollector* collector_ran,
+                          uint64_t bytes_allocated_before_gc = 0);
 
   size_t GetPercentFree();
 
@@ -771,10 +789,6 @@
   // Clear cards and update the mod union table.
   void ProcessCards(TimingLogger* timings, bool use_rem_sets);
 
-  // Signal the heap trim daemon that there is something to do, either a heap transition or heap
-  // trim.
-  void SignalHeapTrimDaemon(Thread* self);
-
   // Push an object onto the allocation stack.
   void PushOnAllocationStack(Thread* self, mirror::Object** obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -783,12 +797,22 @@
   void PushOnThreadLocalAllocationStackWithInternalGC(Thread* thread, mirror::Object** obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void ClearConcurrentGCRequest();
+  void ClearPendingTrim(Thread* self) LOCKS_EXCLUDED(pending_task_lock_);
+  void ClearPendingCollectorTransition(Thread* self) LOCKS_EXCLUDED(pending_task_lock_);
+
   // What kind of concurrency behavior is the runtime after? Currently true for concurrent mark
   // sweep GC, false for other GC types.
   bool IsGcConcurrent() const ALWAYS_INLINE {
     return collector_type_ == kCollectorTypeCMS || collector_type_ == kCollectorTypeCC;
   }
 
+  // Trim the managed and native spaces by releasing unused memory back to the OS.
+  void TrimSpaces(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+
+  // Trim 0 pages at the end of reference tables.
+  void TrimIndirectReferenceTables(Thread* self);
+
   // All-known continuous spaces, where objects lie within fixed bounds.
   std::vector<space::ContinuousSpace*> continuous_spaces_;
 
@@ -835,14 +859,8 @@
   // Desired collector type, heap trimming daemon transitions the heap if it is != collector_type_.
   CollectorType desired_collector_type_;
 
-  // Lock which guards heap trim requests.
-  Mutex* heap_trim_request_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  // When we want to perform the next heap trim (nano seconds).
-  uint64_t last_trim_time_ GUARDED_BY(heap_trim_request_lock_);
-  // When we want to perform the next heap transition (nano seconds) or heap trim.
-  uint64_t heap_transition_or_trim_target_time_ GUARDED_BY(heap_trim_request_lock_);
-  // If we have a heap trim request pending.
-  bool heap_trim_request_pending_ GUARDED_BY(heap_trim_request_lock_);
+  // Lock which guards pending tasks.
+  Mutex* pending_task_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
 
   // How many GC threads we may use for paused parts of garbage collection.
   const size_t parallel_gc_threads_;
@@ -882,6 +900,9 @@
   // Reference processor;
   ReferenceProcessor reference_processor_;
 
+  // Task processor, proxies heap trim requests to the daemon threads.
+  std::unique_ptr<TaskProcessor> task_processor_;
+
   // True while the garbage collector is running.
   volatile CollectorType collector_type_running_ GUARDED_BY(gc_complete_lock_);
 
@@ -890,7 +911,7 @@
   collector::GcType next_gc_type_;
 
   // Maximum size that the heap can reach.
-  const size_t capacity_;
+  size_t capacity_;
 
   // The size the heap is limited to. This is initially smaller than capacity, but for largeHeap
   // programs it is "cleared" making it the same as capacity.
@@ -968,12 +989,6 @@
   // Parallel GC data structures.
   std::unique_ptr<ThreadPool> thread_pool_;
 
-  // The nanosecond time at which the last GC ended.
-  uint64_t last_gc_time_ns_;
-
-  // How many bytes were allocated at the end of the last GC.
-  uint64_t last_gc_size_;
-
   // Estimated allocation rate (bytes / second). Computed between the time of the last GC cycle
   // and the start of the current one.
   uint64_t allocation_rate_;
@@ -1060,9 +1075,17 @@
   // Count for performed homogeneous space compaction.
   Atomic<size_t> count_performed_homogeneous_space_compaction_;
 
+  // Whether or not a concurrent GC is pending.
+  Atomic<bool> concurrent_gc_pending_;
+
+  // Active tasks which we can modify (change target time, desired collector type, etc..).
+  CollectorTransitionTask* pending_collector_transition_ GUARDED_BY(pending_task_lock_);
+  HeapTrimTask* pending_heap_trim_ GUARDED_BY(pending_task_lock_);
+
   // Whether or not we use homogeneous space compaction to avoid OOM errors.
   bool use_homogeneous_space_compaction_for_oom_;
 
+  friend class CollectorTransitionTask;
   friend class collector::GarbageCollector;
   friend class collector::MarkCompact;
   friend class collector::MarkSweep;
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index e6b5c75..73196b2 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -48,8 +48,8 @@
     Handle<mirror::Class> c(
         hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")));
     for (size_t i = 0; i < 1024; ++i) {
-      StackHandleScope<1> hs(soa.Self());
-      Handle<mirror::ObjectArray<mirror::Object>> array(hs.NewHandle(
+      StackHandleScope<1> hs2(soa.Self());
+      Handle<mirror::ObjectArray<mirror::Object>> array(hs2.NewHandle(
           mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), c.Get(), 2048)));
       for (size_t j = 0; j < 2048; ++j) {
         mirror::String* string = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!");
@@ -62,7 +62,7 @@
 }
 
 TEST_F(HeapTest, HeapBitmapCapacityTest) {
-  byte* heap_begin = reinterpret_cast<byte*>(0x1000);
+  uint8_t* heap_begin = reinterpret_cast<uint8_t*>(0x1000);
   const size_t heap_capacity = kObjectAlignment * (sizeof(intptr_t) * 8 + 1);
   std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap(
       accounting::ContinuousSpaceBitmap::Create("test bitmap", heap_begin, heap_capacity));
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index bfaa2bb..01e8795 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -23,11 +23,14 @@
 #include "reflection.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
+#include "task_processor.h"
 #include "well_known_classes.h"
 
 namespace art {
 namespace gc {
 
+static constexpr bool kAsyncReferenceQueueAdd = false;
+
 ReferenceProcessor::ReferenceProcessor()
     : process_references_args_(nullptr, nullptr, nullptr),
       preserving_references_(false),
@@ -143,7 +146,7 @@
   soft_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
   weak_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
   {
-    TimingLogger::ScopedTiming t(concurrent ? "EnqueueFinalizerReferences" :
+    TimingLogger::ScopedTiming t2(concurrent ? "EnqueueFinalizerReferences" :
         "(Paused)EnqueueFinalizerReferences", timings);
     if (concurrent) {
       StartPreservingReferences(self);
@@ -213,17 +216,43 @@
   cleared_references_.UpdateRoots(callback, arg);
 }
 
+class ClearedReferenceTask : public HeapTask {
+ public:
+  explicit ClearedReferenceTask(jobject cleared_references)
+      : HeapTask(NanoTime()), cleared_references_(cleared_references) {
+  }
+  virtual void Run(Thread* thread) {
+    ScopedObjectAccess soa(thread);
+    jvalue args[1];
+    args[0].l = cleared_references_;
+    InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
+    soa.Env()->DeleteGlobalRef(cleared_references_);
+  }
+
+ private:
+  const jobject cleared_references_;
+};
+
 void ReferenceProcessor::EnqueueClearedReferences(Thread* self) {
   Locks::mutator_lock_->AssertNotHeld(self);
+  // When a runtime isn't started there are no reference queues to care about so ignore.
   if (!cleared_references_.IsEmpty()) {
-    // When a runtime isn't started there are no reference queues to care about so ignore.
     if (LIKELY(Runtime::Current()->IsStarted())) {
-      ScopedObjectAccess soa(self);
-      ScopedLocalRef<jobject> arg(self->GetJniEnv(),
-                                  soa.AddLocalReference<jobject>(cleared_references_.GetList()));
-      jvalue args[1];
-      args[0].l = arg.get();
-      InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
+      jobject cleared_references;
+      {
+        ReaderMutexLock mu(self, *Locks::mutator_lock_);
+        cleared_references = self->GetJniEnv()->vm->AddGlobalRef(
+            self, cleared_references_.GetList());
+      }
+      if (kAsyncReferenceQueueAdd) {
+        // TODO: This can cause RunFinalization to terminate before newly freed objects are
+        // finalized since they may not be enqueued by the time RunFinalization starts.
+        Runtime::Current()->GetHeap()->GetTaskProcessor()->AddTask(
+            self, new ClearedReferenceTask(cleared_references));
+      } else {
+        ClearedReferenceTask task(cleared_references);
+        task.Run(self);
+      }
     }
     cleared_references_.Clear();
   }
@@ -234,7 +263,7 @@
   MutexLock mu(self, *Locks::reference_processor_lock_);
   // Wait untul we are done processing reference.
   while (SlowPathEnabled()) {
-    condition_.Wait(self);
+    condition_.WaitHoldingLocks(self);
   }
   // At this point, since the sentinel of the reference is live, it is guaranteed to not be
   // enqueued if we just finished processing references. Otherwise, we may be doing the main GC
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index 4003524..f4efe3c 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -91,15 +91,30 @@
 void ReferenceQueue::Dump(std::ostream& os) const {
   mirror::Reference* cur = list_;
   os << "Reference starting at list_=" << list_ << "\n";
-  while (cur != nullptr) {
+  if (cur == nullptr) {
+    return;
+  }
+  do {
     mirror::Reference* pending_next = cur->GetPendingNext();
-    os << "PendingNext=" << pending_next;
+    os << "Reference= " << cur << " PendingNext=" << pending_next;
     if (cur->IsFinalizerReferenceInstance()) {
       os << " Zombie=" << cur->AsFinalizerReference()->GetZombie();
     }
     os << "\n";
     cur = pending_next;
+  } while (cur != list_);
+}
+
+size_t ReferenceQueue::GetLength() const {
+  size_t count = 0;
+  mirror::Reference* cur = list_;
+  if (cur != nullptr) {
+    do {
+      ++count;
+      cur = cur->GetPendingNext();
+    } while (cur != list_);
   }
+  return count;
 }
 
 void ReferenceQueue::ClearWhiteReferences(ReferenceQueue* cleared_references,
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index dbf4abc..f7d89d0 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_);
+
+  // Enqueue a reference without checking that it is enqueable.
   void EnqueuePendingReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Dequeue the first reference (returns list_).
   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.
+
+  // 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
+
+  // 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_);
+
+  void Dump(std::ostream& os) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  size_t GetLength() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsEmpty() const {
     return list_ == nullptr;
   }
   void Clear() {
     list_ = nullptr;
   }
-  mirror::Reference* GetList() {
+  mirror::Reference* GetList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     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,12 @@
  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/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
new file mode 100644
index 0000000..888c0d2
--- /dev/null
+++ b/runtime/gc/reference_queue_test.cc
@@ -0,0 +1,85 @@
+/*
+ * 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 "common_runtime_test.h"
+#include "reference_queue.h"
+#include "handle_scope-inl.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace gc {
+
+class ReferenceQueueTest : public CommonRuntimeTest {};
+
+TEST_F(ReferenceQueueTest, EnqueueDequeue) {
+  Thread* self = Thread::Current();
+  StackHandleScope<20> hs(self);
+  Mutex lock("Reference queue lock");
+  ReferenceQueue queue(&lock);
+  ASSERT_TRUE(queue.IsEmpty());
+  ScopedObjectAccess soa(self);
+  ASSERT_EQ(queue.GetLength(), 0U);
+  auto ref_class = hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
+                                                      NullHandle<mirror::ClassLoader>()));
+  ASSERT_TRUE(ref_class.Get() != nullptr);
+  auto ref1(hs.NewHandle(ref_class->AllocObject(self)->AsReference()));
+  ASSERT_TRUE(ref1.Get() != nullptr);
+  auto ref2(hs.NewHandle(ref_class->AllocObject(self)->AsReference()));
+  ASSERT_TRUE(ref2.Get() != nullptr);
+  // FIFO ordering.
+  queue.EnqueuePendingReference(ref1.Get());
+  ASSERT_TRUE(!queue.IsEmpty());
+  ASSERT_EQ(queue.GetLength(), 1U);
+  queue.EnqueuePendingReference(ref2.Get());
+  ASSERT_TRUE(!queue.IsEmpty());
+  ASSERT_EQ(queue.GetLength(), 2U);
+  ASSERT_EQ(queue.DequeuePendingReference(), ref2.Get());
+  ASSERT_TRUE(!queue.IsEmpty());
+  ASSERT_EQ(queue.GetLength(), 1U);
+  ASSERT_EQ(queue.DequeuePendingReference(), ref1.Get());
+  ASSERT_EQ(queue.GetLength(), 0U);
+  ASSERT_TRUE(queue.IsEmpty());
+}
+
+TEST_F(ReferenceQueueTest, Dump) {
+  Thread* self = Thread::Current();
+  StackHandleScope<20> hs(self);
+  Mutex lock("Reference queue lock");
+  ReferenceQueue queue(&lock);
+  ScopedObjectAccess soa(self);
+  queue.Dump(LOG(INFO));
+  auto weak_ref_class = hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
+                                                      NullHandle<mirror::ClassLoader>()));
+  ASSERT_TRUE(weak_ref_class.Get() != nullptr);
+  auto finalizer_ref_class = hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/FinalizerReference;",
+                                                      NullHandle<mirror::ClassLoader>()));
+  ASSERT_TRUE(finalizer_ref_class.Get() != nullptr);
+  auto ref1(hs.NewHandle(weak_ref_class->AllocObject(self)->AsReference()));
+  ASSERT_TRUE(ref1.Get() != nullptr);
+  auto ref2(hs.NewHandle(finalizer_ref_class->AllocObject(self)->AsReference()));
+  ASSERT_TRUE(ref2.Get() != nullptr);
+  queue.EnqueuePendingReference(ref1.Get());
+  queue.Dump(LOG(INFO));
+  queue.EnqueuePendingReference(ref2.Get());
+  queue.Dump(LOG(INFO));
+}
+
+}  // namespace gc
+}  // namespace art
diff --git a/runtime/gc/space/bump_pointer_space-inl.h b/runtime/gc/space/bump_pointer_space-inl.h
index ee3c979..9f1f953 100644
--- a/runtime/gc/space/bump_pointer_space-inl.h
+++ b/runtime/gc/space/bump_pointer_space-inl.h
@@ -41,7 +41,7 @@
                                                            size_t* usable_size) {
   Locks::mutator_lock_->AssertExclusiveHeld(self);
   num_bytes = RoundUp(num_bytes, kAlignment);
-  byte* end = end_.LoadRelaxed();
+  uint8_t* end = end_.LoadRelaxed();
   if (end + num_bytes > growth_end_) {
     return nullptr;
   }
@@ -59,8 +59,8 @@
 
 inline mirror::Object* BumpPointerSpace::AllocNonvirtualWithoutAccounting(size_t num_bytes) {
   DCHECK(IsAligned<kAlignment>(num_bytes));
-  byte* old_end;
-  byte* new_end;
+  uint8_t* old_end;
+  uint8_t* new_end;
   do {
     old_end = end_.LoadRelaxed();
     new_end = old_end + num_bytes;
diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc
index fb6bbac..04b09e9 100644
--- a/runtime/gc/space/bump_pointer_space.cc
+++ b/runtime/gc/space/bump_pointer_space.cc
@@ -25,7 +25,7 @@
 namespace space {
 
 BumpPointerSpace* BumpPointerSpace::Create(const std::string& name, size_t capacity,
-                                           byte* requested_begin) {
+                                           uint8_t* requested_begin) {
   capacity = RoundUp(capacity, kPageSize);
   std::string error_msg;
   std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity,
@@ -42,7 +42,7 @@
   return new BumpPointerSpace(name, mem_map);
 }
 
-BumpPointerSpace::BumpPointerSpace(const std::string& name, byte* begin, byte* limit)
+BumpPointerSpace::BumpPointerSpace(const std::string& name, uint8_t* begin, uint8_t* limit)
     : ContinuousMemMapAllocSpace(name, nullptr, begin, begin, limit,
                                  kGcRetentionPolicyAlwaysCollect),
       growth_end_(limit),
@@ -134,12 +134,12 @@
 }
 
 // Returns the start of the storage.
-byte* BumpPointerSpace::AllocBlock(size_t bytes) {
+uint8_t* BumpPointerSpace::AllocBlock(size_t bytes) {
   bytes = RoundUp(bytes, kAlignment);
   if (!num_blocks_) {
     UpdateMainBlock();
   }
-  byte* storage = reinterpret_cast<byte*>(
+  uint8_t* storage = reinterpret_cast<uint8_t*>(
       AllocNonvirtualWithoutAccounting(bytes + sizeof(BlockHeader)));
   if (LIKELY(storage != nullptr)) {
     BlockHeader* header = reinterpret_cast<BlockHeader*>(storage);
@@ -151,9 +151,9 @@
 }
 
 void BumpPointerSpace::Walk(ObjectCallback* callback, void* arg) {
-  byte* pos = Begin();
-  byte* end = End();
-  byte* main_end = pos;
+  uint8_t* pos = Begin();
+  uint8_t* end = End();
+  uint8_t* main_end = pos;
   {
     MutexLock mu(Thread::Current(), block_lock_);
     // If we have 0 blocks then we need to update the main header since we have bump pointer style
@@ -179,7 +179,7 @@
       return;
     } else {
       callback(obj, arg);
-      pos = reinterpret_cast<byte*>(GetNextObject(obj));
+      pos = reinterpret_cast<uint8_t*>(GetNextObject(obj));
     }
   }
   // Walk the other blocks (currently only TLABs).
@@ -188,11 +188,11 @@
     size_t block_size = header->size_;
     pos += sizeof(BlockHeader);  // Skip the header so that we know where the objects
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(pos);
-    const mirror::Object* end = reinterpret_cast<const mirror::Object*>(pos + block_size);
-    CHECK_LE(reinterpret_cast<const byte*>(end), End());
+    const mirror::Object* end_obj = reinterpret_cast<const mirror::Object*>(pos + block_size);
+    CHECK_LE(reinterpret_cast<const uint8_t*>(end_obj), End());
     // We don't know how many objects are allocated in the current block. When we hit a null class
     // assume its the end. TODO: Have a thread update the header when it flushes the block?
-    while (obj < end && obj->GetClass() != nullptr) {
+    while (obj < end_obj && obj->GetClass() != nullptr) {
       callback(obj, arg);
       obj = GetNextObject(obj);
     }
@@ -201,8 +201,8 @@
 }
 
 accounting::ContinuousSpaceBitmap::SweepCallback* BumpPointerSpace::GetSweepCallback() {
-  LOG(FATAL) << "Unimplemented";
-  return nullptr;
+  UNIMPLEMENTED(FATAL);
+  UNREACHABLE();
 }
 
 uint64_t BumpPointerSpace::GetBytesAllocated() {
@@ -250,7 +250,7 @@
 bool BumpPointerSpace::AllocNewTlab(Thread* self, size_t bytes) {
   MutexLock mu(Thread::Current(), block_lock_);
   RevokeThreadLocalBuffersLocked(self);
-  byte* start = AllocBlock(bytes);
+  uint8_t* start = AllocBlock(bytes);
   if (start == nullptr) {
     return false;
   }
diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h
index 71b15ba..089ede4 100644
--- a/runtime/gc/space/bump_pointer_space.h
+++ b/runtime/gc/space/bump_pointer_space.h
@@ -42,7 +42,7 @@
   // Create a bump pointer space with the requested sizes. The requested base address is not
   // guaranteed to be granted, if it is required, the caller should call Begin on the returned
   // space to confirm the request was granted.
-  static BumpPointerSpace* Create(const std::string& name, size_t capacity, byte* requested_begin);
+  static BumpPointerSpace* Create(const std::string& name, size_t capacity, uint8_t* requested_begin);
   static BumpPointerSpace* CreateFromMemMap(const std::string& name, MemMap* mem_map);
 
   // Allocate num_bytes, returns nullptr if the space is full.
@@ -121,12 +121,12 @@
   }
 
   bool Contains(const mirror::Object* obj) const {
-    const byte* byte_obj = reinterpret_cast<const byte*>(obj);
+    const uint8_t* byte_obj = reinterpret_cast<const uint8_t*>(obj);
     return byte_obj >= Begin() && byte_obj < End();
   }
 
   // TODO: Change this? Mainly used for compacting to a particular region of memory.
-  BumpPointerSpace(const std::string& name, byte* begin, byte* limit);
+  BumpPointerSpace(const std::string& name, uint8_t* begin, uint8_t* limit);
 
   // Return the object which comes after obj, while ensuring alignment.
   static mirror::Object* GetNextObject(mirror::Object* obj)
@@ -161,7 +161,7 @@
   BumpPointerSpace(const std::string& name, MemMap* mem_map);
 
   // Allocate a raw block of bytes.
-  byte* AllocBlock(size_t bytes) EXCLUSIVE_LOCKS_REQUIRED(block_lock_);
+  uint8_t* AllocBlock(size_t bytes) EXCLUSIVE_LOCKS_REQUIRED(block_lock_);
   void RevokeThreadLocalBuffersLocked(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(block_lock_);
 
   // The main block is an unbounded block where objects go when there are no other blocks. This
@@ -169,7 +169,7 @@
   // allocation. The main block starts at the space Begin().
   void UpdateMainBlock() EXCLUSIVE_LOCKS_REQUIRED(block_lock_);
 
-  byte* growth_end_;
+  uint8_t* growth_end_;
   AtomicInteger objects_allocated_;  // Accumulated from revoked thread local regions.
   AtomicInteger bytes_allocated_;  // Accumulated from revoked thread local regions.
   Mutex block_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -186,8 +186,8 @@
     size_t unused_;  // Ensures alignment of kAlignment.
   };
 
-  COMPILE_ASSERT(sizeof(BlockHeader) % kAlignment == 0,
-                 continuous_block_must_be_kAlignment_aligned);
+  static_assert(sizeof(BlockHeader) % kAlignment == 0,
+                "continuous block must be kAlignment aligned");
 
   friend class collector::MarkSweep;
   DISALLOW_COPY_AND_ASSIGN(BumpPointerSpace);
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 456d1b3..b8a9dd6 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -33,12 +33,9 @@
 
 static constexpr bool kPrefetchDuringDlMallocFreeList = true;
 
-template class ValgrindMallocSpace<DlMallocSpace, void*>;
-
-DlMallocSpace::DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
-                             byte* end, byte* limit, size_t growth_limit,
-                             bool can_move_objects, size_t starting_size,
-                             size_t initial_size)
+DlMallocSpace::DlMallocSpace(MemMap* mem_map, size_t initial_size, const std::string& name,
+                             void* mspace, uint8_t* begin, uint8_t* end, uint8_t* limit,
+                             size_t growth_limit, bool can_move_objects, size_t starting_size)
     : MallocSpace(name, mem_map, begin, end, limit, growth_limit, true, can_move_objects,
                   starting_size, initial_size),
       mspace_(mspace) {
@@ -57,25 +54,25 @@
   }
 
   // Protect memory beyond the starting size. morecore will add r/w permissions when necessory
-  byte* end = mem_map->Begin() + starting_size;
+  uint8_t* end = mem_map->Begin() + starting_size;
   if (capacity - starting_size > 0) {
     CHECK_MEMORY_CALL(mprotect, (end, capacity - starting_size, PROT_NONE), name);
   }
 
   // Everything is set so record in immutable structure and leave
-  byte* begin = mem_map->Begin();
+  uint8_t* begin = mem_map->Begin();
   if (Runtime::Current()->RunningOnValgrind()) {
-    return new ValgrindMallocSpace<DlMallocSpace, void*>(
-        name, mem_map, mspace, begin, end, begin + capacity, growth_limit, initial_size,
+    return new ValgrindMallocSpace<DlMallocSpace, kDefaultValgrindRedZoneBytes, true, false>(
+        mem_map, initial_size, name, mspace, begin, end, begin + capacity, growth_limit,
         can_move_objects, starting_size);
   } else {
-    return new DlMallocSpace(name, mem_map, mspace, begin, end, begin + capacity, growth_limit,
-                             can_move_objects, starting_size, initial_size);
+    return new DlMallocSpace(mem_map, initial_size, name, mspace, begin, end, begin + capacity,
+                             growth_limit, can_move_objects, starting_size);
   }
 }
 
 DlMallocSpace* DlMallocSpace::Create(const std::string& name, size_t initial_size,
-                                     size_t growth_limit, size_t capacity, byte* requested_begin,
+                                     size_t growth_limit, size_t capacity, uint8_t* requested_begin,
                                      bool can_move_objects) {
   uint64_t start_time = 0;
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -148,12 +145,18 @@
   return result;
 }
 
-MallocSpace* DlMallocSpace::CreateInstance(const std::string& name, MemMap* mem_map,
-                                           void* allocator, byte* begin, byte* end,
-                                           byte* limit, size_t growth_limit,
+MallocSpace* DlMallocSpace::CreateInstance(MemMap* mem_map, const std::string& name,
+                                           void* allocator, uint8_t* begin, uint8_t* end,
+                                           uint8_t* limit, size_t growth_limit,
                                            bool can_move_objects) {
-  return new DlMallocSpace(name, mem_map, allocator, begin, end, limit, growth_limit,
-                           can_move_objects, starting_size_, initial_size_);
+  if (Runtime::Current()->RunningOnValgrind()) {
+    return new ValgrindMallocSpace<DlMallocSpace, kDefaultValgrindRedZoneBytes, true, false>(
+        mem_map, initial_size_, name, allocator, begin, end, limit, growth_limit,
+        can_move_objects, starting_size_);
+  } else {
+    return new DlMallocSpace(mem_map, initial_size_, name, allocator, begin, end, limit,
+                             growth_limit, can_move_objects, starting_size_);
+  }
 }
 
 size_t DlMallocSpace::Free(Thread* self, mirror::Object* ptr) {
@@ -213,27 +216,6 @@
   }
 }
 
-// Callback from dlmalloc when it needs to increase the footprint
-extern "C" void* art_heap_morecore(void* mspace, intptr_t increment) {
-  Heap* heap = Runtime::Current()->GetHeap();
-  DlMallocSpace* dlmalloc_space = heap->GetDlMallocSpace();
-  // Support for multiple DlMalloc provided by a slow path.
-  if (UNLIKELY(dlmalloc_space == nullptr || dlmalloc_space->GetMspace() != mspace)) {
-    dlmalloc_space = nullptr;
-    for (space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
-      if (space->IsDlMallocSpace()) {
-        DlMallocSpace* cur_dlmalloc_space = space->AsDlMallocSpace();
-        if (cur_dlmalloc_space->GetMspace() == mspace) {
-          dlmalloc_space = cur_dlmalloc_space;
-          break;
-        }
-      }
-    }
-    CHECK(dlmalloc_space != nullptr) << "Couldn't find DlmMallocSpace with mspace=" << mspace;
-  }
-  return dlmalloc_space->MoreCore(increment);
-}
-
 size_t DlMallocSpace::Trim() {
   MutexLock mu(Thread::Current(), lock_);
   // Trim to release memory at the end of the space.
@@ -314,6 +296,7 @@
 }
 
 void DlMallocSpace::LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) {
+  UNUSED(failed_alloc_bytes);
   Thread* self = Thread::Current();
   size_t max_contiguous_allocation = 0;
   // To allow the Walk/InspectAll() to exclusively-lock the mutator
@@ -329,5 +312,31 @@
 }
 
 }  // namespace space
+
+namespace allocator {
+
+// Implement the dlmalloc morecore callback.
+void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) {
+  Heap* heap = Runtime::Current()->GetHeap();
+  ::art::gc::space::DlMallocSpace* dlmalloc_space = heap->GetDlMallocSpace();
+  // Support for multiple DlMalloc provided by a slow path.
+  if (UNLIKELY(dlmalloc_space == nullptr || dlmalloc_space->GetMspace() != mspace)) {
+    dlmalloc_space = nullptr;
+    for (space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
+      if (space->IsDlMallocSpace()) {
+        ::art::gc::space::DlMallocSpace* cur_dlmalloc_space = space->AsDlMallocSpace();
+        if (cur_dlmalloc_space->GetMspace() == mspace) {
+          dlmalloc_space = cur_dlmalloc_space;
+          break;
+        }
+      }
+    }
+    CHECK(dlmalloc_space != nullptr) << "Couldn't find DlmMallocSpace with mspace=" << mspace;
+  }
+  return dlmalloc_space->MoreCore(increment);
+}
+
+}  // namespace allocator
+
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index 7aff14b..6ce138c 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -44,7 +44,7 @@
   // the caller should call Begin on the returned space to confirm the
   // request was granted.
   static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
-                               size_t capacity, byte* requested_begin, bool can_move_objects);
+                               size_t capacity, uint8_t* requested_begin, bool can_move_objects);
 
   // Virtual to allow ValgrindMallocSpace to intercept.
   virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated,
@@ -107,8 +107,8 @@
   // allocations fail we GC before increasing the footprint limit and allowing the mspace to grow.
   void SetFootprintLimit(size_t limit) OVERRIDE;
 
-  MallocSpace* CreateInstance(const std::string& name, MemMap* mem_map, void* allocator,
-                              byte* begin, byte* end, byte* limit, size_t growth_limit,
+  MallocSpace* CreateInstance(MemMap* mem_map, const std::string& name, void* allocator,
+                              uint8_t* begin, uint8_t* end, uint8_t* limit, size_t growth_limit,
                               bool can_move_objects);
 
   uint64_t GetBytesAllocated() OVERRIDE;
@@ -128,9 +128,9 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
-  DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin, byte* end,
-                byte* limit, size_t growth_limit, bool can_move_objects, size_t starting_size,
-                size_t initial_size);
+  DlMallocSpace(MemMap* mem_map, size_t initial_size, const std::string& name, void* mspace,
+                uint8_t* begin, uint8_t* end, uint8_t* limit, size_t growth_limit,
+                bool can_move_objects, size_t starting_size);
 
  private:
   mirror::Object* AllocWithoutGrowthLocked(Thread* self, size_t num_bytes, size_t* bytes_allocated,
@@ -144,7 +144,7 @@
   static void* CreateMspace(void* base, size_t morecore_start, size_t initial_size);
 
   // The boundary tag overhead.
-  static const size_t kChunkOverhead = kWordSize;
+  static const size_t kChunkOverhead = sizeof(intptr_t);
 
   // Underlying malloc space.
   void* mspace_;
diff --git a/runtime/gc/space/dlmalloc_space_base_test.cc b/runtime/gc/space/dlmalloc_space_base_test.cc
index 02fc4a5..93fe155 100644
--- a/runtime/gc/space/dlmalloc_space_base_test.cc
+++ b/runtime/gc/space/dlmalloc_space_base_test.cc
@@ -24,7 +24,7 @@
 namespace space {
 
 MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, byte* requested_begin) {
+                                 size_t capacity, uint8_t* requested_begin) {
   return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, false);
 }
 
diff --git a/runtime/gc/space/dlmalloc_space_random_test.cc b/runtime/gc/space/dlmalloc_space_random_test.cc
index 4b1a1b1..f9b41da 100644
--- a/runtime/gc/space/dlmalloc_space_random_test.cc
+++ b/runtime/gc/space/dlmalloc_space_random_test.cc
@@ -23,7 +23,7 @@
 namespace space {
 
 MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, byte* requested_begin) {
+                                 size_t capacity, uint8_t* requested_begin) {
   return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, false);
 }
 
diff --git a/runtime/gc/space/dlmalloc_space_static_test.cc b/runtime/gc/space/dlmalloc_space_static_test.cc
index d17d0a7..5758e0c 100644
--- a/runtime/gc/space/dlmalloc_space_static_test.cc
+++ b/runtime/gc/space/dlmalloc_space_static_test.cc
@@ -23,7 +23,7 @@
 namespace space {
 
 MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, byte* requested_begin) {
+                                 size_t capacity, uint8_t* requested_begin) {
   return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, false);
 }
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 59630fe..071997f 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -17,10 +17,12 @@
 #include "image_space.h"
 
 #include <dirent.h>
+#include <sys/statvfs.h>
 #include <sys/types.h>
 
 #include <random>
 
+#include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "base/scoped_flock.h"
@@ -69,18 +71,20 @@
 }
 
 // We are relocating or generating the core image. We should get rid of everything. It is all
-// out-of-date. We also don't really care if this fails since it is just a convienence.
+// out-of-date. We also don't really care if this fails since it is just a convenience.
 // Adapted from prune_dex_cache(const char* subdir) in frameworks/native/cmds/installd/commands.c
 // Note this should only be used during first boot.
-static void RealPruneDexCache(const std::string& cache_dir_path);
-static void PruneDexCache(InstructionSet isa) {
+static void RealPruneDalvikCache(const std::string& cache_dir_path);
+
+static void PruneDalvikCache(InstructionSet isa) {
   CHECK_NE(isa, kNone);
-  // Prune the base /data/dalvik-cache
-  RealPruneDexCache(GetDalvikCacheOrDie(".", false));
-  // prune /data/dalvik-cache/<isa>
-  RealPruneDexCache(GetDalvikCacheOrDie(GetInstructionSetString(isa), false));
+  // Prune the base /data/dalvik-cache.
+  RealPruneDalvikCache(GetDalvikCacheOrDie(".", false));
+  // Prune /data/dalvik-cache/<isa>.
+  RealPruneDalvikCache(GetDalvikCacheOrDie(GetInstructionSetString(isa), false));
 }
-static void RealPruneDexCache(const std::string& cache_dir_path) {
+
+static void RealPruneDalvikCache(const std::string& cache_dir_path) {
   if (!OS::DirectoryExists(cache_dir_path.c_str())) {
     return;
   }
@@ -95,8 +99,8 @@
     if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
       continue;
     }
-    // We only want to delete regular files.
-    if (de->d_type != DT_REG) {
+    // We only want to delete regular files and symbolic links.
+    if (de->d_type != DT_REG && de->d_type != DT_LNK) {
       if (de->d_type != DT_DIR) {
         // We do expect some directories (namely the <isa> for pruning the base dalvik-cache).
         LOG(WARNING) << "Unexpected file type of " << std::hex << de->d_type << " encountered.";
@@ -114,11 +118,33 @@
   CHECK_EQ(0, TEMP_FAILURE_RETRY(closedir(cache_dir))) << "Unable to close directory.";
 }
 
+// We write out an empty file to the zygote's ISA specific cache dir at the start of
+// every zygote boot and delete it when the boot completes. If we find a file already
+// present, it usually means the boot didn't complete. We wipe the entire dalvik
+// cache if that's the case.
+static void MarkZygoteStart(const InstructionSet isa) {
+  const std::string isa_subdir = GetDalvikCacheOrDie(GetInstructionSetString(isa), false);
+  const std::string boot_marker = isa_subdir + "/.booting";
+
+  if (OS::FileExists(boot_marker.c_str())) {
+    LOG(WARNING) << "Incomplete boot detected. Pruning dalvik cache";
+    RealPruneDalvikCache(isa_subdir);
+  }
+
+  VLOG(startup) << "Creating boot start marker: " << boot_marker;
+  std::unique_ptr<File> f(OS::CreateEmptyFile(boot_marker.c_str()));
+  if (f.get() != nullptr) {
+    if (f->FlushCloseOrErase() != 0) {
+      PLOG(WARNING) << "Failed to write boot marker.";
+    }
+  }
+}
+
 static bool GenerateImage(const std::string& image_filename, InstructionSet image_isa,
                           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;
@@ -126,7 +152,7 @@
   // We should clean up so we are more likely to have room for the image.
   if (Runtime::Current()->IsZygote()) {
     LOG(INFO) << "Pruning dalvik-cache since we are generating an image and will need to recompile";
-    PruneDexCache(image_isa);
+    PruneDalvikCache(image_isa);
   }
 
   std::vector<std::string> arg_vector;
@@ -143,9 +169,7 @@
   }
 
   std::string oat_file_option_string("--oat-file=");
-  oat_file_option_string += image_filename;
-  oat_file_option_string.erase(oat_file_option_string.size() - 3);
-  oat_file_option_string += "oat";
+  oat_file_option_string += ImageHeader::GetOatLocationFromImageLocation(image_filename);
   arg_vector.push_back(oat_file_option_string);
 
   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
@@ -230,7 +254,7 @@
   // We should clean up so we are more likely to have room for the image.
   if (Runtime::Current()->IsZygote()) {
     LOG(INFO) << "Pruning dalvik-cache since we are relocating an image and will need to recompile";
-    PruneDexCache(isa);
+    PruneDalvikCache(isa);
   }
 
   std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
@@ -377,6 +401,41 @@
   return false;
 }
 
+static constexpr uint64_t kLowSpaceValue = 50 * MB;
+static constexpr uint64_t kTmpFsSentinelValue = 384 * MB;
+
+// Read the free space of the cache partition and make a decision whether to keep the generated
+// image. This is to try to mitigate situations where the system might run out of space later.
+static bool CheckSpace(const std::string& cache_filename, std::string* error_msg) {
+  // Using statvfs vs statvfs64 because of b/18207376, and it is enough for all practical purposes.
+  struct statvfs buf;
+
+  int res = TEMP_FAILURE_RETRY(statvfs(cache_filename.c_str(), &buf));
+  if (res != 0) {
+    // Could not stat. Conservatively tell the system to delete the image.
+    *error_msg = "Could not stat the filesystem, assuming low-memory situation.";
+    return false;
+  }
+
+  uint64_t fs_overall_size = buf.f_bsize * static_cast<uint64_t>(buf.f_blocks);
+  // Zygote is privileged, but other things are not. Use bavail.
+  uint64_t fs_free_size = buf.f_bsize * static_cast<uint64_t>(buf.f_bavail);
+
+  // Take the overall size as an indicator for a tmpfs, which is being used for the decryption
+  // environment. We do not want to fail quickening the boot image there, as it is beneficial
+  // for time-to-UI.
+  if (fs_overall_size > kTmpFsSentinelValue) {
+    if (fs_free_size < kLowSpaceValue) {
+      *error_msg = StringPrintf("Low-memory situation: only %4.2f megabytes available after image"
+                                " generation, need at least %" PRIu64 ".",
+                                static_cast<double>(fs_free_size) / MB,
+                                kLowSpaceValue / MB);
+      return false;
+    }
+  }
+  return true;
+}
+
 ImageSpace* ImageSpace::Create(const char* image_location,
                                const InstructionSet image_isa,
                                std::string* error_msg) {
@@ -390,6 +449,10 @@
                                              &has_system, &cache_filename, &dalvik_cache_exists,
                                              &has_cache, &is_global_cache);
 
+  if (Runtime::Current()->IsZygote()) {
+    MarkZygoteStart(image_isa);
+  }
+
   ImageSpace* space;
   bool relocate = Runtime::Current()->ShouldRelocate();
   bool can_compile = Runtime::Current()->IsImageDex2OatEnabled();
@@ -434,6 +497,11 @@
             *error_msg = StringPrintf("Unable to relocate image '%s' from '%s' to '%s': %s",
                                       image_location, system_filename.c_str(),
                                       cache_filename.c_str(), reason.c_str());
+            // We failed to create files, remove any possibly garbage output.
+            // Since ImageCreationAllowed was true above, we are the zygote
+            // and therefore the only process expected to generate these for
+            // the device.
+            PruneDalvikCache(image_isa);
             return nullptr;
           }
         }
@@ -480,19 +548,23 @@
       return space;
     }
 
-    // If the /system file exists, it should be up-to-date, don't try to generate it. Same if it is
-    // a relocated copy from something in /system (i.e. checksum's match).
-    // Otherwise, log a warning and fall through to GenerateImage.
     if (relocated_version_used) {
-      LOG(FATAL) << "Attempted to use relocated version of " << image_location << " "
-                 << "at " << cache_filename << " generated from " << system_filename << " "
-                 << "but image failed to load: " << error_msg;
+      // Something is wrong with the relocated copy (even though checksums match). Cleanup.
+      // This can happen if the .oat is corrupt, since the above only checks the .art checksums.
+      // TODO: Check the oat file validity earlier.
+      *error_msg = StringPrintf("Attempted to use relocated version of %s at %s generated from %s "
+                                "but image failed to load: %s",
+                                image_location, cache_filename.c_str(), system_filename.c_str(),
+                                error_msg->c_str());
+      PruneDalvikCache(image_isa);
       return nullptr;
     } else if (is_system) {
+      // If the /system file exists, it should be up-to-date, don't try to generate it.
       *error_msg = StringPrintf("Failed to load /system image '%s': %s",
                                 image_filename->c_str(), error_msg->c_str());
       return nullptr;
     } else {
+      // Otherwise, log a warning and fall through to GenerateImage.
       LOG(WARNING) << *error_msg;
     }
   }
@@ -508,8 +580,20 @@
   } else if (!GenerateImage(cache_filename, image_isa, error_msg)) {
     *error_msg = StringPrintf("Failed to generate image '%s': %s",
                               cache_filename.c_str(), error_msg->c_str());
+    // We failed to create files, remove any possibly garbage output.
+    // Since ImageCreationAllowed was true above, we are the zygote
+    // and therefore the only process expected to generate these for
+    // the device.
+    PruneDalvikCache(image_isa);
     return nullptr;
   } else {
+    // Check whether there is enough space left over after we have generated the image.
+    if (!CheckSpace(cache_filename, error_msg)) {
+      // No. Delete the generated image and try to run out of the dex files.
+      PruneDalvikCache(image_isa);
+      return nullptr;
+    }
+
     // Note that we must not use the file descriptor associated with
     // ScopedFlock::GetFile to Init the image file. We want the file
     // descriptor (and the associated exclusive lock) to be released when
@@ -526,7 +610,7 @@
 }
 
 void ImageSpace::VerifyImageAllocations() {
-  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
+  uint8_t* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
   while (current < End()) {
     DCHECK_ALIGNED(current, kObjectAlignment);
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(current);
@@ -595,7 +679,7 @@
                                        bitmap_index));
   std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap(
       accounting::ContinuousSpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
-                                                          reinterpret_cast<byte*>(map->Begin()),
+                                                          reinterpret_cast<uint8_t*>(map->Begin()),
                                                           map->Size()));
   if (bitmap.get() == nullptr) {
     *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
@@ -629,6 +713,9 @@
   runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
   mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod);
   runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method));
+  mirror::Object* imt_unimplemented_method =
+      image_header.GetImageRoot(ImageHeader::kImtUnimplementedMethod);
+  runtime->SetImtUnimplementedMethod(down_cast<mirror::ArtMethod*>(imt_unimplemented_method));
   mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt);
   runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
 
@@ -653,7 +740,10 @@
   const ImageHeader& image_header = GetImageHeader();
   std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_path);
 
+  CHECK(image_header.GetOatDataBegin() != nullptr);
+
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
+                                    image_header.GetOatFileBegin(),
                                     !Runtime::Current()->IsCompiler(), error_msg);
   if (oat_file == NULL) {
     *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
@@ -669,7 +759,7 @@
   }
   int32_t image_patch_delta = image_header.GetPatchDelta();
   int32_t oat_patch_delta = oat_file->GetOatHeader().GetImagePatchDelta();
-  if (oat_patch_delta != image_patch_delta) {
+  if (oat_patch_delta != image_patch_delta && !image_header.CompilePic()) {
     // We should have already relocated by this point. Bail out.
     *error_msg = StringPrintf("Failed to match oat file patch delta %d to expected patch delta %d "
                               "in image %s", oat_patch_delta, image_patch_delta, GetName());
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index dad5855..c0c6444 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -45,7 +45,7 @@
     mirror::Object* object_without_rdz = reinterpret_cast<mirror::Object*>(
         reinterpret_cast<uintptr_t>(obj) + kValgrindRedZoneBytes);
     VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<void*>(obj), kValgrindRedZoneBytes);
-    VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(object_without_rdz) + num_bytes,
+    VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<uint8_t*>(object_without_rdz) + num_bytes,
                                kValgrindRedZoneBytes);
     if (usable_size != nullptr) {
       *usable_size = num_bytes;  // Since we have redzones, shrink the usable size.
@@ -84,7 +84,7 @@
   mark_bitmap_->SetName(temp_name);
 }
 
-LargeObjectSpace::LargeObjectSpace(const std::string& name, byte* begin, byte* end)
+LargeObjectSpace::LargeObjectSpace(const std::string& name, uint8_t* begin, uint8_t* end)
     : DiscontinuousSpace(name, kGcRetentionPolicyAlwaysCollect),
       num_bytes_allocated_(0), num_objects_allocated_(0), total_bytes_allocated_(0),
       total_objects_allocated_(0), begin_(begin), end_(end) {
@@ -122,8 +122,8 @@
   mem_maps_.Put(obj, mem_map);
   const size_t allocation_size = mem_map->BaseSize();
   DCHECK(bytes_allocated != nullptr);
-  begin_ = std::min(begin_, reinterpret_cast<byte*>(obj));
-  byte* obj_end = reinterpret_cast<byte*>(obj) + allocation_size;
+  begin_ = std::min(begin_, reinterpret_cast<uint8_t*>(obj));
+  uint8_t* obj_end = reinterpret_cast<uint8_t*>(obj) + allocation_size;
   if (end_ == nullptr || obj_end > end_) {
     end_ = obj_end;
   }
@@ -159,7 +159,11 @@
   MutexLock mu(Thread::Current(), lock_);
   auto found = mem_maps_.find(obj);
   CHECK(found != mem_maps_.end()) << "Attempted to get size of a large object which is not live";
-  return found->second->BaseSize();
+  size_t alloc_size = found->second->BaseSize();
+  if (usable_size != nullptr) {
+    *usable_size = alloc_size;
+  }
+  return alloc_size;
 }
 
 size_t LargeObjectSpace::FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
@@ -283,7 +287,7 @@
   return reinterpret_cast<uintptr_t>(a) < reinterpret_cast<uintptr_t>(b);
 }
 
-FreeListSpace* FreeListSpace::Create(const std::string& name, byte* requested_begin, size_t size) {
+FreeListSpace* FreeListSpace::Create(const std::string& name, uint8_t* requested_begin, size_t size) {
   CHECK_EQ(size % kAlignment, 0U);
   std::string error_msg;
   MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, size,
@@ -292,7 +296,7 @@
   return new FreeListSpace(name, mem_map, mem_map->Begin(), mem_map->End());
 }
 
-FreeListSpace::FreeListSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end)
+FreeListSpace::FreeListSpace(const std::string& name, MemMap* mem_map, uint8_t* begin, uint8_t* end)
     : LargeObjectSpace(name, begin, end),
       mem_map_(mem_map),
       lock_("free list space lock", kAllocSpaceLock) {
@@ -319,8 +323,8 @@
   while (cur_info < end_info) {
     if (!cur_info->IsFree()) {
       size_t alloc_size = cur_info->ByteSize();
-      byte* byte_start = reinterpret_cast<byte*>(GetAddressForAllocationInfo(cur_info));
-      byte* byte_end = byte_start + alloc_size;
+      uint8_t* byte_start = reinterpret_cast<uint8_t*>(GetAddressForAllocationInfo(cur_info));
+      uint8_t* byte_end = byte_start + alloc_size;
       callback(byte_start, byte_end, alloc_size, arg);
       callback(nullptr, nullptr, 0, arg);
     }
diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h
index a63c5c0..850a006 100644
--- a/runtime/gc/space/large_object_space.h
+++ b/runtime/gc/space/large_object_space.h
@@ -77,11 +77,11 @@
     return false;
   }
   // Current address at which the space begins, which may vary as the space is filled.
-  byte* Begin() const {
+  uint8_t* Begin() const {
     return begin_;
   }
   // Current address at which the space ends, which may vary as the space is filled.
-  byte* End() const {
+  uint8_t* End() const {
     return end_;
   }
   // Current size of space
@@ -90,14 +90,14 @@
   }
   // Return true if we contain the specified address.
   bool Contains(const mirror::Object* obj) const {
-    const byte* byte_obj = reinterpret_cast<const byte*>(obj);
+    const uint8_t* byte_obj = reinterpret_cast<const uint8_t*>(obj);
     return Begin() <= byte_obj && byte_obj < End();
   }
   void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
-  explicit LargeObjectSpace(const std::string& name, byte* begin, byte* end);
+  explicit LargeObjectSpace(const std::string& name, uint8_t* begin, uint8_t* end);
   static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg);
 
   // Approximate number of bytes which have been allocated into the space.
@@ -106,8 +106,8 @@
   uint64_t total_bytes_allocated_;
   uint64_t total_objects_allocated_;
   // Begin and end, may change as more large objects are allocated.
-  byte* begin_;
-  byte* end_;
+  uint8_t* begin_;
+  uint8_t* end_;
 
   friend class Space;
 
@@ -149,7 +149,7 @@
   static constexpr size_t kAlignment = kPageSize;
 
   virtual ~FreeListSpace();
-  static FreeListSpace* Create(const std::string& name, byte* requested_begin, size_t capacity);
+  static FreeListSpace* Create(const std::string& name, uint8_t* requested_begin, size_t capacity);
   size_t AllocationSize(mirror::Object* obj, size_t* usable_size) OVERRIDE
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
   mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
@@ -159,7 +159,7 @@
   void Dump(std::ostream& os) const;
 
  protected:
-  FreeListSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end);
+  FreeListSpace(const std::string& name, MemMap* mem_map, uint8_t* begin, uint8_t* end);
   size_t GetSlotIndexForAddress(uintptr_t address) const {
     DCHECK(Contains(reinterpret_cast<mirror::Object*>(address)));
     return (address - reinterpret_cast<uintptr_t>(Begin())) / kAlignment;
diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc
index c5d8abc..e17bad8 100644
--- a/runtime/gc/space/large_object_space_test.cc
+++ b/runtime/gc/space/large_object_space_test.cc
@@ -55,7 +55,7 @@
         ASSERT_EQ(allocation_size, los->AllocationSize(obj, nullptr));
         ASSERT_GE(allocation_size, request_size);
         // Fill in our magic value.
-        byte magic = (request_size & 0xFF) | 1;
+        uint8_t magic = (request_size & 0xFF) | 1;
         memset(obj, magic, request_size);
         requests.push_back(std::make_pair(obj, request_size));
       }
@@ -73,9 +73,9 @@
         mirror::Object* obj = requests.back().first;
         size_t request_size = requests.back().second;
         requests.pop_back();
-        byte magic = (request_size & 0xFF) | 1;
+        uint8_t magic = (request_size & 0xFF) | 1;
         for (size_t k = 0; k < request_size; ++k) {
-          ASSERT_EQ(reinterpret_cast<const byte*>(obj)[k], magic);
+          ASSERT_EQ(reinterpret_cast<const uint8_t*>(obj)[k], magic);
         }
         ASSERT_GE(los->Free(Thread::Current(), obj), request_size);
       }
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index ba7e5c1..9bbbb3c 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -36,7 +36,7 @@
 size_t MallocSpace::bitmap_index_ = 0;
 
 MallocSpace::MallocSpace(const std::string& name, MemMap* mem_map,
-                         byte* begin, byte* end, byte* limit, size_t growth_limit,
+                         uint8_t* begin, uint8_t* end, uint8_t* limit, size_t growth_limit,
                          bool create_bitmaps, bool can_move_objects, size_t starting_size,
                          size_t initial_size)
     : ContinuousMemMapAllocSpace(name, mem_map, begin, end, limit, kGcRetentionPolicyAlwaysCollect),
@@ -66,7 +66,7 @@
 }
 
 MemMap* MallocSpace::CreateMemMap(const std::string& name, size_t starting_size, size_t* initial_size,
-                                  size_t* growth_limit, size_t* capacity, byte* requested_begin) {
+                                  size_t* growth_limit, size_t* capacity, uint8_t* requested_begin) {
   // Sanity check arguments
   if (starting_size > *initial_size) {
     *initial_size = starting_size;
@@ -129,10 +129,10 @@
 
 void* MallocSpace::MoreCore(intptr_t increment) {
   CheckMoreCoreForPrecondition();
-  byte* original_end = End();
+  uint8_t* original_end = End();
   if (increment != 0) {
     VLOG(heap) << "MallocSpace::MoreCore " << PrettySize(increment);
-    byte* new_end = original_end + increment;
+    uint8_t* new_end = original_end + increment;
     if (increment > 0) {
       // Should never be asked to increase the allocation beyond the capacity of the space. Enforced
       // by mspace_set_footprint_limit.
@@ -163,7 +163,7 @@
   // alloc space so that we won't mix thread local runs from different
   // alloc spaces.
   RevokeAllThreadLocalBuffers();
-  SetEnd(reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(End()), kPageSize)));
+  SetEnd(reinterpret_cast<uint8_t*>(RoundUp(reinterpret_cast<uintptr_t>(End()), kPageSize)));
   DCHECK(IsAligned<accounting::CardTable::kCardSize>(begin_));
   DCHECK(IsAligned<accounting::CardTable::kCardSize>(End()));
   DCHECK(IsAligned<kPageSize>(begin_));
@@ -173,7 +173,8 @@
   // stored in between objects.
   // Remaining size is for the new alloc space.
   const size_t growth_limit = growth_limit_ - size;
-  const size_t capacity = Capacity() - size;
+  // Use mem map limit in case error for clear growth limit.
+  const size_t capacity = NonGrowthLimitCapacity() - size;
   VLOG(heap) << "Begin " << reinterpret_cast<const void*>(begin_) << "\n"
              << "End " << reinterpret_cast<const void*>(End()) << "\n"
              << "Size " << size << "\n"
@@ -194,11 +195,11 @@
   void* allocator = CreateAllocator(End(), starting_size_, initial_size_, capacity,
                                     low_memory_mode);
   // Protect memory beyond the initial size.
-  byte* end = mem_map->Begin() + starting_size_;
+  uint8_t* end = mem_map->Begin() + starting_size_;
   if (capacity > initial_size_) {
     CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size_, PROT_NONE), alloc_space_name);
   }
-  *out_malloc_space = CreateInstance(alloc_space_name, mem_map.release(), allocator, End(), end,
+  *out_malloc_space = CreateInstance(mem_map.release(), alloc_space_name, allocator, End(), end,
                                      limit_, growth_limit, CanMoveObjects());
   SetLimit(End());
   live_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End()));
@@ -247,6 +248,16 @@
   context->freed.bytes += space->FreeList(self, num_ptrs, ptrs);
 }
 
+void MallocSpace::ClampGrowthLimit() {
+  size_t new_capacity = Capacity();
+  CHECK_LE(new_capacity, NonGrowthLimitCapacity());
+  GetLiveBitmap()->SetHeapSize(new_capacity);
+  GetMarkBitmap()->SetHeapSize(new_capacity);
+  GetMemMap()->SetSize(new_capacity);
+  limit_ = Begin() + new_capacity;
+  CHECK(temp_bitmap_.get() == nullptr);
+}
+
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index bace3f6..06239e5 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>
 
@@ -110,13 +110,17 @@
     return GetMemMap()->Size();
   }
 
+  // Change the non growth limit capacity by shrinking or expanding the map. Currently, only
+  // shrinking is supported.
+  void ClampGrowthLimit();
+
   void Dump(std::ostream& os) const;
 
   void SetGrowthLimit(size_t growth_limit);
 
-  virtual MallocSpace* CreateInstance(const std::string& name, MemMap* mem_map, void* allocator,
-                                      byte* begin, byte* end, byte* limit, size_t growth_limit,
-                                      bool can_move_objects) = 0;
+  virtual MallocSpace* CreateInstance(MemMap* mem_map, const std::string& name, void* allocator,
+                                      uint8_t* begin, uint8_t* end, uint8_t* limit,
+                                      size_t growth_limit, bool can_move_objects) = 0;
 
   // Splits ourself into a zygote space and new malloc space which has our unused memory. When true,
   // the low memory mode argument specifies that the heap wishes the created space to be more
@@ -138,12 +142,12 @@
   }
 
  protected:
-  MallocSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end,
-              byte* limit, size_t growth_limit, bool create_bitmaps, bool can_move_objects,
+  MallocSpace(const std::string& name, MemMap* mem_map, uint8_t* begin, uint8_t* end,
+              uint8_t* limit, size_t growth_limit, bool create_bitmaps, bool can_move_objects,
               size_t starting_size, size_t initial_size);
 
   static MemMap* CreateMemMap(const std::string& name, size_t starting_size, size_t* initial_size,
-                              size_t* growth_limit, size_t* capacity, byte* requested_begin);
+                              size_t* growth_limit, size_t* capacity, uint8_t* requested_begin);
 
   // When true the low memory mode argument specifies that the heap wishes the created allocator to
   // be more aggressive in releasing unused pages.
diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h
index fbfef45..5d6642d 100644
--- a/runtime/gc/space/rosalloc_space-inl.h
+++ b/runtime/gc/space/rosalloc_space-inl.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 
 #include "gc/allocator/rosalloc-inl.h"
+#include "gc/space/valgrind_settings.h"
 #include "rosalloc_space.h"
 #include "thread.h"
 
@@ -26,13 +27,19 @@
 namespace space {
 
 inline size_t RosAllocSpace::AllocationSizeNonvirtual(mirror::Object* obj, size_t* usable_size) {
-  void* obj_ptr = const_cast<void*>(reinterpret_cast<const void*>(obj));
   // obj is a valid object. Use its class in the header to get the size.
   // Don't use verification since the object may be dead if we are sweeping.
   size_t size = obj->SizeOf<kVerifyNone>();
+  bool running_on_valgrind = RUNNING_ON_VALGRIND != 0;
+  if (running_on_valgrind) {
+    size += 2 * kDefaultValgrindRedZoneBytes;
+  }
   size_t size_by_size = rosalloc_->UsableSize(size);
   if (kIsDebugBuild) {
-    size_t size_by_ptr = rosalloc_->UsableSize(obj_ptr);
+    // On valgrind, the red zone has an impact...
+    const uint8_t* obj_ptr = reinterpret_cast<const uint8_t*>(obj);
+    size_t size_by_ptr = rosalloc_->UsableSize(
+        obj_ptr - (running_on_valgrind ? kDefaultValgrindRedZoneBytes : 0));
     if (size_by_size != size_by_ptr) {
       LOG(INFO) << "Found a bad sized obj of size " << size
                 << " at " << std::hex << reinterpret_cast<intptr_t>(obj_ptr) << std::dec
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 3f39c77..ced25a4 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"
@@ -41,10 +44,10 @@
 // TODO: Fix
 // template class ValgrindMallocSpace<RosAllocSpace, allocator::RosAlloc*>;
 
-RosAllocSpace::RosAllocSpace(const std::string& name, MemMap* mem_map,
-                             art::gc::allocator::RosAlloc* rosalloc, byte* begin, byte* end,
-                             byte* limit, size_t growth_limit, bool can_move_objects,
-                             size_t starting_size, size_t initial_size, bool low_memory_mode)
+RosAllocSpace::RosAllocSpace(MemMap* mem_map, size_t initial_size, const std::string& name,
+                             art::gc::allocator::RosAlloc* rosalloc, uint8_t* begin, uint8_t* end,
+                             uint8_t* limit, size_t growth_limit, bool can_move_objects,
+                             size_t starting_size, bool low_memory_mode)
     : MallocSpace(name, mem_map, begin, end, limit, growth_limit, true, can_move_objects,
                   starting_size, initial_size),
       rosalloc_(rosalloc), low_memory_mode_(low_memory_mode) {
@@ -56,28 +59,33 @@
                                                size_t growth_limit, size_t capacity,
                                                bool low_memory_mode, bool can_move_objects) {
   DCHECK(mem_map != nullptr);
+
+  bool running_on_valgrind = Runtime::Current()->RunningOnValgrind();
+
   allocator::RosAlloc* rosalloc = CreateRosAlloc(mem_map->Begin(), starting_size, initial_size,
-                                                 capacity, low_memory_mode);
+                                                 capacity, low_memory_mode, running_on_valgrind);
   if (rosalloc == NULL) {
     LOG(ERROR) << "Failed to initialize rosalloc for alloc space (" << name << ")";
     return NULL;
   }
 
   // Protect memory beyond the starting size. MoreCore will add r/w permissions when necessory
-  byte* end = mem_map->Begin() + starting_size;
+  uint8_t* end = mem_map->Begin() + starting_size;
   if (capacity - starting_size > 0) {
     CHECK_MEMORY_CALL(mprotect, (end, capacity - starting_size, PROT_NONE), name);
   }
 
   // Everything is set so record in immutable structure and leave
-  byte* begin = mem_map->Begin();
+  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 (running_on_valgrind) {
+    return new ValgrindMallocSpace<RosAllocSpace, kDefaultValgrindRedZoneBytes, false, true>(
+        mem_map, initial_size, name, rosalloc, begin, end, begin + capacity, growth_limit,
+        can_move_objects, starting_size, low_memory_mode);
   } else {
-    return new RosAllocSpace(name, mem_map, rosalloc, begin, end, begin + capacity, growth_limit,
-                             can_move_objects, starting_size, initial_size, low_memory_mode);
+    return new RosAllocSpace(mem_map, initial_size, name, rosalloc, begin, end, begin + capacity,
+                             growth_limit, can_move_objects, starting_size, low_memory_mode);
   }
 }
 
@@ -86,7 +94,7 @@
 }
 
 RosAllocSpace* RosAllocSpace::Create(const std::string& name, size_t initial_size,
-                                     size_t growth_limit, size_t capacity, byte* requested_begin,
+                                     size_t growth_limit, size_t capacity, uint8_t* requested_begin,
                                      bool low_memory_mode, bool can_move_objects) {
   uint64_t start_time = 0;
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -124,7 +132,8 @@
 
 allocator::RosAlloc* RosAllocSpace::CreateRosAlloc(void* begin, size_t morecore_start,
                                                    size_t initial_size,
-                                                   size_t maximum_size, bool low_memory_mode) {
+                                                   size_t maximum_size, bool low_memory_mode,
+                                                   bool running_on_valgrind) {
   // clear errno to allow PLOG on error
   errno = 0;
   // create rosalloc using our backing storage starting at begin and
@@ -134,7 +143,8 @@
       begin, morecore_start, maximum_size,
       low_memory_mode ?
           art::gc::allocator::RosAlloc::kPageReleaseModeAll :
-          art::gc::allocator::RosAlloc::kPageReleaseModeSizeAndEnd);
+          art::gc::allocator::RosAlloc::kPageReleaseModeSizeAndEnd,
+      running_on_valgrind);
   if (rosalloc != NULL) {
     rosalloc->SetFootprintLimit(initial_size);
   } else {
@@ -163,12 +173,19 @@
   return result;
 }
 
-MallocSpace* RosAllocSpace::CreateInstance(const std::string& name, MemMap* mem_map, void* allocator,
-                                           byte* begin, byte* end, byte* limit, size_t growth_limit,
+MallocSpace* RosAllocSpace::CreateInstance(MemMap* mem_map, const std::string& name,
+                                           void* allocator, uint8_t* begin, uint8_t* end,
+                                           uint8_t* limit, size_t growth_limit,
                                            bool can_move_objects) {
-  return new RosAllocSpace(name, mem_map, reinterpret_cast<allocator::RosAlloc*>(allocator),
-                           begin, end, limit, growth_limit, can_move_objects, starting_size_,
-                           initial_size_, low_memory_mode_);
+  if (Runtime::Current()->RunningOnValgrind()) {
+    return new ValgrindMallocSpace<RosAllocSpace, kDefaultValgrindRedZoneBytes, false, true>(
+        mem_map, initial_size_, name, reinterpret_cast<allocator::RosAlloc*>(allocator), begin, end,
+        limit, growth_limit, can_move_objects, starting_size_, low_memory_mode_);
+  } else {
+    return new RosAllocSpace(mem_map, initial_size_, name,
+                             reinterpret_cast<allocator::RosAlloc*>(allocator), begin, end, limit,
+                             growth_limit, can_move_objects, starting_size_, low_memory_mode_);
+  }
 }
 
 size_t RosAllocSpace::Free(Thread* self, mirror::Object* ptr) {
@@ -224,15 +241,6 @@
   return bytes_freed;
 }
 
-// Callback from rosalloc when it needs to increase the footprint
-extern "C" void* art_heap_rosalloc_morecore(allocator::RosAlloc* rosalloc, intptr_t increment) {
-  Heap* heap = Runtime::Current()->GetHeap();
-  RosAllocSpace* rosalloc_space = heap->GetRosAllocSpace(rosalloc);
-  DCHECK(rosalloc_space != nullptr);
-  DCHECK_EQ(rosalloc_space->GetRosAlloc(), rosalloc);
-  return rosalloc_space->MoreCore(increment);
-}
-
 size_t RosAllocSpace::Trim() {
   VLOG(heap) << "RosAllocSpace::Trim() ";
   {
@@ -357,11 +365,26 @@
   mark_bitmap_->Clear();
   SetEnd(begin_ + starting_size_);
   delete rosalloc_;
-  rosalloc_ = CreateRosAlloc(mem_map_->Begin(), starting_size_, initial_size_, Capacity(),
-                             low_memory_mode_);
+  rosalloc_ = CreateRosAlloc(mem_map_->Begin(), starting_size_, initial_size_,
+                             NonGrowthLimitCapacity(), low_memory_mode_,
+                             Runtime::Current()->RunningOnValgrind());
   SetFootprintLimit(footprint_limit);
 }
 
 }  // namespace space
+
+namespace allocator {
+
+// Callback from rosalloc when it needs to increase the footprint.
+void* ArtRosAllocMoreCore(allocator::RosAlloc* rosalloc, intptr_t increment) {
+  Heap* heap = Runtime::Current()->GetHeap();
+  art::gc::space::RosAllocSpace* rosalloc_space = heap->GetRosAllocSpace(rosalloc);
+  DCHECK(rosalloc_space != nullptr);
+  DCHECK_EQ(rosalloc_space->GetRosAlloc(), rosalloc);
+  return rosalloc_space->MoreCore(increment);
+}
+
+}  // namespace allocator
+
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index f1ce115..c856e95 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -39,7 +39,7 @@
   // the caller should call Begin on the returned space to confirm the
   // request was granted.
   static RosAllocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
-                               size_t capacity, byte* requested_begin, bool low_memory_mode,
+                               size_t capacity, uint8_t* requested_begin, bool low_memory_mode,
                                bool can_move_objects);
   static RosAllocSpace* CreateFromMemMap(MemMap* mem_map, const std::string& name,
                                          size_t starting_size, size_t initial_size,
@@ -92,8 +92,8 @@
 
   void Clear() OVERRIDE;
 
-  MallocSpace* CreateInstance(const std::string& name, MemMap* mem_map, void* allocator,
-                              byte* begin, byte* end, byte* limit, size_t growth_limit,
+  MallocSpace* CreateInstance(MemMap* mem_map, const std::string& name, void* allocator,
+                              uint8_t* begin, uint8_t* end, uint8_t* limit, size_t growth_limit,
                               bool can_move_objects) OVERRIDE;
 
   uint64_t GetBytesAllocated() OVERRIDE;
@@ -126,9 +126,10 @@
   }
 
  protected:
-  RosAllocSpace(const std::string& name, MemMap* mem_map, allocator::RosAlloc* rosalloc,
-                byte* begin, byte* end, byte* limit, size_t growth_limit, bool can_move_objects,
-                size_t starting_size, size_t initial_size, bool low_memory_mode);
+  RosAllocSpace(MemMap* mem_map, size_t initial_size, const std::string& name,
+                allocator::RosAlloc* rosalloc, uint8_t* begin, uint8_t* end, uint8_t* limit,
+                size_t growth_limit, bool can_move_objects, size_t starting_size,
+                bool low_memory_mode);
 
  private:
   template<bool kThreadSafe = true>
@@ -137,10 +138,12 @@
 
   void* CreateAllocator(void* base, size_t morecore_start, size_t initial_size,
                         size_t maximum_size, bool low_memory_mode) OVERRIDE {
-    return CreateRosAlloc(base, morecore_start, initial_size, maximum_size, low_memory_mode);
+    return CreateRosAlloc(base, morecore_start, initial_size, maximum_size, low_memory_mode,
+                          RUNNING_ON_VALGRIND != 0);
   }
   static allocator::RosAlloc* CreateRosAlloc(void* base, size_t morecore_start, size_t initial_size,
-                                             size_t maximum_size, bool low_memory_mode);
+                                             size_t maximum_size, bool low_memory_mode,
+                                             bool running_on_valgrind);
 
   void InspectAllRosAlloc(void (*callback)(void *start, void *end, size_t num_bytes, void* callback_arg),
                           void* arg, bool do_null_callback_at_end)
diff --git a/runtime/gc/space/rosalloc_space_base_test.cc b/runtime/gc/space/rosalloc_space_base_test.cc
index c3157fa..0c5be03 100644
--- a/runtime/gc/space/rosalloc_space_base_test.cc
+++ b/runtime/gc/space/rosalloc_space_base_test.cc
@@ -21,7 +21,7 @@
 namespace space {
 
 MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, byte* requested_begin) {
+                                 size_t capacity, uint8_t* requested_begin) {
   return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin,
                                Runtime::Current()->GetHeap()->IsLowMemoryMode(), false);
 }
diff --git a/runtime/gc/space/rosalloc_space_random_test.cc b/runtime/gc/space/rosalloc_space_random_test.cc
index 864bbc9..ca3aff4 100644
--- a/runtime/gc/space/rosalloc_space_random_test.cc
+++ b/runtime/gc/space/rosalloc_space_random_test.cc
@@ -21,7 +21,7 @@
 namespace space {
 
 MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, byte* requested_begin) {
+                                 size_t capacity, uint8_t* requested_begin) {
   return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin,
                                Runtime::Current()->GetHeap()->IsLowMemoryMode(), false);
 }
diff --git a/runtime/gc/space/rosalloc_space_static_test.cc b/runtime/gc/space/rosalloc_space_static_test.cc
index c0e2ac8..a78623e 100644
--- a/runtime/gc/space/rosalloc_space_static_test.cc
+++ b/runtime/gc/space/rosalloc_space_static_test.cc
@@ -21,7 +21,7 @@
 namespace space {
 
 MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, byte* requested_begin) {
+                                 size_t capacity, uint8_t* requested_begin) {
   return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin,
                                Runtime::Current()->GetHeap()->IsLowMemoryMode(), false);
 }
diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc
index bff28f6..486d79a 100644
--- a/runtime/gc/space/space.cc
+++ b/runtime/gc/space/space.cc
@@ -39,33 +39,33 @@
 }
 
 DlMallocSpace* Space::AsDlMallocSpace() {
-  LOG(FATAL) << "Unreachable";
-  return nullptr;
+  UNIMPLEMENTED(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 RosAllocSpace* Space::AsRosAllocSpace() {
-  LOG(FATAL) << "Unreachable";
-  return nullptr;
+  UNIMPLEMENTED(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 ZygoteSpace* Space::AsZygoteSpace() {
-  LOG(FATAL) << "Unreachable";
-  return nullptr;
+  UNIMPLEMENTED(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 BumpPointerSpace* Space::AsBumpPointerSpace() {
-  LOG(FATAL) << "Unreachable";
-  return nullptr;
+  UNIMPLEMENTED(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 AllocSpace* Space::AsAllocSpace() {
-  LOG(FATAL) << "Unimplemented";
-  return nullptr;
+  UNIMPLEMENTED(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 ContinuousMemMapAllocSpace* Space::AsContinuousMemMapAllocSpace() {
-  LOG(FATAL) << "Unimplemented";
-  return nullptr;
+  UNIMPLEMENTED(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 DiscontinuousSpace::DiscontinuousSpace(const std::string& name,
@@ -133,8 +133,8 @@
   mark_bitmap_->SetName(temp_name);
 }
 
-AllocSpace::SweepCallbackContext::SweepCallbackContext(bool swap_bitmaps, space::Space* space)
-    : swap_bitmaps(swap_bitmaps), space(space), self(Thread::Current()) {
+AllocSpace::SweepCallbackContext::SweepCallbackContext(bool swap_bitmaps_in, space::Space* space_in)
+    : swap_bitmaps(swap_bitmaps_in), space(space_in), self(Thread::Current()) {
 }
 
 }  // namespace space
diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h
index 523d4fe..860a4c9 100644
--- a/runtime/gc/space/space.h
+++ b/runtime/gc/space/space.h
@@ -246,27 +246,27 @@
 class ContinuousSpace : public Space {
  public:
   // Address at which the space begins.
-  byte* Begin() const {
+  uint8_t* Begin() const {
     return begin_;
   }
 
   // Current address at which the space ends, which may vary as the space is filled.
-  byte* End() const {
+  uint8_t* End() const {
     return end_.LoadRelaxed();
   }
 
   // The end of the address range covered by the space.
-  byte* Limit() const {
+  uint8_t* Limit() const {
     return limit_;
   }
 
   // Change the end of the space. Be careful with use since changing the end of a space to an
   // invalid value may break the GC.
-  void SetEnd(byte* end) {
+  void SetEnd(uint8_t* end) {
     end_.StoreRelaxed(end);
   }
 
-  void SetLimit(byte* limit) {
+  void SetLimit(uint8_t* limit) {
     limit_ = limit;
   }
 
@@ -286,7 +286,7 @@
   // Is object within this space? We check to see if the pointer is beyond the end first as
   // continuous spaces are iterated over from low to high.
   bool HasAddress(const mirror::Object* obj) const {
-    const byte* byte_ptr = reinterpret_cast<const byte*>(obj);
+    const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(obj);
     return byte_ptr >= Begin() && byte_ptr < Limit();
   }
 
@@ -302,18 +302,18 @@
 
  protected:
   ContinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy,
-                  byte* begin, byte* end, byte* limit) :
+                  uint8_t* begin, uint8_t* end, uint8_t* limit) :
       Space(name, gc_retention_policy), begin_(begin), end_(end), limit_(limit) {
   }
 
   // The beginning of the storage for fast access.
-  byte* begin_;
+  uint8_t* begin_;
 
   // Current end of the space.
-  Atomic<byte*> end_;
+  Atomic<uint8_t*> end_;
 
   // Limit of the space.
-  byte* limit_;
+  uint8_t* limit_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ContinuousSpace);
@@ -369,7 +369,7 @@
   }
 
  protected:
-  MemMapSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end, byte* limit,
+  MemMapSpace(const std::string& name, MemMap* mem_map, uint8_t* begin, uint8_t* end, uint8_t* limit,
               GcRetentionPolicy gc_retention_policy)
       : ContinuousSpace(name, gc_retention_policy, begin, end, limit),
         mem_map_(mem_map) {
@@ -425,8 +425,8 @@
   std::unique_ptr<accounting::ContinuousSpaceBitmap> mark_bitmap_;
   std::unique_ptr<accounting::ContinuousSpaceBitmap> temp_bitmap_;
 
-  ContinuousMemMapAllocSpace(const std::string& name, MemMap* mem_map, byte* begin,
-                             byte* end, byte* limit, GcRetentionPolicy gc_retention_policy)
+  ContinuousMemMapAllocSpace(const std::string& name, MemMap* mem_map, uint8_t* begin,
+                             uint8_t* end, uint8_t* limit, GcRetentionPolicy gc_retention_policy)
       : MemMapSpace(name, mem_map, begin, end, limit, gc_retention_policy) {
   }
 
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 7211bb4..09d10dd 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -110,7 +110,7 @@
   }
 
   typedef MallocSpace* (*CreateSpaceFn)(const std::string& name, size_t initial_size, size_t growth_limit,
-                                        size_t capacity, byte* requested_begin);
+                                        size_t capacity, uint8_t* requested_begin);
   void InitTestBody(CreateSpaceFn create_space);
   void ZygoteSpaceTestBody(CreateSpaceFn create_space);
   void AllocAndFreeTestBody(CreateSpaceFn create_space);
@@ -127,6 +127,9 @@
 }
 
 void SpaceTest::InitTestBody(CreateSpaceFn create_space) {
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   {
     // Init < max == growth
     std::unique_ptr<Space> space(create_space("test", 16 * MB, 32 * MB, 32 * MB, nullptr));
diff --git a/runtime/gc/space/valgrind_malloc_space-inl.h b/runtime/gc/space/valgrind_malloc_space-inl.h
index 966c276..ae8e892 100644
--- a/runtime/gc/space/valgrind_malloc_space-inl.h
+++ b/runtime/gc/space/valgrind_malloc_space-inl.h
@@ -21,68 +21,189 @@
 
 #include <memcheck/memcheck.h>
 
+#include "valgrind_settings.h"
+
 namespace art {
 namespace gc {
 namespace space {
 
-// Number of bytes to use as a red zone (rdz). A red zone of this size will be placed before and
-// after each allocation. 8 bytes provides long/double alignment.
-static constexpr size_t kValgrindRedZoneBytes = 8;
+namespace valgrind_details {
 
-template <typename S, typename A>
-mirror::Object* ValgrindMallocSpace<S, A>::AllocWithGrowth(Thread* self, size_t num_bytes,
-                                                           size_t* bytes_allocated,
-                                                           size_t* usable_size) {
+template <size_t kValgrindRedZoneBytes, bool kUseObjSizeForUsable>
+inline mirror::Object* AdjustForValgrind(void* obj_with_rdz, size_t num_bytes,
+                                         size_t bytes_allocated, size_t usable_size,
+                                         size_t* bytes_allocated_out, size_t* usable_size_out) {
+  if (bytes_allocated_out != nullptr) {
+    *bytes_allocated_out = bytes_allocated;
+  }
+
+  // This cuts over-provision and is a trade-off between testing the over-provisioning code paths
+  // vs checking overflows in the regular paths.
+  if (usable_size_out != nullptr) {
+    if (kUseObjSizeForUsable) {
+      *usable_size_out = num_bytes;
+    } else {
+      *usable_size_out = usable_size - 2 * kValgrindRedZoneBytes;
+    }
+  }
+
+  // Left redzone.
+  VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
+
+  // Make requested memory readable.
+  // (If the allocator assumes memory is zeroed out, we might get UNDEFINED warnings, so make
+  //  everything DEFINED initially.)
+  mirror::Object* result = reinterpret_cast<mirror::Object*>(
+      reinterpret_cast<uint8_t*>(obj_with_rdz) + kValgrindRedZoneBytes);
+  VALGRIND_MAKE_MEM_DEFINED(result, num_bytes);
+
+  // Right redzone. Assumes that if bytes_allocated > usable_size, then the difference is
+  // management data at the upper end, and for simplicity we will not protect that.
+  // At the moment, this fits RosAlloc (no management data in a slot, usable_size == alloc_size)
+  // and DlMalloc (allocation_size = (usable_size == num_bytes) + 4, 4 is management)
+  VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<uint8_t*>(result) + num_bytes,
+                             usable_size - (num_bytes + kValgrindRedZoneBytes));
+
+  return result;
+}
+
+inline size_t GetObjSizeNoThreadSafety(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS {
+  return obj->SizeOf<kVerifyNone>();
+}
+
+}  // namespace valgrind_details
+
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+mirror::Object*
+ValgrindMallocSpace<S,
+                    kValgrindRedZoneBytes,
+                    kAdjustForRedzoneInAllocSize,
+                    kUseObjSizeForUsable>::AllocWithGrowth(
+    Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out) {
+  size_t bytes_allocated;
+  size_t usable_size;
   void* obj_with_rdz = S::AllocWithGrowth(self, num_bytes + 2 * kValgrindRedZoneBytes,
-                                          bytes_allocated, usable_size);
+                                          &bytes_allocated, &usable_size);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
-  mirror::Object* result = reinterpret_cast<mirror::Object*>(
-      reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
-  // Make redzones as no access.
-  VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
-  VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(result) + num_bytes, kValgrindRedZoneBytes);
-  return result;
+
+  return valgrind_details::AdjustForValgrind<kValgrindRedZoneBytes,
+                                             kUseObjSizeForUsable>(obj_with_rdz, num_bytes,
+                                                                   bytes_allocated, usable_size,
+                                                                   bytes_allocated_out,
+                                                                   usable_size_out);
 }
 
-template <typename S, typename A>
-mirror::Object* ValgrindMallocSpace<S, A>::Alloc(Thread* self, size_t num_bytes,
-                                                 size_t* bytes_allocated,
-                                                 size_t* usable_size) {
-  void* obj_with_rdz = S::Alloc(self, num_bytes + 2 * kValgrindRedZoneBytes, bytes_allocated,
-                                usable_size);
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+mirror::Object* ValgrindMallocSpace<S,
+                                    kValgrindRedZoneBytes,
+                                    kAdjustForRedzoneInAllocSize,
+                                    kUseObjSizeForUsable>::Alloc(
+    Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out) {
+  size_t bytes_allocated;
+  size_t usable_size;
+  void* obj_with_rdz = S::Alloc(self, num_bytes + 2 * kValgrindRedZoneBytes,
+                                &bytes_allocated, &usable_size);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
-  mirror::Object* result = reinterpret_cast<mirror::Object*>(
-      reinterpret_cast<byte*>(obj_with_rdz) + kValgrindRedZoneBytes);
-  // Make redzones as no access.
-  VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
-  VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<byte*>(result) + num_bytes, kValgrindRedZoneBytes);
-  return result;
+
+  return valgrind_details::AdjustForValgrind<kValgrindRedZoneBytes,
+                                             kUseObjSizeForUsable>(obj_with_rdz, num_bytes,
+                                                                   bytes_allocated, usable_size,
+                                                                   bytes_allocated_out,
+                                                                   usable_size_out);
 }
 
-template <typename S, typename A>
-size_t ValgrindMallocSpace<S, A>::AllocationSize(mirror::Object* obj, size_t* usable_size) {
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+mirror::Object* ValgrindMallocSpace<S,
+                                    kValgrindRedZoneBytes,
+                                    kAdjustForRedzoneInAllocSize,
+                                    kUseObjSizeForUsable>::AllocThreadUnsafe(
+    Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out) {
+  size_t bytes_allocated;
+  size_t usable_size;
+  void* obj_with_rdz = S::AllocThreadUnsafe(self, num_bytes + 2 * kValgrindRedZoneBytes,
+                                &bytes_allocated, &usable_size);
+  if (obj_with_rdz == nullptr) {
+    return nullptr;
+  }
+
+  return valgrind_details::AdjustForValgrind<kValgrindRedZoneBytes,
+                                             kUseObjSizeForUsable>(obj_with_rdz, num_bytes,
+                                                                   bytes_allocated, usable_size,
+                                                                   bytes_allocated_out,
+                                                                   usable_size_out);
+}
+
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+size_t ValgrindMallocSpace<S,
+                           kValgrindRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::AllocationSize(
+    mirror::Object* obj, size_t* usable_size) {
   size_t result = S::AllocationSize(reinterpret_cast<mirror::Object*>(
-      reinterpret_cast<byte*>(obj) - kValgrindRedZoneBytes), usable_size);
+      reinterpret_cast<uint8_t*>(obj) - (kAdjustForRedzoneInAllocSize ? kValgrindRedZoneBytes : 0)),
+      usable_size);
+  if (usable_size != nullptr) {
+    if (kUseObjSizeForUsable) {
+      *usable_size = valgrind_details::GetObjSizeNoThreadSafety(obj);
+    } else {
+      *usable_size = *usable_size - 2 * kValgrindRedZoneBytes;
+    }
+  }
   return result;
 }
 
-template <typename S, typename A>
-size_t ValgrindMallocSpace<S, A>::Free(Thread* self, mirror::Object* ptr) {
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+size_t ValgrindMallocSpace<S,
+                           kValgrindRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::Free(
+    Thread* self, mirror::Object* ptr) {
   void* obj_after_rdz = reinterpret_cast<void*>(ptr);
-  void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
+  uint8_t* obj_with_rdz = reinterpret_cast<uint8_t*>(obj_after_rdz) - kValgrindRedZoneBytes;
   // Make redzones undefined.
-  size_t usable_size = 0;
-  AllocationSize(ptr, &usable_size);
-  VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, usable_size);
+  size_t usable_size;
+  size_t allocation_size = AllocationSize(ptr, &usable_size);
+
+  // Unprotect the allocation.
+  // Use the obj-size-for-usable flag to determine whether usable_size is the more important one,
+  // e.g., whether there's data in the allocation_size (and usable_size can't be trusted).
+  if (kUseObjSizeForUsable) {
+    VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, allocation_size);
+  } else {
+    VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, usable_size + 2 * kValgrindRedZoneBytes);
+  }
+
   return S::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
 }
 
-template <typename S, typename A>
-size_t ValgrindMallocSpace<S, A>::FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+size_t ValgrindMallocSpace<S,
+                           kValgrindRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::FreeList(
+    Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
   size_t freed = 0;
   for (size_t i = 0; i < num_ptrs; i++) {
     freed += Free(self, ptrs[i]);
@@ -91,15 +212,18 @@
   return freed;
 }
 
-template <typename S, typename A>
-ValgrindMallocSpace<S, A>::ValgrindMallocSpace(const std::string& name, MemMap* mem_map,
-                                               A allocator, byte* begin,
-                                               byte* end, byte* limit, size_t growth_limit,
-                                               size_t initial_size,
-                                               bool can_move_objects, size_t starting_size) :
-    S(name, mem_map, allocator, begin, end, limit, growth_limit, can_move_objects, starting_size,
-      initial_size) {
-  VALGRIND_MAKE_MEM_UNDEFINED(mem_map->Begin() + initial_size, mem_map->Size() - initial_size);
+template <typename S,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
+template <typename... Params>
+ValgrindMallocSpace<S,
+                    kValgrindRedZoneBytes,
+                    kAdjustForRedzoneInAllocSize,
+                    kUseObjSizeForUsable>::ValgrindMallocSpace(
+    MemMap* mem_map, size_t initial_size, Params... params) : S(mem_map, initial_size, params...) {
+  VALGRIND_MAKE_MEM_UNDEFINED(mem_map->Begin() + initial_size,
+                              mem_map->Size() - initial_size);
 }
 
 }  // namespace space
diff --git a/runtime/gc/space/valgrind_malloc_space.h b/runtime/gc/space/valgrind_malloc_space.h
index 200ad83..707ea69 100644
--- a/runtime/gc/space/valgrind_malloc_space.h
+++ b/runtime/gc/space/valgrind_malloc_space.h
@@ -27,13 +27,19 @@
 
 // A specialization of DlMallocSpace/RosAllocSpace that places valgrind red zones around
 // allocations.
-template <typename BaseMallocSpaceType, typename AllocatorType>
+template <typename BaseMallocSpaceType,
+          size_t kValgrindRedZoneBytes,
+          bool kAdjustForRedzoneInAllocSize,
+          bool kUseObjSizeForUsable>
 class ValgrindMallocSpace FINAL : public BaseMallocSpaceType {
  public:
   mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated,
                                   size_t* usable_size) OVERRIDE;
   mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
                         size_t* usable_size) OVERRIDE;
+  mirror::Object* AllocThreadUnsafe(Thread* self, size_t num_bytes, size_t* bytes_allocated,
+                                    size_t* usable_size) OVERRIDE
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   size_t AllocationSize(mirror::Object* obj, size_t* usable_size) OVERRIDE;
 
@@ -44,11 +50,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void RegisterRecentFree(mirror::Object* ptr) OVERRIDE {
+    UNUSED(ptr);
   }
 
-  ValgrindMallocSpace(const std::string& name, MemMap* mem_map, AllocatorType allocator,
-                      byte* begin, byte* end, byte* limit, size_t growth_limit,
-                      size_t initial_size, bool can_move_objects, size_t starting_size);
+  template <typename... Params>
+  explicit ValgrindMallocSpace(MemMap* mem_map, size_t initial_size, Params... params);
   virtual ~ValgrindMallocSpace() {}
 
  private:
diff --git a/runtime/gc/space/valgrind_settings.h b/runtime/gc/space/valgrind_settings.h
new file mode 100644
index 0000000..73da0fd
--- /dev/null
+++ b/runtime/gc/space/valgrind_settings.h
@@ -0,0 +1,32 @@
+/*
+ * 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_RUNTIME_GC_SPACE_VALGRIND_SETTINGS_H_
+#define ART_RUNTIME_GC_SPACE_VALGRIND_SETTINGS_H_
+
+namespace art {
+namespace gc {
+namespace space {
+
+// Default number of bytes to use as a red zone (rdz). A red zone of this size will be placed before
+// and after each allocation. 8 bytes provides long/double alignment.
+static constexpr size_t kDefaultValgrindRedZoneBytes = 8;
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_RUNTIME_GC_SPACE_VALGRIND_SETTINGS_H_
diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc
index 51d84f5..a868e68 100644
--- a/runtime/gc/space/zygote_space.cc
+++ b/runtime/gc/space/zygote_space.cc
@@ -32,6 +32,7 @@
       : objects_allocated_(objects_allocated) {}
 
   void operator()(mirror::Object* obj) const {
+    UNUSED(obj);
     ++*objects_allocated_;
   }
 
@@ -58,7 +59,8 @@
 }
 
 void ZygoteSpace::Clear() {
-  LOG(FATAL) << "Unimplemented";
+  UNIMPLEMENTED(FATAL);
+  UNREACHABLE();
 }
 
 ZygoteSpace::ZygoteSpace(const std::string& name, MemMap* mem_map, size_t objects_allocated)
@@ -75,30 +77,29 @@
       << ",name=\"" << GetName() << "\"]";
 }
 
-mirror::Object* ZygoteSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
-                                   size_t* usable_size) {
+mirror::Object* ZygoteSpace::Alloc(Thread*, size_t, size_t*, size_t*) {
   UNIMPLEMENTED(FATAL);
-  return nullptr;
+  UNREACHABLE();
 }
 
-size_t ZygoteSpace::AllocationSize(mirror::Object* obj, size_t* usable_size) {
+size_t ZygoteSpace::AllocationSize(mirror::Object*, size_t*) {
   UNIMPLEMENTED(FATAL);
-  return 0;
+  UNREACHABLE();
 }
 
-size_t ZygoteSpace::Free(Thread* self, mirror::Object* ptr) {
+size_t ZygoteSpace::Free(Thread*, mirror::Object*) {
   UNIMPLEMENTED(FATAL);
-  return 0;
+  UNREACHABLE();
 }
 
-size_t ZygoteSpace::FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
+size_t ZygoteSpace::FreeList(Thread*, size_t, mirror::Object**) {
   UNIMPLEMENTED(FATAL);
-  return 0;
+  UNREACHABLE();
 }
 
-void ZygoteSpace::LogFragmentationAllocFailure(std::ostream& /*os*/,
-                                               size_t /*failed_alloc_bytes*/) {
+void ZygoteSpace::LogFragmentationAllocFailure(std::ostream&, size_t) {
   UNIMPLEMENTED(FATAL);
+  UNREACHABLE();
 }
 
 void ZygoteSpace::SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) {
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc
new file mode 100644
index 0000000..1a3c6f5
--- /dev/null
+++ b/runtime/gc/task_processor.cc
@@ -0,0 +1,125 @@
+/*
+ * 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 "task_processor.h"
+
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace gc {
+
+TaskProcessor::TaskProcessor()
+    : lock_(new Mutex("Task processor lock", kReferenceProcessorLock)), is_running_(false) {
+  // Piggyback off the reference processor lock level.
+  cond_.reset(new ConditionVariable("Task processor condition", *lock_));
+}
+
+TaskProcessor::~TaskProcessor() {
+  delete lock_;
+}
+
+void TaskProcessor::AddTask(Thread* self, HeapTask* task) {
+  ScopedThreadStateChange tsc(self, kBlocked);
+  MutexLock mu(self, *lock_);
+  tasks_.insert(task);
+  cond_->Signal(self);
+}
+
+HeapTask* TaskProcessor::GetTask(Thread* self) {
+  ScopedThreadStateChange tsc(self, kBlocked);
+  MutexLock mu(self, *lock_);
+  while (true) {
+    if (tasks_.empty()) {
+      if (!is_running_) {
+        return nullptr;
+      }
+      cond_->Wait(self);  // Empty queue, wait until we are signalled.
+    } else {
+      // Non empty queue, look at the top element and see if we are ready to run it.
+      const uint64_t current_time = NanoTime();
+      HeapTask* task = *tasks_.begin();
+      // If we are shutting down, return the task right away without waiting. Otherwise return the
+      // task if it is late enough.
+      uint64_t target_time = task->GetTargetRunTime();
+      if (!is_running_ || target_time <= current_time) {
+        tasks_.erase(tasks_.begin());
+        return task;
+      }
+      DCHECK_GT(target_time, current_time);
+      // Wait untl we hit the target run time.
+      const uint64_t delta_time = target_time - current_time;
+      const uint64_t ms_delta = NsToMs(delta_time);
+      const uint64_t ns_delta = delta_time - MsToNs(ms_delta);
+      cond_->TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta));
+    }
+  }
+  UNREACHABLE();
+  return nullptr;
+}
+
+void TaskProcessor::UpdateTargetRunTime(Thread* self, HeapTask* task, uint64_t new_target_time) {
+  MutexLock mu(self, *lock_);
+  // Find the task.
+  auto range = tasks_.equal_range(task);
+  for (auto it = range.first; it != range.second; ++it) {
+    if (*it == task) {
+      // Check if the target time was updated, if so re-insert then wait.
+      if (new_target_time != task->GetTargetRunTime()) {
+        tasks_.erase(it);
+        task->SetTargetRunTime(new_target_time);
+        tasks_.insert(task);
+        // If we became the first task then we may need to signal since we changed the task that we
+        // are sleeping on.
+        if (*tasks_.begin() == task) {
+          cond_->Signal(self);
+        }
+        return;
+      }
+    }
+  }
+}
+
+bool TaskProcessor::IsRunning() const {
+  MutexLock mu(Thread::Current(), *lock_);
+  return is_running_;
+}
+
+void TaskProcessor::Stop(Thread* self) {
+  MutexLock mu(self, *lock_);
+  is_running_ = false;
+  cond_->Broadcast(self);
+}
+
+void TaskProcessor::Start(Thread* self) {
+  MutexLock mu(self, *lock_);
+  is_running_ = true;
+}
+
+void TaskProcessor::RunAllTasks(Thread* self) {
+  while (true) {
+    // Wait and get a task, may be interrupted.
+    HeapTask* task = GetTask(self);
+    if (task != nullptr) {
+      task->Run(self);
+      task->Finalize();
+    } else if (!IsRunning()) {
+      break;
+    }
+  }
+}
+
+}  // namespace gc
+}  // namespace art
diff --git a/runtime/gc/task_processor.h b/runtime/gc/task_processor.h
new file mode 100644
index 0000000..765f035
--- /dev/null
+++ b/runtime/gc/task_processor.h
@@ -0,0 +1,84 @@
+/*
+ * 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_RUNTIME_GC_TASK_PROCESSOR_H_
+#define ART_RUNTIME_GC_TASK_PROCESSOR_H_
+
+#include <memory>
+#include <set>
+
+#include "base/mutex.h"
+#include "globals.h"
+#include "thread_pool.h"
+
+namespace art {
+namespace gc {
+
+class HeapTask : public SelfDeletingTask {
+ public:
+  explicit HeapTask(uint64_t target_run_time) : target_run_time_(target_run_time) {
+  }
+  uint64_t GetTargetRunTime() const {
+    return target_run_time_;
+  }
+
+ private:
+  // Update the updated_target_run_time_, the task processor will re-insert the task when it is
+  // popped and update the target_run_time_.
+  void SetTargetRunTime(uint64_t new_target_run_time) {
+    target_run_time_ = new_target_run_time;
+  }
+
+  // Time in ns at which we want the task to run.
+  uint64_t target_run_time_;
+
+  friend class TaskProcessor;
+};
+
+// Used to process GC tasks (heap trim, heap transitions, concurrent GC).
+class TaskProcessor {
+ public:
+  TaskProcessor();
+  virtual ~TaskProcessor();
+  void AddTask(Thread* self, HeapTask* task) LOCKS_EXCLUDED(lock_);
+  HeapTask* GetTask(Thread* self) LOCKS_EXCLUDED(lock_);
+  void Start(Thread* self) LOCKS_EXCLUDED(lock_);
+  // Stop tells the RunAllTasks to finish up the remaining tasks as soon as
+  // possible then return.
+  void Stop(Thread* self) LOCKS_EXCLUDED(lock_);
+  void RunAllTasks(Thread* self) LOCKS_EXCLUDED(lock_);
+  bool IsRunning() const LOCKS_EXCLUDED(lock_);
+  void UpdateTargetRunTime(Thread* self, HeapTask* target_time, uint64_t new_target_time)
+      LOCKS_EXCLUDED(lock_);
+
+ private:
+  class CompareByTargetRunTime {
+   public:
+    bool operator()(const HeapTask* a, const HeapTask* b) const {
+      return a->GetTargetRunTime() < b->GetTargetRunTime();
+    }
+  };
+
+  mutable Mutex* lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  bool is_running_ GUARDED_BY(lock_);
+  std::unique_ptr<ConditionVariable> cond_ GUARDED_BY(lock_);
+  std::multiset<HeapTask*, CompareByTargetRunTime> tasks_ GUARDED_BY(lock_);
+};
+
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_RUNTIME_GC_TASK_PROCESSOR_H_
diff --git a/runtime/gc/task_processor_test.cc b/runtime/gc/task_processor_test.cc
new file mode 100644
index 0000000..5dd6d8f
--- /dev/null
+++ b/runtime/gc/task_processor_test.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 "common_runtime_test.h"
+#include "task_processor.h"
+#include "thread_pool.h"
+#include "thread-inl.h"
+#include "utils.h"
+
+namespace art {
+namespace gc {
+
+class TaskProcessorTest : public CommonRuntimeTest {
+ public:
+};
+
+class RecursiveTask : public HeapTask {
+ public:
+  RecursiveTask(TaskProcessor* task_processor, Atomic<size_t>* counter, size_t max_recursion)
+     : HeapTask(NanoTime() + MsToNs(10)), task_processor_(task_processor), counter_(counter),
+       max_recursion_(max_recursion) {
+  }
+  virtual void Run(Thread* self) OVERRIDE {
+    if (max_recursion_ > 0) {
+      task_processor_->AddTask(self,
+                               new RecursiveTask(task_processor_, counter_, max_recursion_ - 1));
+      counter_->FetchAndAddSequentiallyConsistent(1U);
+    }
+  }
+
+ private:
+  TaskProcessor* const task_processor_;
+  Atomic<size_t>* const counter_;
+  const size_t max_recursion_;
+};
+
+class WorkUntilDoneTask : public SelfDeletingTask {
+ public:
+  WorkUntilDoneTask(TaskProcessor* task_processor, Atomic<bool>* done_running)
+      : task_processor_(task_processor), done_running_(done_running) {
+  }
+  virtual void Run(Thread* self) OVERRIDE {
+    task_processor_->RunAllTasks(self);
+    done_running_->StoreSequentiallyConsistent(true);
+  }
+
+ private:
+  TaskProcessor* const task_processor_;
+  Atomic<bool>* done_running_;
+};
+
+TEST_F(TaskProcessorTest, Interrupt) {
+  ThreadPool thread_pool("task processor test", 1U);
+  Thread* const self = Thread::Current();
+  TaskProcessor task_processor;
+  static constexpr size_t kRecursion = 10;
+  Atomic<bool> done_running(false);
+  Atomic<size_t> counter(0);
+  task_processor.AddTask(self, new RecursiveTask(&task_processor, &counter, kRecursion));
+  task_processor.Start(self);
+  // Add a task which will wait until interrupted to the thread pool.
+  thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running));
+  thread_pool.StartWorkers(self);
+  ASSERT_FALSE(done_running);
+  // Wait until all the tasks are done, but since we didn't interrupt, done_running should be 0.
+  while (counter.LoadSequentiallyConsistent() != kRecursion) {
+    usleep(10);
+  }
+  ASSERT_FALSE(done_running);
+  task_processor.Stop(self);
+  thread_pool.Wait(self, true, false);
+  // After the interrupt and wait, the WorkUntilInterruptedTasktask should have terminated and
+  // set done_running_ to true.
+  ASSERT_TRUE(done_running.LoadSequentiallyConsistent());
+
+  // Test that we finish remaining tasks before returning from RunTasksUntilInterrupted.
+  counter.StoreSequentiallyConsistent(0);
+  done_running.StoreSequentiallyConsistent(false);
+  // Self interrupt before any of the other tasks run, but since we added them we should keep on
+  // working until all the tasks are completed.
+  task_processor.Stop(self);
+  task_processor.AddTask(self, new RecursiveTask(&task_processor, &counter, kRecursion));
+  thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running));
+  thread_pool.StartWorkers(self);
+  thread_pool.Wait(self, true, false);
+  ASSERT_TRUE(done_running.LoadSequentiallyConsistent());
+  ASSERT_EQ(counter.LoadSequentiallyConsistent(), kRecursion);
+}
+
+class TestOrderTask : public HeapTask {
+ public:
+  explicit TestOrderTask(uint64_t expected_time, size_t expected_counter, size_t* counter)
+     : HeapTask(expected_time), expected_counter_(expected_counter), counter_(counter) {
+  }
+  virtual void Run(Thread* thread) OVERRIDE {
+    UNUSED(thread);  // Fix cppling bug.
+    ASSERT_EQ(*counter_, expected_counter_);
+    ++*counter_;
+  }
+
+ private:
+  const size_t expected_counter_;
+  size_t* const counter_;
+};
+
+TEST_F(TaskProcessorTest, Ordering) {
+  static const size_t kNumTasks = 25;
+  const uint64_t current_time = NanoTime();
+  Thread* const self = Thread::Current();
+  TaskProcessor task_processor;
+  task_processor.Stop(self);
+  size_t counter = 0;
+  std::vector<std::pair<uint64_t, size_t>> orderings;
+  for (size_t i = 0; i < kNumTasks; ++i) {
+    orderings.push_back(std::make_pair(current_time + MsToNs(10U * i), i));
+  }
+  for (size_t i = 0; i < kNumTasks; ++i) {
+    std::swap(orderings[i], orderings[(i * 87654231 + 12345) % orderings.size()]);
+  }
+  for (const auto& pair : orderings) {
+    auto* task = new TestOrderTask(pair.first, pair.second, &counter);
+    task_processor.AddTask(self, task);
+  }
+  ThreadPool thread_pool("task processor test", 1U);
+  Atomic<bool> done_running(false);
+  // Add a task which will wait until interrupted to the thread pool.
+  thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running));
+  ASSERT_FALSE(done_running.LoadSequentiallyConsistent());
+  thread_pool.StartWorkers(self);
+  thread_pool.Wait(self, true, false);
+  ASSERT_TRUE(done_running.LoadSequentiallyConsistent());
+  ASSERT_EQ(counter, kNumTasks);
+}
+
+}  // namespace gc
+}  // namespace art
diff --git a/runtime/gc_root-inl.h b/runtime/gc_root-inl.h
index 482f7bc..a42ec08 100644
--- a/runtime/gc_root-inl.h
+++ b/runtime/gc_root-inl.h
@@ -25,7 +25,7 @@
 
 template<class MirrorType>
 template<ReadBarrierOption kReadBarrierOption>
-inline MirrorType* GcRoot<MirrorType>::Read() {
+inline MirrorType* GcRoot<MirrorType>::Read() const {
   return ReadBarrier::BarrierForRoot<MirrorType, kReadBarrierOption>(&root_);
 }
 
diff --git a/runtime/gc_root.h b/runtime/gc_root.h
index b10a55c..7e0be64 100644
--- a/runtime/gc_root.h
+++ b/runtime/gc_root.h
@@ -19,18 +19,73 @@
 
 #include "base/macros.h"
 #include "base/mutex.h"       // For Locks::mutator_lock_.
-#include "object_callbacks.h"
 
 namespace art {
 
+namespace mirror {
+class Object;
+}  // namespace mirror
+
+enum RootType {
+  kRootUnknown = 0,
+  kRootJNIGlobal,
+  kRootJNILocal,
+  kRootJavaFrame,
+  kRootNativeStack,
+  kRootStickyClass,
+  kRootThreadBlock,
+  kRootMonitorUsed,
+  kRootThreadObject,
+  kRootInternedString,
+  kRootDebugger,
+  kRootVMInternal,
+  kRootJNIMonitor,
+};
+std::ostream& operator<<(std::ostream& os, const RootType& root_type);
+
+class RootInfo {
+ public:
+  // Thread id 0 is for non thread roots.
+  explicit RootInfo(RootType type, uint32_t thread_id = 0)
+     : type_(type), thread_id_(thread_id) {
+  }
+  virtual ~RootInfo() {
+  }
+  RootType GetType() const {
+    return type_;
+  }
+  uint32_t GetThreadId() const {
+    return thread_id_;
+  }
+  virtual void Describe(std::ostream& os) const {
+    os << "Type=" << type_ << " thread_id=" << thread_id_;
+  }
+
+ private:
+  const RootType type_;
+  const uint32_t thread_id_;
+};
+
+// Returns the new address of the object, returns root if it has not moved. tid and root_type are
+// only used by hprof.
+typedef void (RootCallback)(mirror::Object** root, void* arg, const RootInfo& root_info);
+
 template<class MirrorType>
 class PACKED(4) GcRoot {
  public:
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  ALWAYS_INLINE MirrorType* Read() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE MirrorType* Read() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void VisitRoot(RootCallback* callback, void* arg, uint32_t thread_id, RootType root_type) {
-    callback(reinterpret_cast<mirror::Object**>(&root_), arg, thread_id, root_type);
+  void VisitRoot(RootCallback* callback, void* arg, const RootInfo& info) const {
+    DCHECK(!IsNull());
+    callback(reinterpret_cast<mirror::Object**>(&root_), arg, info);
+    DCHECK(!IsNull());
+  }
+
+  void VisitRootIfNonNull(RootCallback* callback, void* arg, const RootInfo& info) const {
+    if (!IsNull()) {
+      VisitRoot(callback, arg, info);
+    }
   }
 
   // This is only used by IrtIterator.
@@ -51,7 +106,7 @@
   }
 
  private:
-  MirrorType* root_;
+  mutable MirrorType* root_;
 };
 
 }  // namespace art
diff --git a/runtime/globals.h b/runtime/globals.h
index 107e064..93026da 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -24,22 +24,14 @@
 
 namespace art {
 
-typedef uint8_t byte;
-typedef intptr_t word;
-typedef uintptr_t uword;
-
 static constexpr size_t KB = 1024;
 static constexpr size_t MB = KB * KB;
 static constexpr size_t GB = KB * KB * KB;
 
 // Runtime sizes.
-static constexpr size_t kWordSize = sizeof(word);
-static constexpr size_t kPointerSize = sizeof(void*);
-
 static constexpr size_t kBitsPerByte = 8;
 static constexpr size_t kBitsPerByteLog2 = 3;
-static constexpr int kBitsPerWord = kWordSize * kBitsPerByte;
-static constexpr size_t kWordHighBitMask = static_cast<size_t>(1) << (kBitsPerWord - 1);
+static constexpr int kBitsPerIntPtrT = sizeof(intptr_t) * kBitsPerByte;
 
 // Required stack alignment
 static constexpr size_t kStackAlignment = 16;
@@ -66,14 +58,14 @@
 static constexpr bool kIsTargetBuild = false;
 #endif
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-static constexpr bool kUsePortableCompiler = true;
+#if defined(ART_USE_OPTIMIZING_COMPILER)
+static constexpr bool kUseOptimizingCompiler = true;
 #else
-static constexpr bool kUsePortableCompiler = false;
+static constexpr bool kUseOptimizingCompiler = false;
 #endif
 
 // Garbage collector constants.
-static constexpr bool kMovingCollector = true && !kUsePortableCompiler;
+static constexpr bool kMovingCollector = true;
 static constexpr bool kMarkCompactSupport = false && kMovingCollector;
 // True if we allow moving field arrays, this can cause complication with mark compact.
 static constexpr bool kMoveFieldArrays = !kMarkCompactSupport;
@@ -103,7 +95,11 @@
 static constexpr bool kUseBakerOrBrooksReadBarrier = kUseBakerReadBarrier || kUseBrooksReadBarrier;
 
 // If true, references within the heap are poisoned (negated).
+#ifdef ART_HEAP_POISONING
+static constexpr bool kPoisonHeapReferences = true;
+#else
 static constexpr bool kPoisonHeapReferences = false;
+#endif
 
 // Kinds of tracing clocks.
 enum TraceClockSource {
@@ -112,7 +108,7 @@
   kTraceClockSourceDual,  // Both wall and thread CPU clocks.
 };
 
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
 static constexpr TraceClockSource kDefaultTraceClockSource = kTraceClockSourceDual;
 #else
 static constexpr TraceClockSource kDefaultTraceClockSource = kTraceClockSourceWall;
@@ -120,6 +116,8 @@
 
 static constexpr bool kDefaultMustRelocate = true;
 
+static constexpr bool kArm32QuickCodeUseSoftFloat = false;
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_GLOBALS_H_
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-inl.h b/runtime/handle_scope-inl.h
index 7bc811d..222083b 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -21,16 +21,19 @@
 
 #include "handle.h"
 #include "thread.h"
+#include "verify_object-inl.h"
 
 namespace art {
 
 template<size_t kNumReferences>
-inline StackHandleScope<kNumReferences>::StackHandleScope(Thread* self)
-    : HandleScope(kNumReferences), self_(self), pos_(0) {
+inline StackHandleScope<kNumReferences>::StackHandleScope(Thread* self, mirror::Object* fill_value)
+    : HandleScope(self->GetTopHandleScope(), kNumReferences), self_(self), pos_(0) {
+  DCHECK_EQ(self, Thread::Current());
+  static_assert(kNumReferences >= 1, "StackHandleScope must contain at least 1 reference");
   // TODO: Figure out how to use a compile assert.
-  DCHECK_EQ(&references_[0], &references_storage_[0]);
+  CHECK_EQ(&storage_[0], GetReferences());
   for (size_t i = 0; i < kNumReferences; ++i) {
-    SetReference(i, nullptr);
+    SetReference(i, fill_value);
   }
   self_->PushHandleScope(this);
 }
@@ -41,6 +44,71 @@
   DCHECK_EQ(top_handle_scope, this);
 }
 
+inline size_t HandleScope::SizeOf(uint32_t num_references) {
+  size_t header_size = sizeof(HandleScope);
+  size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
+  return header_size + data_size;
+}
+
+inline size_t HandleScope::SizeOf(size_t pointer_size, uint32_t num_references) {
+  // Assume that the layout is packed.
+  size_t header_size = pointer_size + sizeof(number_of_references_);
+  size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
+  return header_size + data_size;
+}
+
+inline mirror::Object* HandleScope::GetReference(size_t i) const {
+  DCHECK_LT(i, number_of_references_);
+  return GetReferences()[i].AsMirrorPtr();
+}
+
+inline Handle<mirror::Object> HandleScope::GetHandle(size_t i) {
+  DCHECK_LT(i, number_of_references_);
+  return Handle<mirror::Object>(&GetReferences()[i]);
+}
+
+inline MutableHandle<mirror::Object> HandleScope::GetMutableHandle(size_t i) {
+  DCHECK_LT(i, number_of_references_);
+  return MutableHandle<mirror::Object>(&GetReferences()[i]);
+}
+
+inline void HandleScope::SetReference(size_t i, mirror::Object* object) {
+  DCHECK_LT(i, number_of_references_);
+  GetReferences()[i].Assign(object);
+}
+
+inline bool HandleScope::Contains(StackReference<mirror::Object>* handle_scope_entry) const {
+  // A HandleScope should always contain something. One created by the
+  // jni_compiler should have a jobject/jclass as a native method is
+  // passed in a this pointer or a class
+  DCHECK_GT(number_of_references_, 0U);
+  return &GetReferences()[0] <= handle_scope_entry &&
+      handle_scope_entry <= &GetReferences()[number_of_references_ - 1];
+}
+
+template<size_t kNumReferences> template<class T>
+inline MutableHandle<T> StackHandleScope<kNumReferences>::NewHandle(T* object) {
+  SetReference(pos_, object);
+  MutableHandle<T> h(GetHandle<T>(pos_));
+  pos_++;
+  return h;
+}
+
+template<size_t kNumReferences> template<class T>
+inline HandleWrapper<T> StackHandleScope<kNumReferences>::NewHandleWrapper(T** object) {
+  SetReference(pos_, *object);
+  MutableHandle<T> h(GetHandle<T>(pos_));
+  pos_++;
+  return HandleWrapper<T>(object, h);
+}
+
+template<size_t kNumReferences>
+inline void StackHandleScope<kNumReferences>::SetReference(size_t i, mirror::Object* object) {
+  DCHECK_LT(i, kNumReferences);
+  VerifyObject(object);
+  GetReferences()[i].Assign(object);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_HANDLE_SCOPE_INL_H_
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 99059f9..782bbea 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -22,6 +22,7 @@
 #include "handle.h"
 #include "stack.h"
 #include "utils.h"
+#include "verify_object.h"
 
 namespace art {
 namespace mirror {
@@ -47,98 +48,77 @@
   // takes the pointer size explicitly so that at compile time we can cross-compile correctly.
 
   // Returns the size of a HandleScope containing num_references handles.
-  static size_t SizeOf(uint32_t num_references) {
-    size_t header_size = sizeof(HandleScope);
-    size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
-    return header_size + data_size;
-  }
+  static size_t SizeOf(uint32_t num_references);
 
   // Returns the size of a HandleScope containing num_references handles.
-  static size_t SizeOf(size_t pointer_size, uint32_t num_references) {
-    // Assume that the layout is packed.
-    size_t header_size = pointer_size + sizeof(number_of_references_);
-    size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
-    return header_size + data_size;
-  }
+  static size_t SizeOf(size_t pointer_size, uint32_t num_references);
 
   // Link to previous HandleScope or null.
   HandleScope* GetLink() const {
     return link_;
   }
 
-  void SetLink(HandleScope* link) {
-    DCHECK_NE(this, link);
-    link_ = link;
-  }
+  ALWAYS_INLINE mirror::Object* GetReference(size_t i) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Sets the number_of_references_ field for constructing tables out of raw memory. Warning: will
-  // not resize anything.
-  void SetNumberOfReferences(uint32_t num_references) {
-    number_of_references_ = num_references;
-  }
+  ALWAYS_INLINE Handle<mirror::Object> GetHandle(size_t i)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    return references_[i].AsMirrorPtr();
-  }
+  ALWAYS_INLINE MutableHandle<mirror::Object> GetMutableHandle(size_t i)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  Handle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    return Handle<mirror::Object>(&references_[i]);
-  }
+  ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  MutableHandle<mirror::Object> GetMutableHandle(size_t i)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    return MutableHandle<mirror::Object>(&references_[i]);
-  }
+  ALWAYS_INLINE bool Contains(StackReference<mirror::Object>* handle_scope_entry) const;
 
-  void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    references_[i].Assign(object);
-  }
-
-  bool Contains(StackReference<mirror::Object>* handle_scope_entry) const {
-    // A HandleScope should always contain something. One created by the
-    // jni_compiler should have a jobject/jclass as a native method is
-    // passed in a this pointer or a class
-    DCHECK_GT(number_of_references_, 0U);
-    return &references_[0] <= handle_scope_entry &&
-        handle_scope_entry <= &references_[number_of_references_ - 1];
-  }
-
-  // Offset of link within HandleScope, used by generated code
-  static size_t LinkOffset(size_t pointer_size) {
+  // Offset of link within HandleScope, used by generated code.
+  static size_t LinkOffset(size_t pointer_size ATTRIBUTE_UNUSED) {
     return 0;
   }
 
-  // Offset of length within handle scope, used by generated code
+  // Offset of length within handle scope, used by generated code.
   static size_t NumberOfReferencesOffset(size_t pointer_size) {
     return pointer_size;
   }
 
-  // Offset of link within handle scope, used by generated code
+  // Offset of link within handle scope, used by generated code.
   static size_t ReferencesOffset(size_t pointer_size) {
     return pointer_size + sizeof(number_of_references_);
   }
 
+  // Placement new creation.
+  static HandleScope* Create(void* storage, HandleScope* link, uint32_t num_references)
+      WARN_UNUSED {
+    return new (storage) HandleScope(link, num_references);
+  }
+
  protected:
+  // Return backing storage used for references.
+  ALWAYS_INLINE StackReference<mirror::Object>* GetReferences() const {
+    uintptr_t address = reinterpret_cast<uintptr_t>(this) + ReferencesOffset(sizeof(void*));
+    return reinterpret_cast<StackReference<mirror::Object>*>(address);
+  }
+
   explicit HandleScope(size_t number_of_references) :
       link_(nullptr), number_of_references_(number_of_references) {
   }
 
-  HandleScope* link_;
-  uint32_t number_of_references_;
+  // Semi-hidden constructor. Construction expected by generated code and StackHandleScope.
+  explicit HandleScope(HandleScope* link, uint32_t num_references) :
+      link_(link), number_of_references_(num_references) {
+  }
 
-  // number_of_references_ are available if this is allocated and filled in by jni_compiler.
-  StackReference<mirror::Object> references_[0];
+  // Link-list of handle scopes. The root is held by a Thread.
+  HandleScope* const link_;
+
+  // Number of handlerized references.
+  const uint32_t number_of_references_;
+
+  // Storage for references.
+  // StackReference<mirror::Object> references_[number_of_references_]
 
  private:
-  template<size_t kNumReferences> friend class StackHandleScope;
-
   DISALLOW_COPY_AND_ASSIGN(HandleScope);
 };
 
@@ -156,57 +136,35 @@
   }
 
  private:
-  T** obj_;
+  T** const obj_;
 };
 
 // Scoped handle storage of a fixed size that is usually stack allocated.
 template<size_t kNumReferences>
 class PACKED(4) StackHandleScope FINAL : public HandleScope {
  public:
-  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.
-  mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    return references_storage_[i].AsMirrorPtr();
-  }
-
-  MutableHandle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    return MutableHandle<mirror::Object>(&references_storage_[i]);
-  }
-
-  void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    DCHECK_LT(i, number_of_references_);
-    references_storage_[i].Assign(object);
-  }
+  explicit ALWAYS_INLINE StackHandleScope(Thread* self, mirror::Object* fill_value = nullptr);
+  ALWAYS_INLINE ~StackHandleScope();
 
   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;
-  }
+  ALWAYS_INLINE MutableHandle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   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);
-  }
+  ALWAYS_INLINE HandleWrapper<T> NewHandleWrapper(T** object)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  // References_storage_ needs to be first so that it appears in the same location as
-  // HandleScope::references_.
-  StackReference<mirror::Object> references_storage_[kNumReferences];
+  template<class T>
+  ALWAYS_INLINE MutableHandle<T> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK_LT(i, kNumReferences);
+    return MutableHandle<T>(&GetReferences()[i]);
+  }
+
+  // Reference storage needs to be first as expected by the HandleScope layout.
+  StackReference<mirror::Object> storage_[kNumReferences];
 
   // The thread that the stack handle scope is a linked list upon. The stack handle scope will
   // push and pop itself from this thread.
diff --git a/runtime/handle_scope_test.cc b/runtime/handle_scope_test.cc
index de563c1..dc99987 100644
--- a/runtime/handle_scope_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -25,7 +25,7 @@
 template<size_t kNumReferences>
 class NoThreadStackHandleScope : public HandleScope {
  public:
-  explicit NoThreadStackHandleScope() : HandleScope(kNumReferences) {
+  explicit NoThreadStackHandleScope(HandleScope* link) : HandleScope(link, kNumReferences) {
   }
   ~NoThreadStackHandleScope() {
   }
@@ -41,22 +41,20 @@
 TEST(HandleScopeTest, Offsets) NO_THREAD_SAFETY_ANALYSIS {
   // As the members of HandleScope are private, we cannot use OFFSETOF_MEMBER
   // here. So do the inverse: set some data, and access it through pointers created from the offsets.
-  NoThreadStackHandleScope<1> test_table;
+  NoThreadStackHandleScope<0x9ABC> test_table(reinterpret_cast<HandleScope*>(0x5678));
   test_table.SetReference(0, reinterpret_cast<mirror::Object*>(0x1234));
-  test_table.SetLink(reinterpret_cast<HandleScope*>(0x5678));
-  test_table.SetNumberOfReferences(0x9ABC);
 
-  byte* table_base_ptr = reinterpret_cast<byte*>(&test_table);
+  uint8_t* table_base_ptr = reinterpret_cast<uint8_t*>(&test_table);
 
   {
     uintptr_t* link_ptr = reinterpret_cast<uintptr_t*>(table_base_ptr +
-        HandleScope::LinkOffset(kPointerSize));
+        HandleScope::LinkOffset(sizeof(void*)));
     EXPECT_EQ(*link_ptr, static_cast<size_t>(0x5678));
   }
 
   {
     uint32_t* num_ptr = reinterpret_cast<uint32_t*>(table_base_ptr +
-        HandleScope::NumberOfReferencesOffset(kPointerSize));
+        HandleScope::NumberOfReferencesOffset(sizeof(void*)));
     EXPECT_EQ(*num_ptr, static_cast<size_t>(0x9ABC));
   }
 
@@ -66,7 +64,7 @@
     EXPECT_EQ(sizeof(StackReference<mirror::Object>), sizeof(uint32_t));
 
     uint32_t* ref_ptr = reinterpret_cast<uint32_t*>(table_base_ptr +
-        HandleScope::ReferencesOffset(kPointerSize));
+        HandleScope::ReferencesOffset(sizeof(void*)));
     EXPECT_EQ(*ref_ptr, static_cast<uint32_t>(0x1234));
   }
 }
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index fd67197..0b04276 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -44,10 +44,13 @@
 #include "common_throws.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "gc_root.h"
 #include "gc/accounting/heap_bitmap.h"
 #include "gc/heap.h"
 #include "gc/space/space.h"
 #include "globals.h"
+#include "jdwp/jdwp.h"
+#include "jdwp/jdwp_priv.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
@@ -61,46 +64,17 @@
 
 namespace hprof {
 
-#define UNIQUE_ERROR -((((uintptr_t)__func__) << 16 | __LINE__) & (0x7fffffff))
+static constexpr bool kDirectStream = true;
 
-#define HPROF_TIME 0
-#define HPROF_NULL_STACK_TRACE   0
-#define HPROF_NULL_THREAD        0
+static constexpr uint32_t kHprofTime = 0;
+static constexpr uint32_t kHprofNullStackTrace = 0;
+static constexpr uint32_t kHprofNullThread = 0;
 
-#define U2_TO_BUF_BE(buf, offset, value) \
-    do { \
-      unsigned char* buf_ = (unsigned char*)(buf); \
-      int offset_ = static_cast<int>(offset); \
-      uint16_t value_ = (uint16_t)(value); \
-      buf_[offset_ + 0] = (unsigned char)(value_ >>  8); \
-      buf_[offset_ + 1] = (unsigned char)(value_      ); \
-    } while (0)
+static constexpr size_t kMaxObjectsPerSegment = 128;
+static constexpr size_t kMaxBytesPerSegment = 4096;
 
-#define U4_TO_BUF_BE(buf, offset, value) \
-    do { \
-      unsigned char* buf_ = (unsigned char*)(buf); \
-      int offset_ = static_cast<int>(offset); \
-      uint32_t value_ = (uint32_t)(value); \
-      buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
-      buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
-      buf_[offset_ + 2] = (unsigned char)(value_ >>  8); \
-      buf_[offset_ + 3] = (unsigned char)(value_      ); \
-    } while (0)
-
-#define U8_TO_BUF_BE(buf, offset, value) \
-    do { \
-      unsigned char* buf_ = (unsigned char*)(buf); \
-      int offset_ = static_cast<int>(offset); \
-      uint64_t value_ = (uint64_t)(value); \
-      buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
-      buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
-      buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
-      buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
-      buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
-      buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
-      buf_[offset_ + 6] = (unsigned char)(value_ >>  8); \
-      buf_[offset_ + 7] = (unsigned char)(value_      ); \
-    } while (0)
+// The static field-name for the synthetic object generated to account for class static overhead.
+static constexpr const char* kStaticOverheadName = "$staticOverhead";
 
 enum HprofTag {
   HPROF_TAG_STRING = 0x01,
@@ -170,216 +144,267 @@
 typedef uint32_t HprofStringId;
 typedef uint32_t HprofClassObjectId;
 
-// Represents a top-level hprof record, whose serialized format is:
-// U1  TAG: denoting the type of the record
-// U4  TIME: number of microseconds since the time stamp in the header
-// U4  LENGTH: number of bytes that follow this uint32_t field and belong to this record
-// U1* BODY: as many bytes as specified in the above uint32_t field
-class HprofRecord {
+class EndianOutput {
  public:
-  HprofRecord() : alloc_length_(128), fp_(nullptr), tag_(0), time_(0), length_(0), dirty_(false) {
-    body_ = reinterpret_cast<unsigned char*>(malloc(alloc_length_));
+  EndianOutput() : length_(0), sum_length_(0), max_length_(0), started_(false) {}
+  virtual ~EndianOutput() {}
+
+  void StartNewRecord(uint8_t tag, uint32_t time) {
+    if (length_ > 0) {
+      EndRecord();
+    }
+    DCHECK_EQ(length_, 0U);
+    AddU1(tag);
+    AddU4(time);
+    AddU4(0xdeaddead);  // Length, replaced on flush.
+    started_ = true;
   }
 
-  ~HprofRecord() {
-    free(body_);
-  }
-
-  int StartNewRecord(FILE* fp, uint8_t tag, uint32_t time) {
-    int rc = Flush();
-    if (rc != 0) {
-      return rc;
+  void EndRecord() {
+    // Replace length in header.
+    if (started_) {
+      UpdateU4(sizeof(uint8_t) + sizeof(uint32_t),
+               length_ - sizeof(uint8_t) - 2 * sizeof(uint32_t));
     }
 
-    fp_ = fp;
-    tag_ = tag;
-    time_ = time;
+    HandleEndRecord();
+
+    sum_length_ += length_;
+    max_length_ = std::max(max_length_, length_);
     length_ = 0;
-    dirty_ = true;
-    return 0;
+    started_ = false;
   }
 
-  int Flush() {
-    if (dirty_) {
-      unsigned char headBuf[sizeof(uint8_t) + 2 * sizeof(uint32_t)];
-
-      headBuf[0] = tag_;
-      U4_TO_BUF_BE(headBuf, 1, time_);
-      U4_TO_BUF_BE(headBuf, 5, length_);
-
-      int nb = fwrite(headBuf, 1, sizeof(headBuf), fp_);
-      if (nb != sizeof(headBuf)) {
-        return UNIQUE_ERROR;
-      }
-      nb = fwrite(body_, 1, length_, fp_);
-      if (nb != static_cast<int>(length_)) {
-        return UNIQUE_ERROR;
-      }
-
-      dirty_ = false;
-    }
-    // TODO if we used less than half (or whatever) of allocLen, shrink the buffer.
-    return 0;
+  void AddU1(uint8_t value) {
+    AddU1List(&value, 1);
+  }
+  void AddU2(uint16_t value) {
+    AddU2List(&value, 1);
+  }
+  void AddU4(uint32_t value) {
+    AddU4List(&value, 1);
   }
 
-  int AddU1(uint8_t value) {
-    int err = GuaranteeRecordAppend(1);
-    if (UNLIKELY(err != 0)) {
-      return err;
-    }
-
-    body_[length_++] = value;
-    return 0;
+  void AddU8(uint64_t value) {
+    AddU8List(&value, 1);
   }
 
-  int AddU2(uint16_t value) {
-    return AddU2List(&value, 1);
-  }
-
-  int AddU4(uint32_t value) {
-    return AddU4List(&value, 1);
-  }
-
-  int AddU8(uint64_t value) {
-    return AddU8List(&value, 1);
-  }
-
-  int AddObjectId(const mirror::Object* value) {
-    return AddU4(PointerToLowMemUInt32(value));
+  void AddObjectId(const mirror::Object* value) {
+    AddU4(PointerToLowMemUInt32(value));
   }
 
   // The ID for the synthetic object generated to account for class static overhead.
-  int AddClassStaticsId(const mirror::Class* value) {
-    return AddU4(1 | PointerToLowMemUInt32(value));
+  void AddClassStaticsId(const mirror::Class* value) {
+    AddU4(1 | PointerToLowMemUInt32(value));
   }
 
-  int AddJniGlobalRefId(jobject value) {
-    return AddU4(PointerToLowMemUInt32(value));
+  void AddJniGlobalRefId(jobject value) {
+    AddU4(PointerToLowMemUInt32(value));
   }
 
-  int AddClassId(HprofClassObjectId value) {
-    return AddU4(value);
+  void AddClassId(HprofClassObjectId value) {
+    AddU4(value);
   }
 
-  int AddStringId(HprofStringId value) {
-    return AddU4(value);
+  void AddStringId(HprofStringId value) {
+    AddU4(value);
   }
 
-  int AddU1List(const uint8_t* values, size_t numValues) {
-    int err = GuaranteeRecordAppend(numValues);
-    if (UNLIKELY(err != 0)) {
-      return err;
-    }
-
-    memcpy(body_ + length_, values, numValues);
-    length_ += numValues;
-    return 0;
+  void AddU1List(const uint8_t* values, size_t count) {
+    HandleU1List(values, count);
+    length_ += count;
+  }
+  void AddU2List(const uint16_t* values, size_t count) {
+    HandleU2List(values, count);
+    length_ += count * sizeof(uint16_t);
+  }
+  void AddU4List(const uint32_t* values, size_t count) {
+    HandleU4List(values, count);
+    length_ += count * sizeof(uint32_t);
+  }
+  virtual void UpdateU4(size_t offset ATTRIBUTE_UNUSED, uint32_t new_value ATTRIBUTE_UNUSED) {
+    DCHECK_LE(offset, length_ - 4);
+  }
+  void AddU8List(const uint64_t* values, size_t count) {
+    HandleU8List(values, count);
+    length_ += count * sizeof(uint64_t);
   }
 
-  int AddU2List(const uint16_t* values, size_t numValues) {
-    int err = GuaranteeRecordAppend(numValues * 2);
-    if (UNLIKELY(err != 0)) {
-      return err;
-    }
-
-    unsigned char* insert = body_ + length_;
-    for (size_t i = 0; i < numValues; ++i) {
-      U2_TO_BUF_BE(insert, 0, *values++);
-      insert += sizeof(*values);
-    }
-    length_ += numValues * 2;
-    return 0;
-  }
-
-  int AddU4List(const uint32_t* values, size_t numValues) {
-    int err = GuaranteeRecordAppend(numValues * 4);
-    if (UNLIKELY(err != 0)) {
-      return err;
-    }
-
-    unsigned char* insert = body_ + length_;
-    for (size_t i = 0; i < numValues; ++i) {
-      U4_TO_BUF_BE(insert, 0, *values++);
-      insert += sizeof(*values);
-    }
-    length_ += numValues * 4;
-    return 0;
-  }
-
-  void UpdateU4(size_t offset, uint32_t new_value) {
-    U4_TO_BUF_BE(body_, offset, new_value);
-  }
-
-  int AddU8List(const uint64_t* values, size_t numValues) {
-    int err = GuaranteeRecordAppend(numValues * 8);
-    if (err != 0) {
-      return err;
-    }
-
-    unsigned char* insert = body_ + length_;
-    for (size_t i = 0; i < numValues; ++i) {
-      U8_TO_BUF_BE(insert, 0, *values++);
-      insert += sizeof(*values);
-    }
-    length_ += numValues * 8;
-    return 0;
-  }
-
-  int AddIdList(mirror::ObjectArray<mirror::Object>* values)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    int32_t length = values->GetLength();
+  void AddIdList(mirror::ObjectArray<mirror::Object>* values)
+  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    const int32_t length = values->GetLength();
     for (int32_t i = 0; i < length; ++i) {
-      int err = AddObjectId(values->GetWithoutChecks(i));
-      if (UNLIKELY(err != 0)) {
-        return err;
-      }
+      AddObjectId(values->GetWithoutChecks(i));
     }
-    return 0;
   }
 
-  int AddUtf8String(const char* str) {
+  void AddUtf8String(const char* str) {
     // The terminating NUL character is NOT written.
-    return AddU1List((const uint8_t*)str, strlen(str));
+    AddU1List((const uint8_t*)str, strlen(str));
   }
 
-  size_t Size() const {
+  size_t Length() const {
     return length_;
   }
 
- private:
-  int GuaranteeRecordAppend(size_t nmore) {
-    size_t minSize = length_ + nmore;
-    if (minSize > alloc_length_) {
-      size_t newAllocLen = alloc_length_ * 2;
-      if (newAllocLen < minSize) {
-        newAllocLen = alloc_length_ + nmore + nmore/2;
-      }
-      unsigned char* newBody = (unsigned char*)realloc(body_, newAllocLen);
-      if (newBody != NULL) {
-        body_ = newBody;
-        alloc_length_ = newAllocLen;
-      } else {
-        // TODO: set an error flag so future ops will fail
-        return UNIQUE_ERROR;
-      }
-    }
-
-    CHECK_LE(length_ + nmore, alloc_length_);
-    return 0;
+  size_t SumLength() const {
+    return sum_length_;
   }
 
-  size_t alloc_length_;
-  unsigned char* body_;
+  size_t MaxLength() const {
+    return max_length_;
+  }
 
-  FILE* fp_;
-  uint8_t tag_;
-  uint32_t time_;
-  size_t length_;
-  bool dirty_;
+ protected:
+  virtual void HandleU1List(const uint8_t* values ATTRIBUTE_UNUSED,
+                            size_t count ATTRIBUTE_UNUSED) {
+  }
+  virtual void HandleU2List(const uint16_t* values ATTRIBUTE_UNUSED,
+                            size_t count ATTRIBUTE_UNUSED) {
+  }
+  virtual void HandleU4List(const uint32_t* values ATTRIBUTE_UNUSED,
+                            size_t count ATTRIBUTE_UNUSED) {
+  }
+  virtual void HandleU8List(const uint64_t* values ATTRIBUTE_UNUSED,
+                            size_t count ATTRIBUTE_UNUSED) {
+  }
+  virtual void HandleEndRecord() {
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(HprofRecord);
+  size_t length_;      // Current record size.
+  size_t sum_length_;  // Size of all data.
+  size_t max_length_;  // Maximum seen length.
+  bool started_;       // Was StartRecord called?
 };
 
+// This keeps things buffered until flushed.
+class EndianOutputBuffered : public EndianOutput {
+ public:
+  explicit EndianOutputBuffered(size_t reserve_size) {
+    buffer_.reserve(reserve_size);
+  }
+  virtual ~EndianOutputBuffered() {}
+
+  void UpdateU4(size_t offset, uint32_t new_value) OVERRIDE {
+    DCHECK_LE(offset, length_ - 4);
+    buffer_[offset + 0] = static_cast<uint8_t>((new_value >> 24) & 0xFF);
+    buffer_[offset + 1] = static_cast<uint8_t>((new_value >> 16) & 0xFF);
+    buffer_[offset + 2] = static_cast<uint8_t>((new_value >> 8)  & 0xFF);
+    buffer_[offset + 3] = static_cast<uint8_t>((new_value >> 0)  & 0xFF);
+  }
+
+ protected:
+  void HandleU1List(const uint8_t* values, size_t count) OVERRIDE {
+    DCHECK_EQ(length_, buffer_.size());
+    buffer_.insert(buffer_.end(), values, values + count);
+  }
+
+  void HandleU2List(const uint16_t* values, size_t count) OVERRIDE {
+    DCHECK_EQ(length_, buffer_.size());
+    for (size_t i = 0; i < count; ++i) {
+      uint16_t value = *values;
+      buffer_.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 0) & 0xFF));
+      values++;
+    }
+  }
+
+  void HandleU4List(const uint32_t* values, size_t count) OVERRIDE {
+    DCHECK_EQ(length_, buffer_.size());
+    for (size_t i = 0; i < count; ++i) {
+      uint32_t value = *values;
+      buffer_.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 8)  & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 0)  & 0xFF));
+      values++;
+    }
+  }
+
+  void HandleU8List(const uint64_t* values, size_t count) OVERRIDE {
+    DCHECK_EQ(length_, buffer_.size());
+    for (size_t i = 0; i < count; ++i) {
+      uint64_t value = *values;
+      buffer_.push_back(static_cast<uint8_t>((value >> 56) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 48) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 40) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 32) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 8)  & 0xFF));
+      buffer_.push_back(static_cast<uint8_t>((value >> 0)  & 0xFF));
+      values++;
+    }
+  }
+
+  void HandleEndRecord() OVERRIDE {
+    DCHECK_EQ(buffer_.size(), length_);
+    if (kIsDebugBuild && started_) {
+      uint32_t stored_length =
+          static_cast<uint32_t>(buffer_[5]) << 24 |
+          static_cast<uint32_t>(buffer_[6]) << 16 |
+          static_cast<uint32_t>(buffer_[7]) << 8 |
+          static_cast<uint32_t>(buffer_[8]);
+      DCHECK_EQ(stored_length, length_ - sizeof(uint8_t) - 2 * sizeof(uint32_t));
+    }
+    HandleFlush(buffer_.data(), length_);
+    buffer_.clear();
+  }
+
+  virtual void HandleFlush(const uint8_t* buffer ATTRIBUTE_UNUSED, size_t length ATTRIBUTE_UNUSED) {
+  }
+
+  std::vector<uint8_t> buffer_;
+};
+
+class FileEndianOutput FINAL : public EndianOutputBuffered {
+ public:
+  FileEndianOutput(File* fp, size_t reserved_size)
+      : EndianOutputBuffered(reserved_size), fp_(fp), errors_(false) {
+    DCHECK(fp != nullptr);
+  }
+  ~FileEndianOutput() {
+  }
+
+  bool Errors() {
+    return errors_;
+  }
+
+ protected:
+  void HandleFlush(const uint8_t* buffer, size_t length) OVERRIDE {
+    if (!errors_) {
+      errors_ = !fp_->WriteFully(buffer, length);
+    }
+  }
+
+ private:
+  File* fp_;
+  bool errors_;
+};
+
+class NetStateEndianOutput FINAL : public EndianOutputBuffered {
+ public:
+  NetStateEndianOutput(JDWP::JdwpNetStateBase* net_state, size_t reserved_size)
+      : EndianOutputBuffered(reserved_size), net_state_(net_state) {
+    DCHECK(net_state != nullptr);
+  }
+  ~NetStateEndianOutput() {}
+
+ protected:
+  void HandleFlush(const uint8_t* buffer, size_t length) OVERRIDE {
+    std::vector<iovec> iov;
+    iov.push_back(iovec());
+    iov[0].iov_base = const_cast<void*>(reinterpret_cast<const void*>(buffer));
+    iov[0].iov_len = length;
+    net_state_->WriteBufferedPacketLocked(iov);
+  }
+
+ private:
+  JDWP::JdwpNetStateBase* net_state_;
+};
+
+#define __ output->
+
 class Hprof {
  public:
   Hprof(const char* output_filename, int fd, bool direct_to_ddms)
@@ -387,221 +412,180 @@
         fd_(fd),
         direct_to_ddms_(direct_to_ddms),
         start_ns_(NanoTime()),
-        current_record_(),
-        gc_thread_serial_number_(0),
-        gc_scan_state_(0),
         current_heap_(HPROF_HEAP_DEFAULT),
         objects_in_segment_(0),
-        header_fp_(NULL),
-        header_data_ptr_(NULL),
-        header_data_size_(0),
-        body_fp_(NULL),
-        body_data_ptr_(NULL),
-        body_data_size_(0),
         next_string_id_(0x400000) {
     LOG(INFO) << "hprof: heap dump \"" << filename_ << "\" starting...";
-
-    header_fp_ = open_memstream(&header_data_ptr_, &header_data_size_);
-    if (header_fp_ == NULL) {
-      PLOG(FATAL) << "header open_memstream failed";
-    }
-
-    body_fp_ = open_memstream(&body_data_ptr_, &body_data_size_);
-    if (body_fp_ == NULL) {
-      PLOG(FATAL) << "body open_memstream failed";
-    }
-  }
-
-  ~Hprof() {
-    if (header_fp_ != NULL) {
-      fclose(header_fp_);
-    }
-    if (body_fp_ != NULL) {
-      fclose(body_fp_);
-    }
-    free(header_data_ptr_);
-    free(body_data_ptr_);
   }
 
   void Dump()
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) {
-    // Walk the roots and the heap.
-    current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
-    Runtime::Current()->VisitRoots(RootVisitor, this);
-    Thread* self = Thread::Current();
+    // First pass to measure the size of the dump.
+    size_t overall_size;
+    size_t max_length;
     {
-      ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-      Runtime::Current()->GetHeap()->VisitObjects(VisitObjectCallback, this);
+      EndianOutput count_output;
+      ProcessHeap(&count_output, false);
+      overall_size = count_output.SumLength();
+      max_length = count_output.MaxLength();
     }
-    current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_END, HPROF_TIME);
-    current_record_.Flush();
-    fflush(body_fp_);
 
-    // Write the header.
-    WriteFixedHeader();
-    // Write the string and class tables, and any stack traces, to the header.
-    // (jhat requires that these appear before any of the data in the body that refers to them.)
-    WriteStringTable();
-    WriteClassTable();
-    WriteStackTraces();
-    current_record_.Flush();
-    fflush(header_fp_);
-
-    bool okay = true;
+    bool okay;
     if (direct_to_ddms_) {
-      // Send the data off to DDMS.
-      iovec iov[2];
-      iov[0].iov_base = header_data_ptr_;
-      iov[0].iov_len = header_data_size_;
-      iov[1].iov_base = body_data_ptr_;
-      iov[1].iov_len = body_data_size_;
-      Dbg::DdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
-    } else {
-      // Where exactly are we writing to?
-      int out_fd;
-      if (fd_ >= 0) {
-        out_fd = dup(fd_);
-        if (out_fd < 0) {
-          ThrowRuntimeException("Couldn't dump heap; dup(%d) failed: %s", fd_, strerror(errno));
-          return;
-        }
+      if (kDirectStream) {
+        okay = DumpToDdmsDirect(overall_size, max_length, CHUNK_TYPE("HPDS"));
       } else {
-        out_fd = open(filename_.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
-        if (out_fd < 0) {
-          ThrowRuntimeException("Couldn't dump heap; open(\"%s\") failed: %s", filename_.c_str(),
-                                strerror(errno));
-          return;
-        }
+        okay = DumpToDdmsBuffered(overall_size, max_length);
       }
-
-      std::unique_ptr<File> file(new File(out_fd, filename_));
-      okay = file->WriteFully(header_data_ptr_, header_data_size_) &&
-          file->WriteFully(body_data_ptr_, body_data_size_);
-      if (!okay) {
-        std::string msg(StringPrintf("Couldn't dump heap; writing \"%s\" failed: %s",
-                                     filename_.c_str(), strerror(errno)));
-        ThrowRuntimeException("%s", msg.c_str());
-        LOG(ERROR) << msg;
-      }
+    } else {
+      okay = DumpToFile(overall_size, max_length);
     }
 
-    // Throw out a log message for the benefit of "runhat".
     if (okay) {
       uint64_t duration = NanoTime() - start_ns_;
       LOG(INFO) << "hprof: heap dump completed ("
-          << PrettySize(header_data_size_ + body_data_size_ + 1023)
+          << PrettySize(RoundUp(overall_size, 1024))
           << ") in " << PrettyDuration(duration);
     }
   }
 
  private:
-  static void RootVisitor(mirror::Object** obj, void* arg, uint32_t thread_id, RootType root_type)
+  struct Env {
+    Hprof* hprof;
+    EndianOutput* output;
+  };
+
+  static void RootVisitor(mirror::Object** obj, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(arg != nullptr);
     DCHECK(obj != nullptr);
     DCHECK(*obj != nullptr);
-    reinterpret_cast<Hprof*>(arg)->VisitRoot(*obj, thread_id, root_type);
+    Env* env = reinterpret_cast<Env*>(arg);
+    env->hprof->VisitRoot(*obj, root_info, env->output);
   }
 
   static void VisitObjectCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(obj != NULL);
-    DCHECK(arg != NULL);
-    reinterpret_cast<Hprof*>(arg)->DumpHeapObject(obj);
+    DCHECK(obj != nullptr);
+    DCHECK(arg != nullptr);
+    Env* env = reinterpret_cast<Env*>(arg);
+    env->hprof->DumpHeapObject(obj, env->output);
   }
 
-  void VisitRoot(const mirror::Object* obj, uint32_t thread_id, RootType type)
+  void DumpHeapObject(mirror::Object* obj, EndianOutput* output)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  int DumpHeapObject(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void DumpHeapClass(mirror::Class* klass, EndianOutput* output)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void Finish() {
+  void DumpHeapArray(mirror::Array* obj, mirror::Class* klass, EndianOutput* output)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass, EndianOutput* output)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void ProcessHeap(EndianOutput* output, bool header_first)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // Reset current heap and object count.
+    current_heap_ = HPROF_HEAP_DEFAULT;
+    objects_in_segment_ = 0;
+
+    if (header_first) {
+      ProcessHeader(output);
+      ProcessBody(output);
+    } else {
+      ProcessBody(output);
+      ProcessHeader(output);
+    }
   }
 
-  int WriteClassTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    HprofRecord* rec = &current_record_;
+  void ProcessBody(EndianOutput* output) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Runtime* runtime = Runtime::Current();
+    // Walk the roots and the heap.
+    output->StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, kHprofTime);
+
+    Env env = { this, output };
+    runtime->VisitRoots(RootVisitor, &env);
+    runtime->GetHeap()->VisitObjects(VisitObjectCallback, &env);
+
+    output->StartNewRecord(HPROF_TAG_HEAP_DUMP_END, kHprofTime);
+    output->EndRecord();
+  }
+
+  void ProcessHeader(EndianOutput* output) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // Write the header.
+    WriteFixedHeader(output);
+    // Write the string and class tables, and any stack traces, to the header.
+    // (jhat requires that these appear before any of the data in the body that refers to them.)
+    WriteStringTable(output);
+    WriteClassTable(output);
+    WriteStackTraces(output);
+    output->EndRecord();
+  }
+
+  void WriteClassTable(EndianOutput* output) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t nextSerialNumber = 1;
 
     for (mirror::Class* c : classes_) {
       CHECK(c != nullptr);
-
-      int err = current_record_.StartNewRecord(header_fp_, HPROF_TAG_LOAD_CLASS, HPROF_TIME);
-      if (UNLIKELY(err != 0)) {
-        return err;
-      }
-
+      output->StartNewRecord(HPROF_TAG_LOAD_CLASS, kHprofTime);
       // LOAD CLASS format:
       // U4: class serial number (always > 0)
       // ID: class object ID. We use the address of the class object structure as its ID.
       // U4: stack trace serial number
       // ID: class name string ID
-      rec->AddU4(nextSerialNumber++);
-      rec->AddObjectId(c);
-      rec->AddU4(HPROF_NULL_STACK_TRACE);
-      rec->AddStringId(LookupClassNameId(c));
+      __ AddU4(nextSerialNumber++);
+      __ AddObjectId(c);
+      __ AddU4(kHprofNullStackTrace);
+      __ AddStringId(LookupClassNameId(c));
     }
-
-    return 0;
   }
 
-  int WriteStringTable() {
-    HprofRecord* rec = &current_record_;
-
-    for (std::pair<std::string, HprofStringId> p : strings_) {
+  void WriteStringTable(EndianOutput* output) {
+    for (const std::pair<std::string, HprofStringId>& p : strings_) {
       const std::string& string = p.first;
-      size_t id = p.second;
+      const size_t id = p.second;
 
-      int err = current_record_.StartNewRecord(header_fp_, HPROF_TAG_STRING, HPROF_TIME);
-      if (err != 0) {
-        return err;
-      }
+      output->StartNewRecord(HPROF_TAG_STRING, kHprofTime);
 
       // STRING format:
       // ID:  ID for this string
       // U1*: UTF8 characters for string (NOT NULL terminated)
       //      (the record format encodes the length)
-      err = rec->AddU4(id);
-      if (err != 0) {
-        return err;
-      }
-      err = rec->AddUtf8String(string.c_str());
-      if (err != 0) {
-        return err;
-      }
+      __ AddU4(id);
+      __ AddUtf8String(string.c_str());
     }
-
-    return 0;
   }
 
-  void StartNewHeapDumpSegment() {
+  void StartNewHeapDumpSegment(EndianOutput* output) {
     // This flushes the old segment and starts a new one.
-    current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
+    output->StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, kHprofTime);
     objects_in_segment_ = 0;
-
     // Starting a new HEAP_DUMP resets the heap to default.
     current_heap_ = HPROF_HEAP_DEFAULT;
   }
 
-  int MarkRootObject(const mirror::Object* obj, jobject jniObj);
+  void CheckHeapSegmentConstraints(EndianOutput* output) {
+    if (objects_in_segment_ >= kMaxObjectsPerSegment || output->Length() >= kMaxBytesPerSegment) {
+      StartNewHeapDumpSegment(output);
+    }
+  }
+
+  void VisitRoot(const mirror::Object* obj, const RootInfo& root_info, EndianOutput* output)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void MarkRootObject(const mirror::Object* obj, jobject jni_obj, HprofHeapTag heap_tag,
+                      uint32_t thread_serial, EndianOutput* output);
 
   HprofClassObjectId LookupClassId(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (c == nullptr) {
-      // c is the superclass of java.lang.Object or a primitive.
-      return 0;
-    }
-
-    {
+    if (c != nullptr) {
       auto result = classes_.insert(c);
       const mirror::Class* present = *result.first;
       CHECK_EQ(present, c);
+      // Make sure that we've assigned a string ID for this class' name
+      LookupClassNameId(c);
     }
-
-    // Make sure that we've assigned a string ID for this class' name
-    LookupClassNameId(c);
-
-    HprofClassObjectId result = PointerToLowMemUInt32(c);
-    return result;
+    return PointerToLowMemUInt32(c);
   }
 
   HprofStringId LookupStringId(mirror::String* string) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -626,46 +610,125 @@
     return LookupStringId(PrettyDescriptor(c));
   }
 
-  void WriteFixedHeader() {
-    char magic[] = "JAVA PROFILE 1.0.3";
-    unsigned char buf[4];
-
+  void WriteFixedHeader(EndianOutput* output) {
     // Write the file header.
     // U1: NUL-terminated magic string.
-    fwrite(magic, 1, sizeof(magic), header_fp_);
+    const char magic[] = "JAVA PROFILE 1.0.3";
+    __ AddU1List(reinterpret_cast<const uint8_t*>(magic), sizeof(magic));
 
     // U4: size of identifiers.  We're using addresses as IDs and our heap references are stored
     // as uint32_t.
     // Note of warning: hprof-conv hard-codes the size of identifiers to 4.
-    COMPILE_ASSERT(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(uint32_t),
-      UnexpectedHeapReferenceSize);
-    U4_TO_BUF_BE(buf, 0, sizeof(uint32_t));
-    fwrite(buf, 1, sizeof(uint32_t), header_fp_);
+    static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(uint32_t),
+                  "Unexpected HeapReference size");
+    __ AddU4(sizeof(uint32_t));
 
     // The current time, in milliseconds since 0:00 GMT, 1/1/70.
     timeval now;
-    uint64_t nowMs;
-    if (gettimeofday(&now, NULL) < 0) {
-      nowMs = 0;
-    } else {
-      nowMs = (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
-    }
-
+    const uint64_t nowMs = (gettimeofday(&now, nullptr) < 0) ? 0 :
+        (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
+    // TODO: It seems it would be correct to use U8.
     // U4: high word of the 64-bit time.
-    U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs >> 32));
-    fwrite(buf, 1, sizeof(uint32_t), header_fp_);
-
+    __ AddU4(static_cast<uint32_t>(nowMs >> 32));
     // U4: low word of the 64-bit time.
-    U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs & 0xffffffffULL));
-    fwrite(buf, 1, sizeof(uint32_t), header_fp_);  // xxx fix the time
+    __ AddU4(static_cast<uint32_t>(nowMs & 0xFFFFFFFF));
   }
 
-  void WriteStackTraces() {
+  void WriteStackTraces(EndianOutput* output) {
     // Write a dummy stack trace record so the analysis tools don't freak out.
-    current_record_.StartNewRecord(header_fp_, HPROF_TAG_STACK_TRACE, HPROF_TIME);
-    current_record_.AddU4(HPROF_NULL_STACK_TRACE);
-    current_record_.AddU4(HPROF_NULL_THREAD);
-    current_record_.AddU4(0);    // no frames
+    output->StartNewRecord(HPROF_TAG_STACK_TRACE, kHprofTime);
+    __ AddU4(kHprofNullStackTrace);
+    __ AddU4(kHprofNullThread);
+    __ AddU4(0);    // no frames
+  }
+
+  bool DumpToDdmsBuffered(size_t overall_size ATTRIBUTE_UNUSED, size_t max_length ATTRIBUTE_UNUSED)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    LOG(FATAL) << "Unimplemented";
+    UNREACHABLE();
+    //        // Send the data off to DDMS.
+    //        iovec iov[2];
+    //        iov[0].iov_base = header_data_ptr_;
+    //        iov[0].iov_len = header_data_size_;
+    //        iov[1].iov_base = body_data_ptr_;
+    //        iov[1].iov_len = body_data_size_;
+    //        Dbg::DdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
+  }
+
+  bool DumpToFile(size_t overall_size, size_t max_length)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // Where exactly are we writing to?
+    int out_fd;
+    if (fd_ >= 0) {
+      out_fd = dup(fd_);
+      if (out_fd < 0) {
+        ThrowRuntimeException("Couldn't dump heap; dup(%d) failed: %s", fd_, strerror(errno));
+        return false;
+      }
+    } else {
+      out_fd = open(filename_.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
+      if (out_fd < 0) {
+        ThrowRuntimeException("Couldn't dump heap; open(\"%s\") failed: %s", filename_.c_str(),
+                              strerror(errno));
+        return false;
+      }
+    }
+
+    std::unique_ptr<File> file(new File(out_fd, filename_, true));
+    bool okay;
+    {
+      FileEndianOutput file_output(file.get(), max_length);
+      ProcessHeap(&file_output, true);
+      okay = !file_output.Errors();
+
+      if (okay) {
+        // Check for expected size.
+        CHECK_EQ(file_output.SumLength(), overall_size);
+      }
+    }
+
+    if (okay) {
+      okay = file->FlushCloseOrErase() == 0;
+    } else {
+      file->Erase();
+    }
+    if (!okay) {
+      std::string msg(StringPrintf("Couldn't dump heap; writing \"%s\" failed: %s",
+                                   filename_.c_str(), strerror(errno)));
+      ThrowRuntimeException("%s", msg.c_str());
+      LOG(ERROR) << msg;
+    }
+
+    return okay;
+  }
+
+  bool DumpToDdmsDirect(size_t overall_size, size_t max_length, uint32_t chunk_type)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CHECK(direct_to_ddms_);
+    JDWP::JdwpState* state = Dbg::GetJdwpState();
+    CHECK(state != nullptr);
+    JDWP::JdwpNetStateBase* net_state = state->netState;
+    CHECK(net_state != nullptr);
+
+    // Hold the socket lock for the whole time since we want this to be atomic.
+    MutexLock mu(Thread::Current(), *net_state->GetSocketLock());
+
+    // Prepare the Ddms chunk.
+    constexpr size_t kChunkHeaderSize = kJDWPHeaderLen + 8;
+    uint8_t chunk_header[kChunkHeaderSize] = { 0 };
+    state->SetupChunkHeader(chunk_type, overall_size, kChunkHeaderSize, chunk_header);
+
+    // Prepare the output and send the chunk header.
+    NetStateEndianOutput net_output(net_state, max_length);
+    net_output.AddU1List(chunk_header, kChunkHeaderSize);
+
+    // Write the dump.
+    ProcessHeap(&net_output, true);
+
+    // Check for expected size.
+    CHECK_EQ(net_output.SumLength(), overall_size + kChunkHeaderSize);
+
+    return true;
   }
 
   // If direct_to_ddms_ is set, "filename_" and "fd" will be ignored.
@@ -677,21 +740,9 @@
 
   uint64_t start_ns_;
 
-  HprofRecord current_record_;
-
-  uint32_t gc_thread_serial_number_;
-  uint8_t gc_scan_state_;
   HprofHeapId current_heap_;  // Which heap we're currently dumping.
   size_t objects_in_segment_;
 
-  FILE* header_fp_;
-  char* header_data_ptr_;
-  size_t header_data_size_;
-
-  FILE* body_fp_;
-  char* body_data_ptr_;
-  size_t body_data_size_;
-
   std::set<mirror::Class*> classes_;
   HprofStringId next_string_id_;
   SafeMap<std::string, HprofStringId> strings_;
@@ -699,56 +750,56 @@
   DISALLOW_COPY_AND_ASSIGN(Hprof);
 };
 
-#define OBJECTS_PER_SEGMENT     ((size_t)128)
-#define BYTES_PER_SEGMENT       ((size_t)4096)
-
-// The static field-name for the synthetic object generated to account for class static overhead.
-#define STATIC_OVERHEAD_NAME    "$staticOverhead"
-
-static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut) {
+static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* size_out) {
   char c = sig[0];
   HprofBasicType ret;
   size_t size;
 
   switch (c) {
-  case '[':
-  case 'L': ret = hprof_basic_object;  size = 4; break;
-  case 'Z': ret = hprof_basic_boolean; size = 1; break;
-  case 'C': ret = hprof_basic_char;    size = 2; break;
-  case 'F': ret = hprof_basic_float;   size = 4; break;
-  case 'D': ret = hprof_basic_double;  size = 8; break;
-  case 'B': ret = hprof_basic_byte;    size = 1; break;
-  case 'S': ret = hprof_basic_short;   size = 2; break;
-  default: CHECK(false);
-  case 'I': ret = hprof_basic_int;     size = 4; break;
-  case 'J': ret = hprof_basic_long;    size = 8; break;
+    case '[':
+    case 'L':
+      ret = hprof_basic_object;
+      size = 4;
+      break;
+    case 'Z':
+      ret = hprof_basic_boolean;
+      size = 1;
+      break;
+    case 'C':
+      ret = hprof_basic_char;
+      size = 2;
+      break;
+    case 'F':
+      ret = hprof_basic_float;
+      size = 4;
+      break;
+    case 'D':
+      ret = hprof_basic_double;
+      size = 8;
+      break;
+    case 'B':
+      ret = hprof_basic_byte;
+      size = 1;
+      break;
+    case 'S':
+      ret = hprof_basic_short;
+      size = 2;
+      break;
+    case 'I':
+      ret = hprof_basic_int;
+      size = 4;
+      break;
+    case 'J':
+      ret = hprof_basic_long;
+      size = 8;
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+      UNREACHABLE();
   }
 
-  if (sizeOut != NULL) {
-    *sizeOut = size;
-  }
-
-  return ret;
-}
-
-static HprofBasicType PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t* sizeOut) {
-  HprofBasicType ret;
-  size_t size;
-
-  switch (prim) {
-  case Primitive::kPrimBoolean: ret = hprof_basic_boolean; size = 1; break;
-  case Primitive::kPrimChar:    ret = hprof_basic_char;    size = 2; break;
-  case Primitive::kPrimFloat:   ret = hprof_basic_float;   size = 4; break;
-  case Primitive::kPrimDouble:  ret = hprof_basic_double;  size = 8; break;
-  case Primitive::kPrimByte:    ret = hprof_basic_byte;    size = 1; break;
-  case Primitive::kPrimShort:   ret = hprof_basic_short;   size = 2; break;
-  default: CHECK(false);
-  case Primitive::kPrimInt:     ret = hprof_basic_int;     size = 4; break;
-  case Primitive::kPrimLong:    ret = hprof_basic_long;    size = 8; break;
-  }
-
-  if (sizeOut != NULL) {
-    *sizeOut = size;
+  if (size_out != nullptr) {
+    *size_out = size;
   }
 
   return ret;
@@ -758,95 +809,94 @@
 // something when ctx->gc_scan_state_ is non-zero, which is usually
 // only true when marking the root set or unreachable
 // objects.  Used to add rootset references to obj.
-int Hprof::MarkRootObject(const mirror::Object* obj, jobject jniObj) {
-  HprofRecord* rec = &current_record_;
-  HprofHeapTag heapTag = (HprofHeapTag)gc_scan_state_;
-
-  if (heapTag == 0) {
-    return 0;
+void Hprof::MarkRootObject(const mirror::Object* obj, jobject jni_obj, HprofHeapTag heap_tag,
+                           uint32_t thread_serial, EndianOutput* output) {
+  if (heap_tag == 0) {
+    return;
   }
 
-  if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->Size() >= BYTES_PER_SEGMENT) {
-    StartNewHeapDumpSegment();
-  }
+  CheckHeapSegmentConstraints(output);
 
-  switch (heapTag) {
-  // ID: object ID
-  case HPROF_ROOT_UNKNOWN:
-  case HPROF_ROOT_STICKY_CLASS:
-  case HPROF_ROOT_MONITOR_USED:
-  case HPROF_ROOT_INTERNED_STRING:
-  case HPROF_ROOT_DEBUGGER:
-  case HPROF_ROOT_VM_INTERNAL:
-    rec->AddU1(heapTag);
-    rec->AddObjectId(obj);
-    break;
+  switch (heap_tag) {
+    // ID: object ID
+    case HPROF_ROOT_UNKNOWN:
+    case HPROF_ROOT_STICKY_CLASS:
+    case HPROF_ROOT_MONITOR_USED:
+    case HPROF_ROOT_INTERNED_STRING:
+    case HPROF_ROOT_DEBUGGER:
+    case HPROF_ROOT_VM_INTERNAL:
+      __ AddU1(heap_tag);
+      __ AddObjectId(obj);
+      break;
 
-  // ID: object ID
-  // ID: JNI global ref ID
-  case HPROF_ROOT_JNI_GLOBAL:
-    rec->AddU1(heapTag);
-    rec->AddObjectId(obj);
-    rec->AddJniGlobalRefId(jniObj);
-    break;
+      // ID: object ID
+      // ID: JNI global ref ID
+    case HPROF_ROOT_JNI_GLOBAL:
+      __ AddU1(heap_tag);
+      __ AddObjectId(obj);
+      __ AddJniGlobalRefId(jni_obj);
+      break;
 
-  // ID: object ID
-  // U4: thread serial number
-  // U4: frame number in stack trace (-1 for empty)
-  case HPROF_ROOT_JNI_LOCAL:
-  case HPROF_ROOT_JNI_MONITOR:
-  case HPROF_ROOT_JAVA_FRAME:
-    rec->AddU1(heapTag);
-    rec->AddObjectId(obj);
-    rec->AddU4(gc_thread_serial_number_);
-    rec->AddU4((uint32_t)-1);
-    break;
+      // ID: object ID
+      // U4: thread serial number
+      // U4: frame number in stack trace (-1 for empty)
+    case HPROF_ROOT_JNI_LOCAL:
+    case HPROF_ROOT_JNI_MONITOR:
+    case HPROF_ROOT_JAVA_FRAME:
+      __ AddU1(heap_tag);
+      __ AddObjectId(obj);
+      __ AddU4(thread_serial);
+      __ AddU4((uint32_t)-1);
+      break;
 
-  // ID: object ID
-  // U4: thread serial number
-  case HPROF_ROOT_NATIVE_STACK:
-  case HPROF_ROOT_THREAD_BLOCK:
-    rec->AddU1(heapTag);
-    rec->AddObjectId(obj);
-    rec->AddU4(gc_thread_serial_number_);
-    break;
+      // ID: object ID
+      // U4: thread serial number
+    case HPROF_ROOT_NATIVE_STACK:
+    case HPROF_ROOT_THREAD_BLOCK:
+      __ AddU1(heap_tag);
+      __ AddObjectId(obj);
+      __ AddU4(thread_serial);
+      break;
 
-  // ID: thread object ID
-  // U4: thread serial number
-  // U4: stack trace serial number
-  case HPROF_ROOT_THREAD_OBJECT:
-    rec->AddU1(heapTag);
-    rec->AddObjectId(obj);
-    rec->AddU4(gc_thread_serial_number_);
-    rec->AddU4((uint32_t)-1);    // xxx
-    break;
+      // ID: thread object ID
+      // U4: thread serial number
+      // U4: stack trace serial number
+    case HPROF_ROOT_THREAD_OBJECT:
+      __ AddU1(heap_tag);
+      __ AddObjectId(obj);
+      __ AddU4(thread_serial);
+      __ AddU4((uint32_t)-1);    // xxx
+      break;
 
-  case HPROF_CLASS_DUMP:
-  case HPROF_INSTANCE_DUMP:
-  case HPROF_OBJECT_ARRAY_DUMP:
-  case HPROF_PRIMITIVE_ARRAY_DUMP:
-  case HPROF_HEAP_DUMP_INFO:
-  case HPROF_PRIMITIVE_ARRAY_NODATA_DUMP:
-    // Ignored.
-    break;
+    case HPROF_CLASS_DUMP:
+    case HPROF_INSTANCE_DUMP:
+    case HPROF_OBJECT_ARRAY_DUMP:
+    case HPROF_PRIMITIVE_ARRAY_DUMP:
+    case HPROF_HEAP_DUMP_INFO:
+    case HPROF_PRIMITIVE_ARRAY_NODATA_DUMP:
+      // Ignored.
+      break;
 
-  case HPROF_ROOT_FINALIZING:
-  case HPROF_ROOT_REFERENCE_CLEANUP:
-  case HPROF_UNREACHABLE:
-    LOG(FATAL) << "obsolete tag " << static_cast<int>(heapTag);
-    break;
+    case HPROF_ROOT_FINALIZING:
+    case HPROF_ROOT_REFERENCE_CLEANUP:
+    case HPROF_UNREACHABLE:
+      LOG(FATAL) << "obsolete tag " << static_cast<int>(heap_tag);
+      break;
   }
 
   ++objects_in_segment_;
-  return 0;
 }
 
 static int StackTraceSerialNumber(const mirror::Object* /*obj*/) {
-  return HPROF_NULL_STACK_TRACE;
+  return kHprofNullStackTrace;
 }
 
-int Hprof::DumpHeapObject(mirror::Object* obj) {
-  HprofRecord* rec = &current_record_;
+void Hprof::DumpHeapObject(mirror::Object* obj, EndianOutput* output) {
+  // Ignore classes that are retired.
+  if (obj->IsClass() && obj->AsClass()->IsRetired()) {
+    return;
+  }
+
   gc::space::ContinuousSpace* space =
       Runtime::Current()->GetHeap()->FindContinuousSpaceFromObject(obj, true);
   HprofHeapId heap_type = HPROF_HEAP_APP;
@@ -857,17 +907,15 @@
       heap_type = HPROF_HEAP_IMAGE;
     }
   }
-  if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->Size() >= BYTES_PER_SEGMENT) {
-    StartNewHeapDumpSegment();
-  }
+  CheckHeapSegmentConstraints(output);
 
   if (heap_type != current_heap_) {
     HprofStringId nameId;
 
     // This object is in a different heap than the current one.
     // Emit a HEAP_DUMP_INFO tag to change heaps.
-    rec->AddU1(HPROF_HEAP_DUMP_INFO);
-    rec->AddU4(static_cast<uint32_t>(heap_type));   // uint32_t: heap type
+    __ AddU1(HPROF_HEAP_DUMP_INFO);
+    __ AddU4(static_cast<uint32_t>(heap_type));   // uint32_t: heap type
     switch (heap_type) {
     case HPROF_HEAP_APP:
       nameId = LookupStringId("app");
@@ -884,179 +932,194 @@
       nameId = LookupStringId("<ILLEGAL>");
       break;
     }
-    rec->AddStringId(nameId);
+    __ AddStringId(nameId);
     current_heap_ = heap_type;
   }
 
   mirror::Class* c = obj->GetClass();
-  if (c == NULL) {
+  if (c == nullptr) {
     // This object will bother HprofReader, because it has a NULL
     // class, so just don't dump it. It could be
     // gDvm.unlinkedJavaLangClass or it could be an object just
     // allocated which hasn't been initialized yet.
   } else {
     if (obj->IsClass()) {
-      mirror::Class* thisClass = obj->AsClass();
-      // obj is a ClassObject.
-      size_t sFieldCount = thisClass->NumStaticFields();
-      if (sFieldCount != 0) {
-        int byteLength = sFieldCount * sizeof(JValue);  // TODO bogus; fields are packed
-        // Create a byte array to reflect the allocation of the
-        // StaticField array at the end of this class.
-        rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
-        rec->AddClassStaticsId(thisClass);
-        rec->AddU4(StackTraceSerialNumber(obj));
-        rec->AddU4(byteLength);
-        rec->AddU1(hprof_basic_byte);
-        for (int i = 0; i < byteLength; ++i) {
-          rec->AddU1(0);
-        }
-      }
-
-      rec->AddU1(HPROF_CLASS_DUMP);
-      rec->AddClassId(LookupClassId(thisClass));
-      rec->AddU4(StackTraceSerialNumber(thisClass));
-      rec->AddClassId(LookupClassId(thisClass->GetSuperClass()));
-      rec->AddObjectId(thisClass->GetClassLoader());
-      rec->AddObjectId(nullptr);    // no signer
-      rec->AddObjectId(nullptr);    // no prot domain
-      rec->AddObjectId(nullptr);    // reserved
-      rec->AddObjectId(nullptr);    // reserved
-      if (thisClass->IsClassClass()) {
-        // ClassObjects have their static fields appended, so aren't all the same size.
-        // But they're at least this size.
-        rec->AddU4(sizeof(mirror::Class));  // instance size
-      } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
-        rec->AddU4(0);
-      } else {
-        rec->AddU4(thisClass->GetObjectSize());  // instance size
-      }
-
-      rec->AddU2(0);  // empty const pool
-
-      // Static fields
-      if (sFieldCount == 0) {
-        rec->AddU2((uint16_t)0);
-      } else {
-        rec->AddU2((uint16_t)(sFieldCount+1));
-        rec->AddStringId(LookupStringId(STATIC_OVERHEAD_NAME));
-        rec->AddU1(hprof_basic_object);
-        rec->AddClassStaticsId(thisClass);
-
-        for (size_t i = 0; i < sFieldCount; ++i) {
-          mirror::ArtField* f = thisClass->GetStaticField(i);
-
-          size_t size;
-          HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
-          rec->AddStringId(LookupStringId(f->GetName()));
-          rec->AddU1(t);
-          if (size == 1) {
-            rec->AddU1(static_cast<uint8_t>(f->Get32(thisClass)));
-          } else if (size == 2) {
-            rec->AddU2(static_cast<uint16_t>(f->Get32(thisClass)));
-          } else if (size == 4) {
-            rec->AddU4(f->Get32(thisClass));
-          } else if (size == 8) {
-            rec->AddU8(f->Get64(thisClass));
-          } else {
-            CHECK(false);
-          }
-        }
-      }
-
-      // Instance fields for this class (no superclass fields)
-      int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
-      rec->AddU2((uint16_t)iFieldCount);
-      for (int i = 0; i < iFieldCount; ++i) {
-        mirror::ArtField* f = thisClass->GetInstanceField(i);
-        HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), NULL);
-        rec->AddStringId(LookupStringId(f->GetName()));
-        rec->AddU1(t);
-      }
+      DumpHeapClass(obj->AsClass(), output);
     } else if (c->IsArrayClass()) {
-      mirror::Array* aobj = obj->AsArray();
-      uint32_t length = aobj->GetLength();
-
-      if (obj->IsObjectArray()) {
-        // obj is an object array.
-        rec->AddU1(HPROF_OBJECT_ARRAY_DUMP);
-
-        rec->AddObjectId(obj);
-        rec->AddU4(StackTraceSerialNumber(obj));
-        rec->AddU4(length);
-        rec->AddClassId(LookupClassId(c));
-
-        // Dump the elements, which are always objects or NULL.
-        rec->AddIdList(aobj->AsObjectArray<mirror::Object>());
-      } else {
-        size_t size;
-        HprofBasicType t = PrimitiveToBasicTypeAndSize(c->GetComponentType()->GetPrimitiveType(), &size);
-
-        // obj is a primitive array.
-        rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
-
-        rec->AddObjectId(obj);
-        rec->AddU4(StackTraceSerialNumber(obj));
-        rec->AddU4(length);
-        rec->AddU1(t);
-
-        // Dump the raw, packed element values.
-        if (size == 1) {
-          rec->AddU1List((const uint8_t*)aobj->GetRawData(sizeof(uint8_t), 0), length);
-        } else if (size == 2) {
-          rec->AddU2List((const uint16_t*)aobj->GetRawData(sizeof(uint16_t), 0), length);
-        } else if (size == 4) {
-          rec->AddU4List((const uint32_t*)aobj->GetRawData(sizeof(uint32_t), 0), length);
-        } else if (size == 8) {
-          rec->AddU8List((const uint64_t*)aobj->GetRawData(sizeof(uint64_t), 0), length);
-        }
-      }
+      DumpHeapArray(obj->AsArray(), c, output);
     } else {
-      // obj is an instance object.
-      rec->AddU1(HPROF_INSTANCE_DUMP);
-      rec->AddObjectId(obj);
-      rec->AddU4(StackTraceSerialNumber(obj));
-      rec->AddClassId(LookupClassId(c));
-
-      // Reserve some space for the length of the instance data, which we won't
-      // know until we're done writing it.
-      size_t size_patch_offset = rec->Size();
-      rec->AddU4(0x77777777);
-
-      // Write the instance data;  fields for this class, followed by super class fields,
-      // and so on. Don't write the klass or monitor fields of Object.class.
-      mirror::Class* sclass = c;
-      while (!sclass->IsObjectClass()) {
-        int ifieldCount = sclass->NumInstanceFields();
-        for (int i = 0; i < ifieldCount; ++i) {
-          mirror::ArtField* f = sclass->GetInstanceField(i);
-          size_t size;
-          SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
-          if (size == 1) {
-            rec->AddU1(f->Get32(obj));
-          } else if (size == 2) {
-            rec->AddU2(f->Get32(obj));
-          } else if (size == 4) {
-            rec->AddU4(f->Get32(obj));
-          } else {
-            CHECK_EQ(size, 8U);
-            rec->AddU8(f->Get64(obj));
-          }
-        }
-
-        sclass = sclass->GetSuperClass();
-      }
-
-      // Patch the instance field length.
-      rec->UpdateU4(size_patch_offset, rec->Size() - (size_patch_offset + 4));
+      DumpHeapInstanceObject(obj, c, output);
     }
   }
 
   ++objects_in_segment_;
-  return 0;
 }
 
-void Hprof::VisitRoot(const mirror::Object* obj, uint32_t thread_id, RootType type) {
+void Hprof::DumpHeapClass(mirror::Class* klass, EndianOutput* output) {
+  size_t sFieldCount = klass->NumStaticFields();
+  if (sFieldCount != 0) {
+    int byteLength = sFieldCount * sizeof(JValue);  // TODO bogus; fields are packed
+    // Create a byte array to reflect the allocation of the
+    // StaticField array at the end of this class.
+    __ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
+    __ AddClassStaticsId(klass);
+    __ AddU4(StackTraceSerialNumber(klass));
+    __ AddU4(byteLength);
+    __ AddU1(hprof_basic_byte);
+    for (int i = 0; i < byteLength; ++i) {
+      __ AddU1(0);
+    }
+  }
+
+  __ AddU1(HPROF_CLASS_DUMP);
+  __ AddClassId(LookupClassId(klass));
+  __ AddU4(StackTraceSerialNumber(klass));
+  __ AddClassId(LookupClassId(klass->GetSuperClass()));
+  __ AddObjectId(klass->GetClassLoader());
+  __ AddObjectId(nullptr);    // no signer
+  __ AddObjectId(nullptr);    // no prot domain
+  __ AddObjectId(nullptr);    // reserved
+  __ AddObjectId(nullptr);    // reserved
+  if (klass->IsClassClass()) {
+    // ClassObjects have their static fields appended, so aren't all the same size.
+    // But they're at least this size.
+    __ AddU4(sizeof(mirror::Class));  // instance size
+  } else if (klass->IsArrayClass() || klass->IsPrimitive()) {
+    __ AddU4(0);
+  } else {
+    __ AddU4(klass->GetObjectSize());  // instance size
+  }
+
+  __ AddU2(0);  // empty const pool
+
+  // Static fields
+  if (sFieldCount == 0) {
+    __ AddU2((uint16_t)0);
+  } else {
+    __ AddU2((uint16_t)(sFieldCount+1));
+    __ AddStringId(LookupStringId(kStaticOverheadName));
+    __ AddU1(hprof_basic_object);
+    __ AddClassStaticsId(klass);
+
+    for (size_t i = 0; i < sFieldCount; ++i) {
+      mirror::ArtField* f = klass->GetStaticField(i);
+
+      size_t size;
+      HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+      __ AddStringId(LookupStringId(f->GetName()));
+      __ AddU1(t);
+      switch (size) {
+        case 1:
+          __ AddU1(static_cast<uint8_t>(f->Get32(klass)));
+          break;
+        case 2:
+          __ AddU2(static_cast<uint16_t>(f->Get32(klass)));
+          break;
+        case 4:
+          __ AddU4(f->Get32(klass));
+          break;
+        case 8:
+          __ AddU8(f->Get64(klass));
+          break;
+        default:
+          LOG(FATAL) << "Unexpected size " << size;
+          UNREACHABLE();
+      }
+    }
+  }
+
+  // Instance fields for this class (no superclass fields)
+  int iFieldCount = klass->IsObjectClass() ? 0 : klass->NumInstanceFields();
+  __ AddU2((uint16_t)iFieldCount);
+  for (int i = 0; i < iFieldCount; ++i) {
+    mirror::ArtField* f = klass->GetInstanceField(i);
+    __ AddStringId(LookupStringId(f->GetName()));
+    HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), nullptr);
+    __ AddU1(t);
+  }
+}
+
+void Hprof::DumpHeapArray(mirror::Array* obj, mirror::Class* klass, EndianOutput* output) {
+  uint32_t length = obj->GetLength();
+
+  if (obj->IsObjectArray()) {
+    // obj is an object array.
+    __ AddU1(HPROF_OBJECT_ARRAY_DUMP);
+
+    __ AddObjectId(obj);
+    __ AddU4(StackTraceSerialNumber(obj));
+    __ AddU4(length);
+    __ AddClassId(LookupClassId(klass));
+
+    // Dump the elements, which are always objects or NULL.
+    __ AddIdList(obj->AsObjectArray<mirror::Object>());
+  } else {
+    size_t size;
+    HprofBasicType t = SignatureToBasicTypeAndSize(
+        Primitive::Descriptor(klass->GetComponentType()->GetPrimitiveType()), &size);
+
+    // obj is a primitive array.
+    __ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
+
+    __ AddObjectId(obj);
+    __ AddU4(StackTraceSerialNumber(obj));
+    __ AddU4(length);
+    __ AddU1(t);
+
+    // Dump the raw, packed element values.
+    if (size == 1) {
+      __ AddU1List(reinterpret_cast<const uint8_t*>(obj->GetRawData(sizeof(uint8_t), 0)), length);
+    } else if (size == 2) {
+      __ AddU2List(reinterpret_cast<const uint16_t*>(obj->GetRawData(sizeof(uint16_t), 0)), length);
+    } else if (size == 4) {
+      __ AddU4List(reinterpret_cast<const uint32_t*>(obj->GetRawData(sizeof(uint32_t), 0)), length);
+    } else if (size == 8) {
+      __ AddU8List(reinterpret_cast<const uint64_t*>(obj->GetRawData(sizeof(uint64_t), 0)), length);
+    }
+  }
+}
+
+void Hprof::DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass,
+                                   EndianOutput* output) {
+  // obj is an instance object.
+  __ AddU1(HPROF_INSTANCE_DUMP);
+  __ AddObjectId(obj);
+  __ AddU4(StackTraceSerialNumber(obj));
+  __ AddClassId(LookupClassId(klass));
+
+  // Reserve some space for the length of the instance data, which we won't
+  // know until we're done writing it.
+  size_t size_patch_offset = output->Length();
+  __ AddU4(0x77777777);
+
+  // Write the instance data;  fields for this class, followed by super class fields,
+  // and so on. Don't write the klass or monitor fields of Object.class.
+  while (!klass->IsObjectClass()) {
+    int ifieldCount = klass->NumInstanceFields();
+    for (int i = 0; i < ifieldCount; ++i) {
+      mirror::ArtField* f = klass->GetInstanceField(i);
+      size_t size;
+      SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+      if (size == 1) {
+        __ AddU1(f->Get32(obj));
+      } else if (size == 2) {
+        __ AddU2(f->Get32(obj));
+      } else if (size == 4) {
+        __ AddU4(f->Get32(obj));
+      } else {
+        CHECK_EQ(size, 8U);
+        __ AddU8(f->Get64(obj));
+      }
+    }
+
+    klass = klass->GetSuperClass();
+  }
+
+  // Patch the instance field length.
+  __ UpdateU4(size_patch_offset, output->Length() - (size_patch_offset + 4));
+}
+
+void Hprof::VisitRoot(const mirror::Object* obj, const RootInfo& info, EndianOutput* output) {
   static const HprofHeapTag xlate[] = {
     HPROF_ROOT_UNKNOWN,
     HPROF_ROOT_JNI_GLOBAL,
@@ -1074,15 +1137,11 @@
     HPROF_ROOT_VM_INTERNAL,
     HPROF_ROOT_JNI_MONITOR,
   };
-  CHECK_LT(type, sizeof(xlate) / sizeof(HprofHeapTag));
-  if (obj == NULL) {
+  CHECK_LT(info.GetType(), sizeof(xlate) / sizeof(HprofHeapTag));
+  if (obj == nullptr) {
     return;
   }
-  gc_scan_state_ = xlate[type];
-  gc_thread_serial_number_ = thread_id;
-  MarkRootObject(obj, 0);
-  gc_scan_state_ = 0;
-  gc_thread_serial_number_ = 0;
+  MarkRootObject(obj, 0, xlate[info.GetType()], info.GetThreadId(), output);
 }
 
 // If "direct_to_ddms" is true, the other arguments are ignored, and data is
@@ -1090,7 +1149,7 @@
 // If "fd" is >= 0, the output will be written to that file descriptor.
 // Otherwise, "filename" is used to create an output file.
 void DumpHeap(const char* filename, int fd, bool direct_to_ddms) {
-  CHECK(filename != NULL);
+  CHECK(filename != nullptr);
 
   Runtime::Current()->GetThreadList()->SuspendAll();
   Hprof hprof(filename, fd, direct_to_ddms);
@@ -1099,5 +1158,4 @@
 }
 
 }  // namespace hprof
-
 }  // namespace art
diff --git a/runtime/image.cc b/runtime/image.cc
index 478b486..b83eeb1 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -23,8 +23,8 @@
 
 namespace art {
 
-const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '9', '\0' };
+const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '3', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
@@ -35,7 +35,8 @@
                          uint32_t oat_file_begin,
                          uint32_t oat_data_begin,
                          uint32_t oat_data_end,
-                         uint32_t oat_file_end)
+                         uint32_t oat_file_end,
+                         bool compile_pic)
   : image_begin_(image_begin),
     image_size_(image_size),
     image_bitmap_offset_(image_bitmap_offset),
@@ -46,7 +47,8 @@
     oat_data_end_(oat_data_end),
     oat_file_end_(oat_file_end),
     patch_delta_(0),
-    image_roots_(image_roots) {
+    image_roots_(image_roots),
+    compile_pic_(compile_pic) {
   CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
   CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
   CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
diff --git a/runtime/image.h b/runtime/image.h
index 424a40b..7e2b847 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -28,7 +28,7 @@
 // header of image files written by ImageWriter, read and validated by Space.
 class PACKED(4) ImageHeader {
  public:
-  ImageHeader() {}
+  ImageHeader() : compile_pic_(0) {}
 
   ImageHeader(uint32_t image_begin,
               uint32_t image_size_,
@@ -39,13 +39,14 @@
               uint32_t oat_file_begin,
               uint32_t oat_data_begin,
               uint32_t oat_data_end,
-              uint32_t oat_file_end);
+              uint32_t oat_file_end,
+              bool compile_pic_);
 
   bool IsValid() const;
   const char* GetMagic() const;
 
-  byte* GetImageBegin() const {
-    return reinterpret_cast<byte*>(image_begin_);
+  uint8_t* GetImageBegin() const {
+    return reinterpret_cast<uint8_t*>(image_begin_);
   }
 
   size_t GetImageSize() const {
@@ -68,20 +69,20 @@
     oat_checksum_ = oat_checksum;
   }
 
-  byte* GetOatFileBegin() const {
-    return reinterpret_cast<byte*>(oat_file_begin_);
+  uint8_t* GetOatFileBegin() const {
+    return reinterpret_cast<uint8_t*>(oat_file_begin_);
   }
 
-  byte* GetOatDataBegin() const {
-    return reinterpret_cast<byte*>(oat_data_begin_);
+  uint8_t* GetOatDataBegin() const {
+    return reinterpret_cast<uint8_t*>(oat_data_begin_);
   }
 
-  byte* GetOatDataEnd() const {
-    return reinterpret_cast<byte*>(oat_data_end_);
+  uint8_t* GetOatDataEnd() const {
+    return reinterpret_cast<uint8_t*>(oat_data_end_);
   }
 
-  byte* GetOatFileEnd() const {
-    return reinterpret_cast<byte*>(oat_file_end_);
+  uint8_t* GetOatFileEnd() const {
+    return reinterpret_cast<uint8_t*>(oat_file_end_);
   }
 
   off_t GetPatchDelta() const {
@@ -105,6 +106,7 @@
   enum ImageRoot {
     kResolutionMethod,
     kImtConflictMethod,
+    kImtUnimplementedMethod,
     kDefaultImt,
     kCalleeSaveMethod,
     kRefsOnlySaveMethod,
@@ -120,12 +122,16 @@
 
   void RelocateImage(off_t delta);
 
- private:
-  static const byte kImageMagic[4];
-  static const byte kImageVersion[4];
+  bool CompilePic() const {
+    return compile_pic_ != 0;
+  }
 
-  byte magic_[4];
-  byte version_[4];
+ private:
+  static const uint8_t kImageMagic[4];
+  static const uint8_t kImageVersion[4];
+
+  uint8_t magic_[4];
+  uint8_t version_[4];
 
   // Required base address for mapping the image.
   uint32_t image_begin_;
@@ -161,6 +167,9 @@
   // Absolute address of an Object[] of objects needed to reinitialize from an image.
   uint32_t image_roots_;
 
+  // Boolean (0 or 1) to denote if the image was compiled with --compile-pic option
+  const uint32_t compile_pic_;
+
   friend class ImageWriter;
 };
 
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 7e770f6..e571a0e 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -77,7 +77,7 @@
     return nullptr;
   }
   uint32_t idx = ExtractIndex(iref);
-  mirror::Object* obj = table_[idx].GetReference()->Read<kWithoutReadBarrier>();
+  mirror::Object* obj = table_[idx].GetReference()->Read<kReadBarrierOption>();
   VerifyObject(obj);
   return obj;
 }
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index c1455fd..aa2a6b5 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;
   }
@@ -162,13 +162,12 @@
   DCHECK(table_ != NULL);
   DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);
 
-  int idx = ExtractIndex(iref);
-
   if (GetIndirectRefKind(iref) == kHandleScopeOrInvalid &&
       Thread::Current()->HandleScopeContains(reinterpret_cast<jobject>(iref))) {
     LOG(WARNING) << "Attempt to remove local handle scope entry from IRT, ignoring";
     return true;
   }
+  const int idx = ExtractIndex(iref);
   if (idx < bottomIndex) {
     // Wrong segment.
     LOG(WARNING) << "Attempt to remove index outside index area (" << idx
@@ -193,7 +192,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 +200,7 @@
         if (!table_[topIndex - 1].GetReference()->IsNull()) {
           break;
         }
-        if (false) {
+        if ((false)) {
           LOG(INFO) << "+++ ate hole at " << (topIndex - 1);
         }
         numHoles--;
@@ -210,7 +209,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 +227,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;
     }
   }
@@ -236,15 +235,22 @@
   return true;
 }
 
-void IndirectReferenceTable::VisitRoots(RootCallback* callback, void* arg, uint32_t tid,
-                                        RootType root_type) {
+void IndirectReferenceTable::Trim() {
+  const size_t top_index = Capacity();
+  auto* release_start = AlignUp(reinterpret_cast<uint8_t*>(&table_[top_index]), kPageSize);
+  uint8_t* release_end = table_mem_map_->End();
+  madvise(release_start, release_end - release_start, MADV_DONTNEED);
+}
+
+void IndirectReferenceTable::VisitRoots(RootCallback* callback, void* arg,
+                                        const RootInfo& root_info) {
   for (auto ref : *this) {
     if (*ref == nullptr) {
       // Need to skip null entries to make it possible to do the
       // non-null check after the call back.
       continue;
     }
-    callback(ref, arg, tid, root_type);
+    callback(ref, arg, root_info);
     DCHECK(*ref != nullptr);
   }
 }
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 168f9f2..7f7870a 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -31,6 +31,8 @@
 
 namespace art {
 
+class RootInfo;
+
 namespace mirror {
 class Object;
 }  // namespace mirror
@@ -316,7 +318,7 @@
     return IrtIterator(table_, Capacity(), Capacity());
   }
 
-  void VisitRoots(RootCallback* callback, void* arg, uint32_t tid, RootType root_type)
+  void VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint32_t GetSegmentState() const {
@@ -331,6 +333,9 @@
     return Offset(OFFSETOF_MEMBER(IndirectReferenceTable, segment_state_));
   }
 
+  // Release pages past the end of the table that may have previously held references.
+  void Trim() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   // Extract the table index from an indirect reference.
   static uint32_t ExtractIndex(IndirectRef iref) {
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 99ee597..1156cf5 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -43,6 +43,9 @@
 }
 
 TEST_F(IndirectReferenceTableTest, BasicTest) {
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   ScopedObjectAccess soa(Thread::Current());
   static const size_t kTableInitial = 10;
   static const size_t kTableMax = 20;
diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc
deleted file mode 100644
index 644e055..0000000
--- a/runtime/instruction_set.cc
+++ /dev/null
@@ -1,131 +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 "instruction_set.h"
-
-namespace art {
-
-const char* GetInstructionSetString(const InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      return "arm";
-    case kArm64:
-      return "arm64";
-    case kX86:
-      return "x86";
-    case kX86_64:
-      return "x86_64";
-    case kMips:
-      return "mips";
-    case kNone:
-      return "none";
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return nullptr;
-  }
-}
-
-InstructionSet GetInstructionSetFromString(const char* isa_str) {
-  CHECK(isa_str != nullptr);
-
-  if (strcmp("arm", isa_str) == 0) {
-    return kArm;
-  } else if (strcmp("arm64", isa_str) == 0) {
-    return kArm64;
-  } else if (strcmp("x86", isa_str) == 0) {
-    return kX86;
-  } else if (strcmp("x86_64", isa_str) == 0) {
-    return kX86_64;
-  } else if (strcmp("mips", isa_str) == 0) {
-    return kMips;
-  }
-
-  return kNone;
-}
-
-size_t GetInstructionSetAlignment(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return kArmAlignment;
-    case kArm64:
-      return kArm64Alignment;
-    case kX86:
-      // Fall-through.
-    case kX86_64:
-      return kX86Alignment;
-    case kMips:
-      return kMipsAlignment;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have alignment.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-
-static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
-static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
-
-static constexpr size_t kArmStackOverflowReservedBytes =    8 * KB;
-static constexpr size_t kArm64StackOverflowReservedBytes =  8 * KB;
-static constexpr size_t kX86StackOverflowReservedBytes =    8 * KB;
-static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB;
-
-size_t GetStackOverflowReservedBytes(InstructionSet isa) {
-  switch (isa) {
-    case kArm:      // Intentional fall-through.
-    case kThumb2:
-      return kArmStackOverflowReservedBytes;
-
-    case kArm64:
-      return kArm64StackOverflowReservedBytes;
-
-    case kMips:
-      return kMipsStackOverflowReservedBytes;
-
-    case kX86:
-      return kX86StackOverflowReservedBytes;
-
-    case kX86_64:
-      return kX86_64StackOverflowReservedBytes;
-
-    case kNone:
-      LOG(FATAL) << "kNone has no stack overflow size";
-      return 0;
-
-    default:
-      LOG(FATAL) << "Unknown instruction set" << isa;
-      return 0;
-  }
-}
-
-std::string InstructionSetFeatures::GetFeatureString() const {
-  std::string result;
-  if ((mask_ & kHwDiv) != 0) {
-    result += "div";
-  }
-  if (result.size() == 0) {
-    result = "none";
-  }
-  return result;
-}
-
-}  // namespace art
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
deleted file mode 100644
index de6d0f4..0000000
--- a/runtime/instruction_set.h
+++ /dev/null
@@ -1,293 +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.
- */
-
-#ifndef ART_RUNTIME_INSTRUCTION_SET_H_
-#define ART_RUNTIME_INSTRUCTION_SET_H_
-
-#include <iosfwd>
-#include <string>
-
-#include "base/logging.h"  // Logging is required for FATAL in the helper functions.
-#include "base/macros.h"
-#include "globals.h"       // For KB.
-
-namespace art {
-
-enum InstructionSet {
-  kNone,
-  kArm,
-  kArm64,
-  kThumb2,
-  kX86,
-  kX86_64,
-  kMips,
-  kMips64
-};
-std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
-
-#if defined(__arm__)
-static constexpr InstructionSet kRuntimeISA = kArm;
-#elif defined(__aarch64__)
-static constexpr InstructionSet kRuntimeISA = kArm64;
-#elif defined(__mips__)
-static constexpr InstructionSet kRuntimeISA = kMips;
-#elif defined(__i386__)
-static constexpr InstructionSet kRuntimeISA = kX86;
-#elif defined(__x86_64__)
-static constexpr InstructionSet kRuntimeISA = kX86_64;
-#else
-static constexpr InstructionSet kRuntimeISA = kNone;
-#endif
-
-// Architecture-specific pointer sizes
-static constexpr size_t kArmPointerSize = 4;
-static constexpr size_t kArm64PointerSize = 8;
-static constexpr size_t kMipsPointerSize = 4;
-static constexpr size_t kMips64PointerSize = 8;
-static constexpr size_t kX86PointerSize = 4;
-static constexpr size_t kX86_64PointerSize = 8;
-
-// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
-// but ARM ELF requires 8..
-static constexpr size_t kArmAlignment = 8;
-
-// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
-static constexpr size_t kArm64Alignment = 16;
-
-// MIPS instruction alignment.  MIPS processors require code to be 4-byte aligned.
-// TODO: Can this be 4?
-static constexpr size_t kMipsAlignment = 8;
-
-// X86 instruction alignment. This is the recommended alignment for maximum performance.
-static constexpr size_t kX86Alignment = 16;
-
-
-const char* GetInstructionSetString(InstructionSet isa);
-
-// Note: Returns kNone when the string cannot be parsed to a known value.
-InstructionSet GetInstructionSetFromString(const char* instruction_set);
-
-static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return kArmPointerSize;
-    case kArm64:
-      return kArm64PointerSize;
-    case kX86:
-      return kX86PointerSize;
-    case kX86_64:
-      return kX86_64PointerSize;
-    case kMips:
-      return kMipsPointerSize;
-    case kMips64:
-      return kMips64PointerSize;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have pointer size.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-size_t GetInstructionSetAlignment(InstructionSet isa);
-
-static inline bool Is64BitInstructionSet(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-    case kX86:
-    case kMips:
-      return false;
-
-    case kArm64:
-    case kX86_64:
-    case kMips64:
-      return true;
-
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have bit width.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return 4;
-    case kArm64:
-      return 8;
-    case kX86:
-      return 4;
-    case kX86_64:
-      return 8;
-    case kMips:
-      return 4;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have spills.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return 4;
-    case kArm64:
-      return 8;
-    case kX86:
-      return 8;
-    case kX86_64:
-      return 8;
-    case kMips:
-      return 4;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have spills.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-size_t GetStackOverflowReservedBytes(InstructionSet isa);
-
-enum InstructionFeatures {
-  kHwDiv  = 0x1,              // Supports hardware divide.
-  kHwLpae = 0x2,              // Supports Large Physical Address Extension.
-};
-
-// This is a bitmask of supported features per architecture.
-class PACKED(4) InstructionSetFeatures {
- public:
-  InstructionSetFeatures() : mask_(0) {}
-  explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
-
-  static InstructionSetFeatures GuessInstructionSetFeatures();
-
-  bool HasDivideInstruction() const {
-      return (mask_ & kHwDiv) != 0;
-  }
-
-  void SetHasDivideInstruction(bool v) {
-    mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
-  }
-
-  bool HasLpae() const {
-    return (mask_ & kHwLpae) != 0;
-  }
-
-  void SetHasLpae(bool v) {
-    mask_ = (mask_ & ~kHwLpae) | (v ? kHwLpae : 0);
-  }
-
-  std::string GetFeatureString() const;
-
-  // Other features in here.
-
-  bool operator==(const InstructionSetFeatures &peer) const {
-    return mask_ == peer.mask_;
-  }
-
-  bool operator!=(const InstructionSetFeatures &peer) const {
-    return mask_ != peer.mask_;
-  }
-
-  bool operator<=(const InstructionSetFeatures &peer) const {
-    return (mask_ & peer.mask_) == mask_;
-  }
-
- private:
-  uint32_t mask_;
-};
-
-// The following definitions create return types for two word-sized entities that will be passed
-// in registers so that memory operations for the interface trampolines can be avoided. The entities
-// are the resolved method and the pointer to the code to be invoked.
-//
-// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
-// uint64_t or long long int.
-//
-// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
-// size_t-sized values.
-//
-// We need two operations:
-//
-// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
-//    GetTwoWordFailureValue() will return a value that has lower part == 0.
-//
-// 2) A value that combines two word-sized values.
-//    GetTwoWordSuccessValue() constructs this.
-//
-// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
-//            that the object does not move or the value is updated. Simple use of this is NOT SAFE
-//            when the garbage collector can move objects concurrently. Ensure that required locks
-//            are held when using!
-
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
-typedef uint64_t TwoWordReturn;
-
-// Encodes method_ptr==nullptr and code_ptr==nullptr
-static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
-  return 0;
-}
-
-// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
-static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
-  uint32_t lo32 = static_cast<uint32_t>(lo);
-  uint64_t hi64 = static_cast<uint64_t>(hi);
-  return ((hi64 << 32) | lo32);
-}
-
-#elif defined(__x86_64__) || defined(__aarch64__)
-struct TwoWordReturn {
-  uintptr_t lo;
-  uintptr_t hi;
-};
-
-// Encodes method_ptr==nullptr. Leaves random value in code pointer.
-static inline TwoWordReturn GetTwoWordFailureValue() {
-  TwoWordReturn ret;
-  ret.lo = 0;
-  return ret;
-}
-
-// Write values into their respective members.
-static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
-  TwoWordReturn ret;
-  ret.lo = lo;
-  ret.hi = hi;
-  return ret;
-}
-#else
-#error "Unsupported architecture"
-#endif
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_INSTRUCTION_SET_H_
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
deleted file mode 100644
index ac17c4f..0000000
--- a/runtime/instruction_set_test.cc
+++ /dev/null
@@ -1,53 +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.
- */
-
-#include "instruction_set.h"
-
-#include "common_runtime_test.h"
-
-namespace art {
-
-class InstructionSetTest : public CommonRuntimeTest {};
-
-TEST_F(InstructionSetTest, GetInstructionSetFromString) {
-  EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
-  EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
-  EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
-  EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
-  EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
-  EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
-  EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
-}
-
-TEST_F(InstructionSetTest, GetInstructionSetString) {
-  EXPECT_STREQ("arm", GetInstructionSetString(kArm));
-  EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
-  EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
-  EXPECT_STREQ("x86", GetInstructionSetString(kX86));
-  EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
-  EXPECT_STREQ("mips", GetInstructionSetString(kMips));
-  EXPECT_STREQ("none", GetInstructionSetString(kNone));
-}
-
-TEST_F(InstructionSetTest, TestRoundTrip) {
-  EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
-}
-
-TEST_F(InstructionSetTest, PointerSize) {
-  EXPECT_EQ(kPointerSize, GetInstructionSetPointerSize(kRuntimeISA));
-}
-
-}  // namespace art
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 15be6b7..14834dd 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"
@@ -53,7 +54,7 @@
 static constexpr bool kDeoptimizeForAccurateMethodEntryExitListeners = true;
 
 static bool InstallStubsClassVisitor(mirror::Class* klass, void* arg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
   return instrumentation->InstallStubsForClass(klass);
 }
@@ -73,43 +74,34 @@
 }
 
 bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
-  for (size_t i = 0, e = klass->NumDirectMethods(); i < e; i++) {
-    InstallStubsForMethod(klass->GetDirectMethod(i));
-  }
-  for (size_t i = 0, e = klass->NumVirtualMethods(); i < e; i++) {
-    InstallStubsForMethod(klass->GetVirtualMethod(i));
+  if (klass->IsErroneous()) {
+    // We can't execute code in a erroneous class: do nothing.
+  } else if (!klass->IsResolved()) {
+    // We need the class to be resolved to install/uninstall stubs. Otherwise its methods
+    // could not be initialized or linked with regards to class inheritance.
+  } else {
+    for (size_t i = 0, e = klass->NumDirectMethods(); i < e; i++) {
+      InstallStubsForMethod(klass->GetDirectMethod(i));
+    }
+    for (size_t i = 0, e = klass->NumVirtualMethods(); i < e; i++) {
+      InstallStubsForMethod(klass->GetVirtualMethod(i));
+    }
   }
   return true;
 }
 
-static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code,
-                              const void* portable_code, bool have_portable_code)
+static void UpdateEntrypoints(mirror::ArtMethod* method, const void* quick_code)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  method->SetEntryPointFromPortableCompiledCode(portable_code);
   method->SetEntryPointFromQuickCompiledCode(quick_code);
-  bool portable_enabled = method->IsPortableCompiled();
-  if (have_portable_code && !portable_enabled) {
-    method->SetIsPortableCompiled();
-  } else if (portable_enabled) {
-    method->ClearIsPortableCompiled();
-  }
   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 (kIsDebugBuild) {
-        if (quick_code == GetQuickToInterpreterBridge()) {
-          DCHECK(portable_code == GetPortableToInterpreterBridge());
-        } else if (quick_code == class_linker->GetQuickResolutionTrampoline()) {
-          DCHECK(portable_code == class_linker->GetPortableResolutionTrampoline());
-        }
-      }
+    if (class_linker->IsQuickToInterpreterBridge(quick_code) ||
+        (class_linker->IsQuickResolutionStub(quick_code) &&
+         Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
+         !method->IsNative() && !method->IsProxyMethod())) {
       DCHECK(!method->IsNative()) << PrettyMethod(method);
       DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
-      method->SetEntryPointFromInterpreter(art::interpreter::artInterpreterToInterpreterBridge);
+      method->SetEntryPointFromInterpreter(art::artInterpreterToInterpreterBridge);
     } else {
       method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
     }
@@ -126,27 +118,21 @@
       method->GetDeclaringClass()->DescriptorEquals("Ljava/lang/reflect/Proxy;")) {
     return;
   }
-  const void* new_portable_code;
   const void* new_quick_code;
   bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   bool is_class_initialized = method->GetDeclaringClass()->IsInitialized();
-  bool have_portable_code = false;
   if (uninstall) {
     if ((forced_interpret_only_ || IsDeoptimized(method)) && !method->IsNative()) {
-      new_portable_code = GetPortableToInterpreterBridge();
       new_quick_code = GetQuickToInterpreterBridge();
     } else if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
-      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_quick_code = GetQuickResolutionStub();
     }
   } else {  // !uninstall
     if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) &&
         !method->IsNative()) {
-      new_portable_code = GetPortableToInterpreterBridge();
       new_quick_code = GetQuickToInterpreterBridge();
     } else {
       // Do not overwrite resolution trampoline. When the trampoline initializes the method's
@@ -154,20 +140,17 @@
       // For more details, see ClassLinker::FixupStaticTrampolines.
       if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
         if (entry_exit_stubs_installed_) {
-          new_portable_code = GetPortableToInterpreterBridge();
           new_quick_code = GetQuickInstrumentationEntryPoint();
         } 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_quick_code = GetQuickResolutionStub();
       }
     }
   }
-  UpdateEntrypoints(method, new_quick_code, new_portable_code, have_portable_code);
+  UpdateEntrypoints(method, new_quick_code);
 }
 
 // Places the instrumentation exit pc as the return PC for every quick frame. This also allows
@@ -177,8 +160,9 @@
 static void InstrumentationInstallStack(Thread* thread, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   struct InstallStackVisitor : public StackVisitor {
-    InstallStackVisitor(Thread* thread, Context* context, uintptr_t instrumentation_exit_pc)
-        : StackVisitor(thread, context),  instrumentation_stack_(thread->GetInstrumentationStack()),
+    InstallStackVisitor(Thread* thread_in, Context* context, uintptr_t instrumentation_exit_pc)
+        : StackVisitor(thread_in, context),
+          instrumentation_stack_(thread_in->GetInstrumentationStack()),
           instrumentation_exit_pc_(instrumentation_exit_pc),
           reached_existing_instrumentation_frames_(false), instrumentation_stack_depth_(0),
           last_return_pc_(0) {
@@ -194,7 +178,7 @@
         return true;  // Ignore upcalls.
       }
       if (GetCurrentQuickFrame() == NULL) {
-        bool interpreter_frame = !m->IsPortableCompiled();
+        bool interpreter_frame = true;
         InstrumentationStackFrame instrumentation_frame(GetThisObject(), m, 0, GetFrameId(),
                                                         interpreter_frame);
         if (kVerboseInstrumentation) {
@@ -287,7 +271,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());
@@ -316,12 +300,12 @@
 static void InstrumentationRestoreStack(Thread* thread, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   struct RestoreStackVisitor : public StackVisitor {
-    RestoreStackVisitor(Thread* thread, uintptr_t instrumentation_exit_pc,
+    RestoreStackVisitor(Thread* thread_in, uintptr_t instrumentation_exit_pc,
                         Instrumentation* instrumentation)
-        : StackVisitor(thread, NULL), thread_(thread),
+        : StackVisitor(thread_in, NULL), thread_(thread_in),
           instrumentation_exit_pc_(instrumentation_exit_pc),
           instrumentation_(instrumentation),
-          instrumentation_stack_(thread->GetInstrumentationStack()),
+          instrumentation_stack_(thread_in->GetInstrumentationStack()),
           frames_removed_(0) {}
 
     virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -388,7 +372,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());
@@ -563,6 +548,7 @@
   }
   Thread* const self = Thread::Current();
   Runtime* runtime = Runtime::Current();
+  Locks::mutator_lock_->AssertExclusiveHeld(self);
   Locks::thread_list_lock_->AssertNotHeld(self);
   if (desired_level > 0) {
     if (require_interpreter) {
@@ -594,6 +580,7 @@
 }
 
 static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
+  UNUSED(arg);
   thread->ResetQuickAllocEntryPointsForThread();
 }
 
@@ -632,7 +619,6 @@
     SetEntrypointsInstrumented(true);
   }
   ++quick_alloc_entry_points_instrumentation_counter_;
-  LOG(INFO) << "Counter: " << quick_alloc_entry_points_instrumentation_counter_;
 }
 
 void Instrumentation::UninstrumentQuickAllocEntryPointsLocked() {
@@ -642,7 +628,6 @@
   if (quick_alloc_entry_points_instrumentation_counter_ == 0) {
     SetEntrypointsInstrumented(false);
   }
-  LOG(INFO) << "Counter: " << quick_alloc_entry_points_instrumentation_counter_;
 }
 
 void Instrumentation::ResetQuickAllocEntryPoints() {
@@ -653,42 +638,27 @@
   }
 }
 
-void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code,
-                                        const void* portable_code, bool have_portable_code) {
-  const void* new_portable_code;
+void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code) {
+  DCHECK(method->GetDeclaringClass()->IsResolved());
   const void* new_quick_code;
-  bool new_have_portable_code;
   if (LIKELY(!instrumentation_stubs_installed_)) {
-    new_portable_code = portable_code;
     new_quick_code = quick_code;
-    new_have_portable_code = have_portable_code;
   } else {
     if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) {
-      new_portable_code = GetPortableToInterpreterBridge();
       new_quick_code = GetQuickToInterpreterBridge();
-      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()));
-        new_portable_code = portable_code;
+      if (class_linker->IsQuickResolutionStub(quick_code) ||
+          class_linker->IsQuickToInterpreterBridge(quick_code)) {
         new_quick_code = quick_code;
-        new_have_portable_code = have_portable_code;
       } else if (entry_exit_stubs_installed_) {
         new_quick_code = GetQuickInstrumentationEntryPoint();
-        new_portable_code = GetPortableToInterpreterBridge();
-        new_have_portable_code = false;
       } else {
-        new_portable_code = portable_code;
         new_quick_code = quick_code;
-        new_have_portable_code = have_portable_code;
       }
     }
   }
-  UpdateEntrypoints(method, new_quick_code, new_portable_code, new_have_portable_code);
+  UpdateEntrypoints(method, new_quick_code);
 }
 
 bool Instrumentation::AddDeoptimizedMethod(mirror::ArtMethod* method) {
@@ -761,8 +731,7 @@
         << " is already deoptimized";
   }
   if (!interpreter_stubs_installed_) {
-    UpdateEntrypoints(method, GetQuickInstrumentationEntryPoint(), GetPortableToInterpreterBridge(),
-                      false);
+    UpdateEntrypoints(method, GetQuickInstrumentationEntryPoint());
 
     // Install instrumentation exit stub and instrumentation frames. We may already have installed
     // these previously so it will only cover the newly created frames.
@@ -793,14 +762,10 @@
     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());
     } else {
-      bool have_portable_code = false;
       const void* quick_code = class_linker->GetQuickOatCodeFor(method);
-      const void* portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
-      UpdateEntrypoints(method, quick_code, portable_code, have_portable_code);
+      UpdateEntrypoints(method, quick_code);
     }
 
     // If there is no deoptimized method left, we can restore the stack of each thread.
@@ -871,15 +836,16 @@
   ConfigureStubs(false, false);
 }
 
-const void* Instrumentation::GetQuickCodeFor(mirror::ArtMethod* method) const {
+const void* Instrumentation::GetQuickCodeFor(mirror::ArtMethod* method, size_t pointer_size) const {
   Runtime* runtime = Runtime::Current();
   if (LIKELY(!instrumentation_stubs_installed_)) {
-    const void* code = method->GetEntryPointFromQuickCompiledCode();
+    const void* code = method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
     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 +983,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;
@@ -1095,7 +1062,7 @@
     return;
   }
   for (auto pair : deoptimized_methods_) {
-    pair.second.VisitRoot(callback, arg, 0, kRootVMInternal);
+    pair.second.VisitRoot(callback, arg, RootInfo(kRootVMInternal));
   }
 }
 
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 3017bf6..2af9a73 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -21,8 +21,8 @@
 #include <list>
 #include <map>
 
+#include "arch/instruction_set.h"
 #include "atomic.h"
-#include "instruction_set.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "gc_root.h"
@@ -103,13 +103,13 @@
 class Instrumentation {
  public:
   enum InstrumentationEvent {
-    kMethodEntered =   1 << 0,
-    kMethodExited =    1 << 1,
-    kMethodUnwind =    1 << 2,
-    kDexPcMoved =      1 << 3,
-    kFieldRead =       1 << 4,
-    kFieldWritten =    1 << 5,
-    kExceptionCaught = 1 << 6,
+    kMethodEntered   = 1,  // 1 << 0
+    kMethodExited    = 2,  // 1 << 1
+    kMethodUnwind    = 4,  // 1 << 2
+    kDexPcMoved      = 8,  // 1 << 3
+    kFieldRead       = 16,  // 1 << 4,
+    kFieldWritten    = 32,  // 1 << 5
+    kExceptionCaught = 64,  // 1 << 6
   };
 
   Instrumentation();
@@ -193,14 +193,13 @@
   void ResetQuickAllocEntryPoints() EXCLUSIVE_LOCKS_REQUIRED(Locks::runtime_shutdown_lock_);
 
   // Update the code of a method respecting any installed stubs.
-  void UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code,
-                         const void* portable_code, bool have_portable_code)
+  void UpdateMethodsCode(mirror::ArtMethod* method, const void* quick_code)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get the quick code for the given method. More efficient than asking the class linker as it
   // will short-cut to GetCode if instrumentation and static method resolution stubs aren't
   // installed.
-  const void* GetQuickCodeFor(mirror::ArtMethod* method) const
+  const void* GetQuickCodeFor(mirror::ArtMethod* method, size_t pointer_size) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void ForceInterpretOnly() {
@@ -217,10 +216,6 @@
     return forced_interpret_only_;
   }
 
-  bool ShouldPortableCodeDeoptimize() const {
-    return instrumentation_stubs_installed_;
-  }
-
   bool AreExitStubsInstalled() const {
     return instrumentation_stubs_installed_;
   }
@@ -464,6 +459,7 @@
 
   DISALLOW_COPY_AND_ASSIGN(Instrumentation);
 };
+std::ostream& operator<<(std::ostream& os, const Instrumentation::InstrumentationEvent& rhs);
 
 // An element in the instrumentation side stack maintained in art::Thread.
 struct InstrumentationStackFrame {
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index f6e6661..f92f209 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -29,56 +29,48 @@
 namespace art {
 
 InternTable::InternTable()
-    : log_new_roots_(false), allow_new_interns_(true),
+    : image_added_to_intern_table_(false), log_new_roots_(false),
+      allow_new_interns_(true),
       new_intern_condition_("New intern condition", *Locks::intern_table_lock_) {
 }
 
 size_t InternTable::Size() const {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  return strong_interns_.size() + weak_interns_.size();
+  return strong_interns_.Size() + weak_interns_.Size();
 }
 
 size_t InternTable::StrongSize() const {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  return strong_interns_.size();
+  return strong_interns_.Size();
 }
 
 size_t InternTable::WeakSize() const {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  return weak_interns_.size();
+  return weak_interns_.Size();
 }
 
 void InternTable::DumpForSigQuit(std::ostream& os) const {
-  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  os << "Intern table: " << strong_interns_.size() << " strong; "
-     << weak_interns_.size() << " weak\n";
+  os << "Intern table: " << StrongSize() << " strong; " << WeakSize() << " weak\n";
 }
 
 void InternTable::VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags) {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   if ((flags & kVisitRootFlagAllRoots) != 0) {
-    for (auto& strong_intern : strong_interns_) {
-      const_cast<GcRoot<mirror::String>&>(strong_intern).
-          VisitRoot(callback, arg, 0, kRootInternedString);
-      DCHECK(!strong_intern.IsNull());
-    }
+    strong_interns_.VisitRoots(callback, arg);
   } else if ((flags & kVisitRootFlagNewRoots) != 0) {
     for (auto& root : new_strong_intern_roots_) {
       mirror::String* old_ref = root.Read<kWithoutReadBarrier>();
-      root.VisitRoot(callback, arg, 0, kRootInternedString);
+      root.VisitRoot(callback, arg, RootInfo(kRootInternedString));
       mirror::String* new_ref = root.Read<kWithoutReadBarrier>();
-      if (UNLIKELY(new_ref != old_ref)) {
+      if (new_ref != old_ref) {
         // The GC moved a root in the log. Need to search the strong interns and update the
         // corresponding object. This is slow, but luckily for us, this may only happen with a
         // concurrent moving GC.
-        auto it = strong_interns_.find(GcRoot<mirror::String>(old_ref));
-        DCHECK(it != strong_interns_.end());
-        strong_interns_.erase(it);
-        strong_interns_.insert(GcRoot<mirror::String>(new_ref));
+        strong_interns_.Remove(old_ref);
+        strong_interns_.Insert(new_ref);
       }
     }
   }
-
   if ((flags & kVisitRootFlagClearRootLog) != 0) {
     new_strong_intern_roots_.clear();
   }
@@ -91,21 +83,17 @@
 }
 
 mirror::String* InternTable::LookupStrong(mirror::String* s) {
-  return Lookup(&strong_interns_, s);
+  return strong_interns_.Find(s);
 }
 
 mirror::String* InternTable::LookupWeak(mirror::String* s) {
-  // Weak interns need a read barrier because they are weak roots.
-  return Lookup(&weak_interns_, s);
+  return weak_interns_.Find(s);
 }
 
-mirror::String* InternTable::Lookup(Table* table, mirror::String* s) {
-  Locks::intern_table_lock_->AssertHeld(Thread::Current());
-  auto it = table->find(GcRoot<mirror::String>(s));
-  if (LIKELY(it != table->end())) {
-    return const_cast<GcRoot<mirror::String>&>(*it).Read();
-  }
-  return nullptr;
+void InternTable::SwapPostZygoteWithPreZygote() {
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
+  weak_interns_.SwapPostZygoteWithPreZygote();
+  strong_interns_.SwapPostZygoteWithPreZygote();
 }
 
 mirror::String* InternTable::InsertStrong(mirror::String* s) {
@@ -116,7 +104,7 @@
   if (log_new_roots_) {
     new_strong_intern_roots_.push_back(GcRoot<mirror::String>(s));
   }
-  strong_interns_.insert(GcRoot<mirror::String>(s));
+  strong_interns_.Insert(s);
   return s;
 }
 
@@ -125,12 +113,12 @@
   if (runtime->IsActiveTransaction()) {
     runtime->RecordWeakStringInsertion(s);
   }
-  weak_interns_.insert(GcRoot<mirror::String>(s));
+  weak_interns_.Insert(s);
   return s;
 }
 
 void InternTable::RemoveStrong(mirror::String* s) {
-  Remove(&strong_interns_, s);
+  strong_interns_.Remove(s);
 }
 
 void InternTable::RemoveWeak(mirror::String* s) {
@@ -138,13 +126,7 @@
   if (runtime->IsActiveTransaction()) {
     runtime->RecordWeakStringRemoval(s);
   }
-  Remove(&weak_interns_, s);
-}
-
-void InternTable::Remove(Table* table, mirror::String* s) {
-  auto it = table->find(GcRoot<mirror::String>(s));
-  DCHECK(it != table->end());
-  table->erase(it);
+  weak_interns_.Remove(s);
 }
 
 // Insert/remove methods used to undo changes made during an aborted transaction.
@@ -165,11 +147,40 @@
   RemoveWeak(s);
 }
 
-static mirror::String* LookupStringFromImage(mirror::String* s)
+void InternTable::AddImageStringsToTable(gc::space::ImageSpace* image_space) {
+  CHECK(image_space != nullptr);
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
+  if (!image_added_to_intern_table_) {
+    mirror::Object* root = image_space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
+    mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>();
+    for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
+      mirror::DexCache* dex_cache = dex_caches->Get(i);
+      const DexFile* dex_file = dex_cache->GetDexFile();
+      const size_t num_strings = dex_file->NumStringIds();
+      for (size_t j = 0; j < num_strings; ++j) {
+        mirror::String* image_string = dex_cache->GetResolvedString(j);
+        if (image_string != nullptr) {
+          mirror::String* found = LookupStrong(image_string);
+          if (found == nullptr) {
+            InsertStrong(image_string);
+          } else {
+            DCHECK_EQ(found, image_string);
+          }
+        }
+      }
+    }
+    image_added_to_intern_table_ = true;
+  }
+}
+
+mirror::String* InternTable::LookupStringFromImage(mirror::String* s)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (image_added_to_intern_table_) {
+    return nullptr;
+  }
   gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
-  if (image == NULL) {
-    return NULL;  // No image present.
+  if (image == nullptr) {
+    return nullptr;  // No image present.
   }
   mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>();
@@ -179,15 +190,15 @@
     const DexFile* dex_file = dex_cache->GetDexFile();
     // Binary search the dex file for the string index.
     const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str());
-    if (string_id != NULL) {
+    if (string_id != nullptr) {
       uint32_t string_idx = dex_file->GetIndexForStringId(*string_id);
-      mirror::String* image = dex_cache->GetResolvedString(string_idx);
-      if (image != NULL) {
-        return image;
+      mirror::String* image_string = dex_cache->GetResolvedString(string_idx);
+      if (image_string != NULL) {
+        return image_string;
       }
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 void InternTable::AllowNewInterns() {
@@ -204,58 +215,36 @@
 }
 
 mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) {
+  if (s == nullptr) {
+    return nullptr;
+  }
   Thread* self = Thread::Current();
   MutexLock mu(self, *Locks::intern_table_lock_);
-
-  DCHECK(s != NULL);
-
   while (UNLIKELY(!allow_new_interns_)) {
     new_intern_condition_.WaitHoldingLocks(self);
   }
-
-  if (is_strong) {
-    // Check the strong table for a match.
-    mirror::String* strong = LookupStrong(s);
-    if (strong != NULL) {
-      return strong;
-    }
-
-    // Check the image for a match.
-    mirror::String* image = LookupStringFromImage(s);
-    if (image != NULL) {
-      return InsertStrong(image);
-    }
-
-    // There is no match in the strong table, check the weak table.
-    mirror::String* weak = LookupWeak(s);
-    if (weak != NULL) {
-      // A match was found in the weak table. Promote to the strong table.
-      RemoveWeak(weak);
-      return InsertStrong(weak);
-    }
-
-    // No match in the strong table or the weak table. Insert into the strong
-    // table.
-    return InsertStrong(s);
-  }
-
   // Check the strong table for a match.
   mirror::String* strong = LookupStrong(s);
-  if (strong != NULL) {
+  if (strong != nullptr) {
     return strong;
   }
   // Check the image for a match.
   mirror::String* image = LookupStringFromImage(s);
-  if (image != NULL) {
-    return InsertWeak(image);
+  if (image != nullptr) {
+    return is_strong ? InsertStrong(image) : InsertWeak(image);
   }
-  // Check the weak table for a match.
+  // There is no match in the strong table, check the weak table.
   mirror::String* weak = LookupWeak(s);
-  if (weak != NULL) {
+  if (weak != nullptr) {
+    if (is_strong) {
+      // A match was found in the weak table. Promote to the strong table.
+      RemoveWeak(weak);
+      return InsertStrong(weak);
+    }
     return weak;
   }
-  // Insert into the weak table.
-  return InsertWeak(s);
+  // No match in the strong table or the weak table. Insert into the strong / weak table.
+  return is_strong ? InsertStrong(s) : InsertWeak(s);
 }
 
 mirror::String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
@@ -270,55 +259,104 @@
 }
 
 mirror::String* InternTable::InternStrong(mirror::String* s) {
-  if (s == nullptr) {
-    return nullptr;
-  }
   return Insert(s, true);
 }
 
 mirror::String* InternTable::InternWeak(mirror::String* s) {
-  if (s == nullptr) {
-    return nullptr;
-  }
   return Insert(s, false);
 }
 
 bool InternTable::ContainsWeak(mirror::String* s) {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  const mirror::String* found = LookupWeak(s);
-  return found == s;
+  return LookupWeak(s) == s;
 }
 
 void InternTable::SweepInternTableWeaks(IsMarkedCallback* callback, void* arg) {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) {
+  weak_interns_.SweepWeaks(callback, arg);
+}
+
+std::size_t InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& root) const {
+  if (kIsDebugBuild) {
+    Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+  }
+  return static_cast<size_t>(root.Read()->GetHashCode());
+}
+
+bool InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& a,
+                                               const GcRoot<mirror::String>& b) const {
+  if (kIsDebugBuild) {
+    Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+  }
+  return a.Read()->Equals(b.Read());
+}
+
+void InternTable::Table::Remove(mirror::String* s) {
+  auto it = post_zygote_table_.Find(GcRoot<mirror::String>(s));
+  if (it != post_zygote_table_.end()) {
+    post_zygote_table_.Erase(it);
+  } else {
+    it = pre_zygote_table_.Find(GcRoot<mirror::String>(s));
+    DCHECK(it != pre_zygote_table_.end());
+    pre_zygote_table_.Erase(it);
+  }
+}
+
+mirror::String* InternTable::Table::Find(mirror::String* s) {
+  Locks::intern_table_lock_->AssertHeld(Thread::Current());
+  auto it = pre_zygote_table_.Find(GcRoot<mirror::String>(s));
+  if (it != pre_zygote_table_.end()) {
+    return it->Read();
+  }
+  it = post_zygote_table_.Find(GcRoot<mirror::String>(s));
+  if (it != post_zygote_table_.end()) {
+    return it->Read();
+  }
+  return nullptr;
+}
+
+void InternTable::Table::SwapPostZygoteWithPreZygote() {
+  CHECK(pre_zygote_table_.Empty());
+  std::swap(pre_zygote_table_, post_zygote_table_);
+  VLOG(heap) << "Swapping " << pre_zygote_table_.Size() << " interns to the pre zygote table";
+}
+
+void InternTable::Table::Insert(mirror::String* s) {
+  // Always insert the post zygote table, this gets swapped when we create the zygote to be the
+  // pre zygote table.
+  post_zygote_table_.Insert(GcRoot<mirror::String>(s));
+}
+
+void InternTable::Table::VisitRoots(RootCallback* callback, void* arg) {
+  for (auto& intern : pre_zygote_table_) {
+    intern.VisitRoot(callback, arg, RootInfo(kRootInternedString));
+  }
+  for (auto& intern : post_zygote_table_) {
+    intern.VisitRoot(callback, arg, RootInfo(kRootInternedString));
+  }
+}
+
+void InternTable::Table::SweepWeaks(IsMarkedCallback* callback, void* arg) {
+  SweepWeaks(&pre_zygote_table_, callback, arg);
+  SweepWeaks(&post_zygote_table_, callback, arg);
+}
+
+void InternTable::Table::SweepWeaks(UnorderedSet* set, IsMarkedCallback* callback, void* arg) {
+  for (auto it = set->begin(), end = set->end(); it != end;) {
     // This does not need a read barrier because this is called by GC.
-    GcRoot<mirror::String>& root = const_cast<GcRoot<mirror::String>&>(*it);
-    mirror::Object* object = root.Read<kWithoutReadBarrier>();
+    mirror::Object* object = it->Read<kWithoutReadBarrier>();
     mirror::Object* new_object = callback(object, arg);
     if (new_object == nullptr) {
-      it = weak_interns_.erase(it);
+      it = set->Erase(it);
     } else {
-      root = GcRoot<mirror::String>(down_cast<mirror::String*>(new_object));
+      *it = GcRoot<mirror::String>(new_object->AsString());
       ++it;
     }
   }
 }
 
-std::size_t InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& root) {
-  if (kIsDebugBuild) {
-    Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
-  }
-  return static_cast<size_t>(const_cast<GcRoot<mirror::String>&>(root).Read()->GetHashCode());
-}
-
-bool InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& a,
-                                               const GcRoot<mirror::String>& b) {
-  if (kIsDebugBuild) {
-    Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
-  }
-  return const_cast<GcRoot<mirror::String>&>(a).Read()->Equals(
-      const_cast<GcRoot<mirror::String>&>(b).Read());
+size_t InternTable::Table::Size() const {
+  return pre_zygote_table_.Size() + post_zygote_table_.Size();
 }
 
 }  // namespace art
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index e3223c8..371d3f7 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -20,12 +20,19 @@
 #include <unordered_set>
 
 #include "base/allocator.h"
+#include "base/hash_set.h"
 #include "base/mutex.h"
 #include "gc_root.h"
 #include "object_callbacks.h"
 
 namespace art {
 
+namespace gc {
+namespace space {
+class ImageSpace;
+}  // namespace space
+}  // namespace gc
+
 enum VisitRootFlags : uint8_t;
 
 namespace mirror {
@@ -66,9 +73,12 @@
 
   bool ContainsWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  size_t Size() const;
-  size_t StrongSize() const;
-  size_t WeakSize() const;
+  // Total number of interned strings.
+  size_t Size() const LOCKS_EXCLUDED(Locks::intern_table_lock_);
+  // Total number of weakly live interned strings.
+  size_t StrongSize() const LOCKS_EXCLUDED(Locks::intern_table_lock_);
+  // Total number of strongly live interned strings.
+  size_t WeakSize() const LOCKS_EXCLUDED(Locks::intern_table_lock_);
 
   void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -78,29 +88,83 @@
   void DisallowNewInterns() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AllowNewInterns() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Adds all of the resolved image strings from the image space into the intern table. The
+  // advantage of doing this is preventing expensive DexFile::FindStringId calls.
+  void AddImageStringsToTable(gc::space::ImageSpace* image_space)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::intern_table_lock_);
+  // Copy the post zygote tables to pre zygote to save memory by preventing dirty pages.
+  void SwapPostZygoteWithPreZygote()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::intern_table_lock_);
+
  private:
   class StringHashEquals {
    public:
-    std::size_t operator()(const GcRoot<mirror::String>& root) NO_THREAD_SAFETY_ANALYSIS;
-    bool operator()(const GcRoot<mirror::String>& a, const GcRoot<mirror::String>& b)
+    std::size_t operator()(const GcRoot<mirror::String>& root) const NO_THREAD_SAFETY_ANALYSIS;
+    bool operator()(const GcRoot<mirror::String>& a, const GcRoot<mirror::String>& b) const
         NO_THREAD_SAFETY_ANALYSIS;
   };
-  typedef std::unordered_set<GcRoot<mirror::String>, StringHashEquals, StringHashEquals,
-      TrackingAllocator<GcRoot<mirror::String>, kAllocatorTagInternTable>> Table;
+  class GcRootEmptyFn {
+   public:
+    void MakeEmpty(GcRoot<mirror::String>& item) const {
+      item = GcRoot<mirror::String>();
+    }
+    bool IsEmpty(const GcRoot<mirror::String>& item) const {
+      return item.IsNull();
+    }
+  };
 
+  // Table which holds pre zygote and post zygote interned strings. There is one instance for
+  // weak interns and strong interns.
+  class Table {
+   public:
+    mirror::String* Find(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    void Insert(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    void Remove(mirror::String* s)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    void VisitRoots(RootCallback* callback, void* arg)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    void SweepWeaks(IsMarkedCallback* callback, void* arg)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    void SwapPostZygoteWithPreZygote() EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    size_t Size() const EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+
+   private:
+    typedef HashSet<GcRoot<mirror::String>, GcRootEmptyFn, StringHashEquals, StringHashEquals,
+        TrackingAllocator<GcRoot<mirror::String>, kAllocatorTagInternTable>> UnorderedSet;
+
+    void SweepWeaks(UnorderedSet* set, IsMarkedCallback* callback, void* arg)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+
+    // We call SwapPostZygoteWithPreZygote when we create the zygote to reduce private dirty pages
+    // caused by modifying the zygote intern table hash table. The pre zygote table are the
+    // interned strings which were interned before we created the zygote space. Post zygote is self
+    // explanatory.
+    UnorderedSet pre_zygote_table_;
+    UnorderedSet post_zygote_table_;
+  };
+
+  // Insert if non null, otherwise return nullptr.
   mirror::String* Insert(mirror::String* s, bool is_strong)
       LOCKS_EXCLUDED(Locks::intern_table_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::String* LookupStrong(mirror::String* s)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   mirror::String* LookupWeak(mirror::String* s)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::String* Lookup(Table* table, mirror::String* s)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   mirror::String* InsertStrong(mirror::String* s)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   mirror::String* InsertWeak(mirror::String* s)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   void RemoveStrong(mirror::String* s)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -108,14 +172,16 @@
   void RemoveWeak(mirror::String* s)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
-  void Remove(Table* table, mirror::String* s)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
 
   // Transaction rollback access.
+  mirror::String* LookupStringFromImage(mirror::String* s)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   mirror::String* InsertStrongFromTransaction(mirror::String* s)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   mirror::String* InsertWeakFromTransaction(mirror::String* s)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   void RemoveStrongFromTransaction(mirror::String* s)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -125,6 +191,7 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
   friend class Transaction;
 
+  bool image_added_to_intern_table_ GUARDED_BY(Locks::intern_table_lock_);
   bool log_new_roots_ GUARDED_BY(Locks::intern_table_lock_);
   bool allow_new_interns_ GUARDED_BY(Locks::intern_table_lock_);
   ConditionVariable new_intern_condition_ GUARDED_BY(Locks::intern_table_lock_);
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 07224ef..b04a18b 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -138,7 +138,7 @@
   if (method->IsStatic()) {
     if (shorty == "L") {
       typedef jobject (fntype)(JNIEnv*, jclass);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       jobject jresult;
@@ -149,35 +149,35 @@
       result->SetL(soa.Decode<Object*>(jresult));
     } else if (shorty == "V") {
       typedef void (fntype)(JNIEnv*, jclass);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), klass.get());
     } else if (shorty == "Z") {
       typedef jboolean (fntype)(JNIEnv*, jclass);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetZ(fn(soa.Env(), klass.get()));
     } else if (shorty == "BI") {
       typedef jbyte (fntype)(JNIEnv*, jclass, jint);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetB(fn(soa.Env(), klass.get(), args[0]));
     } else if (shorty == "II") {
       typedef jint (fntype)(JNIEnv*, jclass, jint);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetI(fn(soa.Env(), klass.get(), args[0]));
     } else if (shorty == "LL") {
       typedef jobject (fntype)(JNIEnv*, jclass, jobject);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -190,14 +190,15 @@
       result->SetL(soa.Decode<Object*>(jresult));
     } else if (shorty == "IIZ") {
       typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetI(fn(soa.Env(), klass.get(), args[0], args[1]));
     } else if (shorty == "ILI") {
       typedef jint (fntype)(JNIEnv*, jclass, jobject, jint);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(
+          method->GetEntryPointFromJni()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -206,21 +207,21 @@
       result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1]));
     } else if (shorty == "SIZ") {
       typedef jshort (fntype)(JNIEnv*, jclass, jint, jboolean);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetEntryPointFromJni()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetS(fn(soa.Env(), klass.get(), args[0], args[1]));
     } else if (shorty == "VIZ") {
       typedef void (fntype)(JNIEnv*, jclass, jint, jboolean);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), klass.get(), args[0], args[1]);
     } else if (shorty == "ZLL") {
       typedef jboolean (fntype)(JNIEnv*, jclass, jobject, jobject);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -231,7 +232,7 @@
       result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get()));
     } else if (shorty == "ZILL") {
       typedef jboolean (fntype)(JNIEnv*, jclass, jint, jobject, jobject);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg1(soa.Env(),
@@ -242,7 +243,7 @@
       result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get()));
     } else if (shorty == "VILII") {
       typedef void (fntype)(JNIEnv*, jclass, jint, jobject, jint, jint);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg1(soa.Env(),
@@ -251,7 +252,7 @@
       fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]);
     } else if (shorty == "VLILII") {
       typedef void (fntype)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -267,7 +268,7 @@
   } else {
     if (shorty == "L") {
       typedef jobject (fntype)(JNIEnv*, jobject);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       jobject jresult;
@@ -278,14 +279,14 @@
       result->SetL(soa.Decode<Object*>(jresult));
     } else if (shorty == "V") {
       typedef void (fntype)(JNIEnv*, jobject);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), rcvr.get());
     } else if (shorty == "LL") {
       typedef jobject (fntype)(JNIEnv*, jobject, jobject);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -299,7 +300,7 @@
       ScopedThreadStateChange tsc(self, kNative);
     } else if (shorty == "III") {
       typedef jint (fntype)(JNIEnv*, jobject, jint, jint);
-      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
+      fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       ScopedThreadStateChange tsc(self, kNative);
@@ -315,6 +316,10 @@
   kSwitchImpl,            // Switch-based interpreter implementation.
   kComputedGotoImplKind   // Computed-goto-based interpreter implementation.
 };
+static std::ostream& operator<<(std::ostream& os, const InterpreterImplKind& rhs) {
+  os << ((rhs == kSwitchImpl) ? "Switch-based interpreter" : "Computed-goto-based interpreter");
+  return os;
+}
 
 #if !defined(__clang__)
 static constexpr InterpreterImplKind kInterpreterImplKind = kComputedGotoImplKind;
@@ -322,38 +327,31 @@
 // Clang 3.4 fails to build the goto interpreter implementation.
 static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImpl;
 template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
-                       ShadowFrame& shadow_frame, JValue result_register) {
+JValue ExecuteGotoImpl(Thread*, const DexFile::CodeItem*, ShadowFrame&, JValue) {
   LOG(FATAL) << "UNREACHABLE";
-  exit(0);
+  UNREACHABLE();
 }
 // Explicit definitions of ExecuteGotoImpl.
 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
-                                    const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
                                     ShadowFrame& shadow_frame, JValue result_register);
 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
-                                     const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
                                      ShadowFrame& shadow_frame, JValue result_register);
 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
-                                    const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, true>(Thread* self,  const DexFile::CodeItem* code_item,
+                                   ShadowFrame& shadow_frame, JValue result_register);
+template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
                                     ShadowFrame& shadow_frame, JValue result_register);
-template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
-                                     const DexFile::CodeItem* code_item,
-                                     ShadowFrame& shadow_frame, JValue result_register);
 #endif
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
-                      ShadowFrame& shadow_frame, JValue result_register)
+static JValue Execute(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame,
+                      JValue result_register)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item,
                              ShadowFrame& shadow_frame, JValue result_register) {
-  DCHECK(shadow_frame.GetMethod() == mh.GetMethod() ||
-         shadow_frame.GetMethod()->GetDeclaringClass()->IsProxyClass());
   DCHECK(!shadow_frame.GetMethod()->IsAbstract());
   DCHECK(!shadow_frame.GetMethod()->IsNative());
   shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
@@ -363,32 +361,32 @@
     // Enter the "without access check" interpreter.
     if (kInterpreterImplKind == kSwitchImpl) {
       if (transaction_active) {
-        return ExecuteSwitchImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register);
       } else {
-        return ExecuteSwitchImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register);
       }
     } else {
       DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
       if (transaction_active) {
-        return ExecuteGotoImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteGotoImpl<false, true>(self, code_item, shadow_frame, result_register);
       } else {
-        return ExecuteGotoImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteGotoImpl<false, false>(self, code_item, shadow_frame, result_register);
       }
     }
   } else {
     // Enter the "with access check" interpreter.
     if (kInterpreterImplKind == kSwitchImpl) {
       if (transaction_active) {
-        return ExecuteSwitchImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register);
       } else {
-        return ExecuteSwitchImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register);
       }
     } else {
       DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
       if (transaction_active) {
-        return ExecuteGotoImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteGotoImpl<true, true>(self, code_item, shadow_frame, result_register);
       } else {
-        return ExecuteGotoImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+        return ExecuteGotoImpl<true, false>(self, code_item, shadow_frame, result_register);
       }
     }
   }
@@ -469,9 +467,7 @@
     }
   }
   if (LIKELY(!method->IsNative())) {
-    StackHandleScope<1> hs(self);
-    MethodHelper mh(hs.NewHandle(method));
-    JValue r = Execute(self, mh, code_item, *shadow_frame, JValue());
+    JValue r = Execute(self, code_item, *shadow_frame, JValue());
     if (result != NULL) {
       *result = r;
     }
@@ -496,10 +492,8 @@
   value.SetJ(ret_val->GetJ());  // Set value to last known result in case the shadow frame chain is empty.
   while (shadow_frame != NULL) {
     self->SetTopOfShadowStack(shadow_frame);
-    StackHandleScope<1> hs(self);
-    MethodHelper mh(hs.NewHandle(shadow_frame->GetMethod()));
-    const DexFile::CodeItem* code_item = mh.GetMethod()->GetCodeItem();
-    value = Execute(self, mh, code_item, *shadow_frame, value);
+    const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem();
+    value = Execute(self, code_item, *shadow_frame, value);
     ShadowFrame* old_frame = shadow_frame;
     shadow_frame = shadow_frame->GetLink();
     delete old_frame;
@@ -507,8 +501,8 @@
   ret_val->SetJ(value.GetJ());
 }
 
-JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
-                                ShadowFrame& shadow_frame) {
+JValue EnterInterpreterFromEntryPoint(Thread* self, 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,11 +510,10 @@
     return JValue();
   }
 
-  return Execute(self, mh, code_item, shadow_frame, JValue());
+  return Execute(self, code_item, *shadow_frame, JValue());
 }
 
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
-                                                  const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
                                                   ShadowFrame* shadow_frame, JValue* result) {
   bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
   if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) {
@@ -529,10 +522,10 @@
   }
 
   self->PushShadowFrame(shadow_frame);
-  ArtMethod* method = shadow_frame->GetMethod();
   // Ensure static methods are initialized.
-  if (method->IsStatic()) {
-    mirror::Class* declaring_class = method->GetDeclaringClass();
+  const bool is_static = shadow_frame->GetMethod()->IsStatic();
+  if (is_static) {
+    mirror::Class* declaring_class = shadow_frame->GetMethod()->GetDeclaringClass();
     if (UNLIKELY(!declaring_class->IsInitialized())) {
       StackHandleScope<1> hs(self);
       HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
@@ -546,15 +539,15 @@
     }
   }
 
-  if (LIKELY(!method->IsNative())) {
-    result->SetJ(Execute(self, mh, code_item, *shadow_frame, JValue()).GetJ());
+  if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
+    result->SetJ(Execute(self, 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 = method->IsStatic() ? nullptr : shadow_frame->GetVRegReference(0);
-    uint32_t* args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1);
-    UnstartedRuntimeJni(self, method, receiver, args, result);
+    Object* receiver = is_static ? nullptr : shadow_frame->GetVRegReference(0);
+    uint32_t* args = shadow_frame->GetVRegArgs(is_static ? 0 : 1);
+    UnstartedRuntimeJni(self, shadow_frame->GetMethod(), receiver, args, result);
   }
 
   self->PopShadowFrame();
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index 0750eb5..7d634b3 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -27,7 +27,6 @@
 }  // namespace mirror
 
 union JValue;
-class MethodHelper;
 class ShadowFrame;
 class Thread;
 
@@ -42,20 +41,18 @@
                                            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, const DexFile::CodeItem* code_item,
+                                             ShadowFrame* shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-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,
-                                                   const DexFile::CodeItem* code_item,
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
+                                                  ShadowFrame* shadow_frame, JValue* result)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, 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 733f1d1..2a63456 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -16,7 +16,6 @@
 
 #include "interpreter_common.h"
 
-#include "field_helper.h"
 #include "mirror/array-inl.h"
 
 namespace art {
@@ -80,6 +79,7 @@
       break;
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
   }
   return true;
 }
@@ -145,6 +145,18 @@
     case Primitive::kPrimInt:
       shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset)));
       break;
+    case Primitive::kPrimBoolean:
+      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldBoolean(field_offset)));
+      break;
+    case Primitive::kPrimByte:
+      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldByte(field_offset)));
+      break;
+    case Primitive::kPrimChar:
+      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldChar(field_offset)));
+      break;
+    case Primitive::kPrimShort:
+      shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldShort(field_offset)));
+      break;
     case Primitive::kPrimLong:
       shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset)));
       break;
@@ -153,6 +165,7 @@
       break;
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
   }
   return true;
 }
@@ -162,9 +175,13 @@
   template bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst, \
                                          uint16_t inst_data)
 
-EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);    // iget-quick.
-EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);   // iget-wide-quick.
-EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot);    // iget-object-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);      // iget-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimBoolean);  // iget-boolean-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimByte);     // iget-byte-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimChar);     // iget-char-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimShort);    // iget-short-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);     // iget-wide-quick.
+EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot);      // iget-object-quick.
 #undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
 
 template<Primitive::Type field_type>
@@ -195,7 +212,7 @@
       break;
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
-      break;
+      UNREACHABLE();
   }
   return field_value;
 }
@@ -265,8 +282,7 @@
           HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
           HandleWrapper<mirror::Object> h_reg(hs.NewHandleWrapper(&reg));
           HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
-          FieldHelper fh(h_f);
-          field_class = fh.GetType();
+          field_class = h_f->GetType(true);
         }
         if (!reg->VerifierInstanceOf(field_class)) {
           // This should never happen.
@@ -285,6 +301,7 @@
     }
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
   }
   return true;
 }
@@ -369,6 +386,7 @@
       break;
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
+      UNREACHABLE();
   }
   return true;
 }
@@ -501,14 +519,14 @@
   return found_dex_pc;
 }
 
-void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
-  LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(mh.GetMethod()->GetDexFile());
-  exit(0);  // Unreachable, keep GCC happy.
+void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) {
+  LOG(FATAL) << "Unexpected instruction: "
+             << inst->DumpString(shadow_frame.GetMethod()->GetDexFile());
+  UNREACHABLE();
 }
 
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
-                                   const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
-                                   JValue* result, size_t arg_offset)
+static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
+                                   ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
@@ -537,29 +555,28 @@
 }
 
 template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
+bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
             const Instruction* inst, uint16_t inst_data, JValue* result) {
   // Compute method information.
-  const DexFile::CodeItem* code_item = method->GetCodeItem();
+  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
   const uint16_t num_ins = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
   uint16_t num_regs;
   if (LIKELY(code_item != NULL)) {
     num_regs = code_item->registers_size_;
     DCHECK_EQ(num_ins, code_item->ins_size_);
   } else {
-    DCHECK(method->IsNative() || method->IsProxyMethod());
+    DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
     num_regs = num_ins;
   }
 
   // Allocate shadow frame on the stack.
   const char* old_cause = self->StartAssertNoThreadSuspension("DoCall");
   void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
-  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
+  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, called_method, 0,
+                                                    memory));
 
   // Initialize new shadow frame.
   const size_t first_dest_reg = num_regs - num_ins;
-  StackHandleScope<1> hs(self);
-  MethodHelper mh(hs.NewHandle(method));
   if (do_assignability_check) {
     // Slow path.
     // We might need to do class loading, which incurs a thread state change to kNative. So
@@ -569,11 +586,12 @@
 
     // We need to do runtime check on reference assignment. We need to load the shorty
     // to get the exact type of each reference argument.
-    const DexFile::TypeList* params = method->GetParameterTypeList();
+    const DexFile::TypeList* params = new_shadow_frame->GetMethod()->GetParameterTypeList();
     uint32_t shorty_len = 0;
-    const char* shorty = method->GetShorty(&shorty_len);
+    const char* shorty = new_shadow_frame->GetMethod()->GetShorty(&shorty_len);
 
-    // TODO: find a cleaner way to separate non-range and range information without duplicating code.
+    // TODO: find a cleaner way to separate non-range and range information without duplicating
+    //       code.
     uint32_t arg[5];  // only used in invoke-XXX.
     uint32_t vregC;   // only used in invoke-XXX-range.
     if (is_range) {
@@ -585,7 +603,7 @@
     // Handle receiver apart since it's not part of the shorty.
     size_t dest_reg = first_dest_reg;
     size_t arg_offset = 0;
-    if (!method->IsStatic()) {
+    if (!new_shadow_frame->GetMethod()->IsStatic()) {
       size_t receiver_reg = is_range ? vregC : arg[0];
       new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
       ++dest_reg;
@@ -598,7 +616,9 @@
         case 'L': {
           Object* o = shadow_frame.GetVRegReference(src_reg);
           if (do_assignability_check && o != NULL) {
-            Class* arg_type = mh.GetClassFromTypeIdx(params->GetTypeItem(shorty_pos).type_idx_);
+            Class* arg_type =
+                new_shadow_frame->GetMethod()->GetClassFromTypeIndex(
+                    params->GetTypeItem(shorty_pos).type_idx_, true);
             if (arg_type == NULL) {
               CHECK(self->IsExceptionPending());
               return false;
@@ -609,7 +629,7 @@
               self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                        "Ljava/lang/VirtualMachineError;",
                                        "Invoking %s with bad arg %d, type '%s' not instance of '%s'",
-                                       method->GetName(), shorty_pos,
+                                       new_shadow_frame->GetMethod()->GetName(), shorty_pos,
                                        o->GetClass()->GetDescriptor(&temp1),
                                        arg_type->GetDescriptor(&temp2));
               return false;
@@ -646,7 +666,8 @@
       uint16_t regList = inst->Fetch16(2);
       uint16_t count = num_ins;
       if (count == 5) {
-        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U, (inst_data >> 8) & 0x0f);
+        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U,
+                       (inst_data >> 8) & 0x0f);
         --count;
        }
       for (size_t arg_index = 0; arg_index < count; ++arg_index, regList >>= 4) {
@@ -658,17 +679,24 @@
 
   // Do the call now.
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    if (kIsDebugBuild && method->GetEntryPointFromInterpreter() == nullptr) {
-      LOG(FATAL) << "Attempt to invoke non-executable method: " << PrettyMethod(method);
+    if (kIsDebugBuild && new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter() == nullptr) {
+      LOG(FATAL) << "Attempt to invoke non-executable method: "
+          << PrettyMethod(new_shadow_frame->GetMethod());
+      UNREACHABLE();
     }
     if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
-        !method->IsNative() && !method->IsProxyMethod() &&
-        method->GetEntryPointFromInterpreter() == artInterpreterToCompiledCodeBridge) {
-      LOG(FATAL) << "Attempt to call compiled code when -Xint: " << PrettyMethod(method);
+        !new_shadow_frame->GetMethod()->IsNative() &&
+        !new_shadow_frame->GetMethod()->IsProxyMethod() &&
+        new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter()
+            == artInterpreterToCompiledCodeBridge) {
+      LOG(FATAL) << "Attempt to call compiled code when -Xint: "
+          << PrettyMethod(new_shadow_frame->GetMethod());
+      UNREACHABLE();
     }
-    (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
+    (new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter())(self, code_item,
+                                                                    new_shadow_frame, result);
   } else {
-    UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, first_dest_reg);
+    UnstartedRuntimeInvoke(self, code_item, new_shadow_frame, result, first_dest_reg);
   }
   return !self->IsExceptionPending();
 }
@@ -809,8 +837,8 @@
   result->SetL(found);
 }
 
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
-                                   const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
+static void UnstartedRuntimeInvoke(Thread* self,  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
   // problems in core libraries.
@@ -851,12 +879,12 @@
     // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
     // going the reflective Dex way.
     Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
-    String* name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
+    String* name2 = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
     ArtField* found = NULL;
     ObjectArray<ArtField>* fields = klass->GetIFields();
     for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
       ArtField* f = fields->Get(i);
-      if (name->Equals(f->GetName())) {
+      if (name2->Equals(f->GetName())) {
         found = f;
       }
     }
@@ -864,14 +892,14 @@
       fields = klass->GetSFields();
       for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
         ArtField* f = fields->Get(i);
-        if (name->Equals(f->GetName())) {
+        if (name2->Equals(f->GetName())) {
           found = f;
         }
       }
     }
     CHECK(found != NULL)
       << "Failed to find field in Class.getDeclaredField in un-started runtime. name="
-      << name->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass);
+      << name2->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass);
     // TODO: getDeclaredField calls GetType once the field is found to ensure a
     //       NoClassDefFoundError is thrown if the field's type cannot be resolved.
     Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass();
@@ -887,9 +915,8 @@
     Object* obj = shadow_frame->GetVRegReference(arg_offset);
     result->SetI(obj->IdentityHashCode());
   } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") {
-    StackHandleScope<1> hs(self);
-    MethodHelper mh(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset)->AsArtMethod()));
-    result->SetL(mh.GetNameAsString(self));
+    mirror::ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod();
+    result->SetL(method->GetNameAsString(self));
   } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
              name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") {
     // Special case array copying without initializing System.
@@ -931,7 +958,7 @@
     }
   } else {
     // Not special, continue with regular interpreter execution.
-    artInterpreterToInterpreterBridge(self, mh, code_item, shadow_frame, result);
+    artInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
   }
 }
 
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a8345ad..ce7c1c3 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"
@@ -30,7 +33,6 @@
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "handle_scope-inl.h"
-#include "method_helper-inl.h"
 #include "nth_caller_visitor.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method.h"
@@ -67,13 +69,11 @@
 // External references to both interpreter implementations.
 
 template<bool do_access_check, bool transaction_active>
-extern JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh,
-                                const DexFile::CodeItem* code_item,
+extern JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
                                 ShadowFrame& shadow_frame, JValue result_register);
 
 template<bool do_access_check, bool transaction_active>
-extern JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh,
-                              const DexFile::CodeItem* code_item,
+extern JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item,
                               ShadowFrame& shadow_frame, JValue result_register);
 
 void ThrowNullPointerExceptionFromInterpreter(const ShadowFrame& shadow_frame)
@@ -97,7 +97,7 @@
 // DoInvokeVirtualQuick functions.
 // Returns true on success, otherwise throws an exception and returns false.
 template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
+bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
             const Instruction* inst, uint16_t inst_data, JValue* result);
 
 // Handles invoke-XXX/range instructions.
@@ -109,19 +109,20 @@
   const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
   Object* receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
   mirror::ArtMethod* sf_method = shadow_frame.GetMethod();
-  ArtMethod* const method = FindMethodFromCode<type, do_access_check>(
+  ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>(
       method_idx, &receiver, &sf_method, self);
   // The shadow frame should already be pushed, so we don't need to update it.
-  if (UNLIKELY(method == nullptr)) {
+  if (UNLIKELY(called_method == nullptr)) {
     CHECK(self->IsExceptionPending());
     result->SetJ(0);
     return false;
-  } else if (UNLIKELY(method->IsAbstract())) {
-    ThrowAbstractMethodError(method);
+  } else if (UNLIKELY(called_method->IsAbstract())) {
+    ThrowAbstractMethodError(called_method);
     result->SetJ(0);
     return false;
   } else {
-    return DoCall<is_range, do_access_check>(method, self, shadow_frame, inst, inst_data, result);
+    return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data,
+                                             result);
   }
 }
 
@@ -141,18 +142,18 @@
   }
   const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
   CHECK(receiver->GetClass()->ShouldHaveEmbeddedImtAndVTable());
-  ArtMethod* const method = receiver->GetClass()->GetEmbeddedVTableEntry(vtable_idx);
-  if (UNLIKELY(method == nullptr)) {
+  ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry(vtable_idx);
+  if (UNLIKELY(called_method == nullptr)) {
     CHECK(self->IsExceptionPending());
     result->SetJ(0);
     return false;
-  } else if (UNLIKELY(method->IsAbstract())) {
-    ThrowAbstractMethodError(method);
+  } else if (UNLIKELY(called_method->IsAbstract())) {
+    ThrowAbstractMethodError(called_method);
     result->SetJ(0);
     return false;
   } else {
     // No need to check since we've been quickened.
-    return DoCall<is_range, false>(method, self, shadow_frame, inst, inst_data, result);
+    return DoCall<is_range, false>(called_method, self, shadow_frame, inst, inst_data, result);
   }
 }
 
@@ -184,7 +185,7 @@
 
 // Handles string resolution for const-string and const-string-jumbo instructions. Also ensures the
 // java.lang.String class is initialized.
-static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
+static inline String* ResolveString(Thread* self, ShadowFrame& shadow_frame, uint32_t string_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(!kMovingMethods);
   Class* java_lang_string_class = String::GetJavaLangString();
@@ -197,7 +198,16 @@
       return nullptr;
     }
   }
-  return mh.ResolveString(string_idx);
+  mirror::ArtMethod* method = shadow_frame.GetMethod();
+  mirror::Class* declaring_class = method->GetDeclaringClass();
+  mirror::String* s = declaring_class->GetDexCacheStrings()->Get(string_idx);
+  if (UNLIKELY(s == nullptr)) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+    s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx,
+                                                            dex_cache);
+  }
+  return s;
 }
 
 // Handles div-int, div-int/2addr, div-int/li16 and div-int/lit8 instructions.
@@ -205,7 +215,7 @@
 static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
                                int32_t dividend, int32_t divisor)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const int32_t kMinInt = std::numeric_limits<int32_t>::min();
+  constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min();
   if (UNLIKELY(divisor == 0)) {
     ThrowArithmeticExceptionDivideByZero();
     return false;
@@ -223,7 +233,7 @@
 static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
                                   int32_t dividend, int32_t divisor)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const int32_t kMinInt = std::numeric_limits<int32_t>::min();
+  constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min();
   if (UNLIKELY(divisor == 0)) {
     ThrowArithmeticExceptionDivideByZero();
     return false;
@@ -339,12 +349,12 @@
     uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
+void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame)
   __attribute__((cold, noreturn))
   SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst,
-                                  const uint32_t dex_pc, MethodHelper& mh)
+                                  const uint32_t dex_pc)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   constexpr bool kTracing = false;
   if (kTracing) {
@@ -352,7 +362,7 @@
     std::ostringstream oss;
     oss << PrettyMethod(shadow_frame.GetMethod())
         << StringPrintf("\n0x%x: ", dex_pc)
-        << inst->DumpString(mh.GetMethod()->GetDexFile()) << "\n";
+        << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()) << "\n";
     for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
       uint32_t raw_value = shadow_frame.GetVReg(i);
       Object* ref_value = shadow_frame.GetVRegReference(i);
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 5c8a6c6..8fcbf90 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -15,6 +15,7 @@
  */
 
 #include "interpreter_common.h"
+#include "safe_math.h"
 
 namespace art {
 namespace interpreter {
@@ -25,7 +26,6 @@
 // - "inst_data" : the current instruction's first 16 bits.
 // - "dex_pc": the current pc.
 // - "shadow_frame": the current shadow frame.
-// - "mh": the current MethodHelper.
 // - "currentHandlersTable": the current table of pointer to each instruction handler.
 
 // Advance to the next instruction and updates interpreter state.
@@ -35,7 +35,7 @@
     inst = inst->RelativeAt(disp);                                          \
     dex_pc = static_cast<uint32_t>(static_cast<int32_t>(dex_pc) + disp);    \
     shadow_frame.SetDexPC(dex_pc);                                          \
-    TraceExecution(shadow_frame, inst, dex_pc, mh);                         \
+    TraceExecution(shadow_frame, inst, dex_pc);                             \
     inst_data = inst->Fetch16(0);                                           \
     goto *currentHandlersTable[inst->Opcode(inst_data)];                    \
   } while (false)
@@ -58,6 +58,7 @@
   do {                                          \
     if (kIsDebugBuild) {                        \
       LOG(FATAL) << "We should not be here !";  \
+      UNREACHABLE();                            \
     }                                           \
   } while (false)
 
@@ -110,8 +111,8 @@
  *
  */
 template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
-                       ShadowFrame& shadow_frame, JValue result_register) {
+JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame,
+                       JValue result_register) {
   // Define handler tables:
   // - The main handler table contains execution handlers for each instruction.
   // - The alternative handler table contains prelude handlers which check for thread suspend and
@@ -321,9 +322,7 @@
     const uint8_t vreg_index = inst->VRegA_11x(inst_data);
     Object* obj_result = shadow_frame.GetVRegReference(vreg_index);
     if (do_assignability_check && obj_result != NULL) {
-      StackHandleScope<1> hs(self);
-      MethodHelper mh(hs.NewHandle(shadow_frame.GetMethod()));
-      Class* return_type = mh.GetReturnType();
+      Class* return_type = shadow_frame.GetMethod()->GetReturnType();
       obj_result = shadow_frame.GetVRegReference(vreg_index);
       if (return_type == NULL) {
         // Return the pending exception.
@@ -420,7 +419,7 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(CONST_STRING) {
-    String* s = ResolveString(self, mh, inst->VRegB_21c());
+    String* s = ResolveString(self, shadow_frame, inst->VRegB_21c());
     if (UNLIKELY(s == NULL)) {
       HANDLE_PENDING_EXCEPTION();
     } else {
@@ -431,7 +430,7 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(CONST_STRING_JUMBO) {
-    String* s = ResolveString(self, mh, inst->VRegB_31c());
+    String* s = ResolveString(self, shadow_frame, inst->VRegB_31c());
     if (UNLIKELY(s == NULL)) {
       HANDLE_PENDING_EXCEPTION();
     } else {
@@ -544,7 +543,7 @@
   HANDLE_INSTRUCTION_START(NEW_ARRAY) {
     int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
     Object* obj = AllocArrayFromCode<do_access_check, true>(
-        inst->VRegC_22c(), shadow_frame.GetMethod(), length, self,
+        inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
         Runtime::Current()->GetHeap()->GetCurrentAllocator());
     if (UNLIKELY(obj == NULL)) {
       HANDLE_PENDING_EXCEPTION();
@@ -573,30 +572,14 @@
 
   HANDLE_INSTRUCTION_START(FILL_ARRAY_DATA) {
     Object* obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
-    if (UNLIKELY(obj == NULL)) {
-      ThrowNullPointerException(NULL, "null array in FILL_ARRAY_DATA");
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      Array* array = obj->AsArray();
-      DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
-      const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
-      const Instruction::ArrayDataPayload* payload =
-          reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
-      if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
-        self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
-                                 "Ljava/lang/ArrayIndexOutOfBoundsException;",
-                                 "failed FILL_ARRAY_DATA; length=%d, index=%d",
-                                 array->GetLength(), payload->element_count);
-        HANDLE_PENDING_EXCEPTION();
-      } else {
-        if (transaction_active) {
-          RecordArrayElementsInTransaction(array, payload->element_count);
-        }
-        uint32_t size_in_bytes = payload->element_count * payload->element_width;
-        memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
-        ADVANCE(3);
-      }
+    const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
+    const Instruction::ArrayDataPayload* payload =
+        reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
+    bool success = FillArrayData(obj, payload);
+    if (transaction_active && success) {
+      RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
     }
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
   }
   HANDLE_INSTRUCTION_END();
 
@@ -678,6 +661,11 @@
   }
   HANDLE_INSTRUCTION_END();
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
   HANDLE_INSTRUCTION_START(CMPL_FLOAT) {
     float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
     float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
@@ -742,6 +730,10 @@
   }
   HANDLE_INSTRUCTION_END();
 
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
   HANDLE_INSTRUCTION_START(CMP_LONG) {
     int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
     int64_t val2 = shadow_frame.GetVRegLong(inst->VRegC_23x());
@@ -1257,6 +1249,30 @@
   }
   HANDLE_INSTRUCTION_END();
 
+  HANDLE_INSTRUCTION_START(IGET_BOOLEAN_QUICK) {
+    bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_INSTRUCTION_END();
+
+  HANDLE_INSTRUCTION_START(IGET_BYTE_QUICK) {
+    bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_INSTRUCTION_END();
+
+  HANDLE_INSTRUCTION_START(IGET_CHAR_QUICK) {
+    bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_INSTRUCTION_END();
+
+  HANDLE_INSTRUCTION_START(IGET_SHORT_QUICK) {
+    bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_INSTRUCTION_END();
+
   HANDLE_INSTRUCTION_START(IGET_WIDE_QUICK) {
     bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
@@ -1643,22 +1659,22 @@
 
   HANDLE_INSTRUCTION_START(ADD_INT)
     shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) +
-                         shadow_frame.GetVReg(inst->VRegC_23x()));
+                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                 shadow_frame.GetVReg(inst->VRegC_23x())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SUB_INT)
     shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) -
-                         shadow_frame.GetVReg(inst->VRegC_23x()));
+                         SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                 shadow_frame.GetVReg(inst->VRegC_23x())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(MUL_INT)
     shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) *
-                         shadow_frame.GetVReg(inst->VRegC_23x()));
+                         SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                 shadow_frame.GetVReg(inst->VRegC_23x())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
@@ -1722,22 +1738,22 @@
 
   HANDLE_INSTRUCTION_START(ADD_LONG)
     shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) +
-                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                             SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SUB_LONG)
     shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) -
-                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                             SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(MUL_LONG)
     shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) *
-                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                             SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
@@ -1872,8 +1888,8 @@
   HANDLE_INSTRUCTION_START(ADD_INT_2ADDR) {
     uint32_t vregA = inst->VRegA_12x(inst_data);
     shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) +
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+                         SafeAdd(shadow_frame.GetVReg(vregA),
+                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
     ADVANCE(1);
   }
   HANDLE_INSTRUCTION_END();
@@ -1881,8 +1897,8 @@
   HANDLE_INSTRUCTION_START(SUB_INT_2ADDR) {
     uint32_t vregA = inst->VRegA_12x(inst_data);
     shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) -
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+                         SafeSub(shadow_frame.GetVReg(vregA),
+                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
     ADVANCE(1);
   }
   HANDLE_INSTRUCTION_END();
@@ -1890,8 +1906,8 @@
   HANDLE_INSTRUCTION_START(MUL_INT_2ADDR) {
     uint32_t vregA = inst->VRegA_12x(inst_data);
     shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) *
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+                         SafeMul(shadow_frame.GetVReg(vregA),
+                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
     ADVANCE(1);
   }
   HANDLE_INSTRUCTION_END();
@@ -1969,8 +1985,8 @@
   HANDLE_INSTRUCTION_START(ADD_LONG_2ADDR) {
     uint32_t vregA = inst->VRegA_12x(inst_data);
     shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) +
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+                             SafeAdd(shadow_frame.GetVRegLong(vregA),
+                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
     ADVANCE(1);
   }
   HANDLE_INSTRUCTION_END();
@@ -1978,8 +1994,8 @@
   HANDLE_INSTRUCTION_START(SUB_LONG_2ADDR) {
     uint32_t vregA = inst->VRegA_12x(inst_data);
     shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) -
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+                             SafeSub(shadow_frame.GetVRegLong(vregA),
+                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
     ADVANCE(1);
   }
   HANDLE_INSTRUCTION_END();
@@ -1987,8 +2003,8 @@
   HANDLE_INSTRUCTION_START(MUL_LONG_2ADDR) {
     uint32_t vregA = inst->VRegA_12x(inst_data);
     shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) *
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+                             SafeMul(shadow_frame.GetVRegLong(vregA),
+                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
     ADVANCE(1);
   }
   HANDLE_INSTRUCTION_END();
@@ -2155,22 +2171,22 @@
 
   HANDLE_INSTRUCTION_START(ADD_INT_LIT16)
     shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) +
-                         inst->VRegC_22s());
+                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+                                 inst->VRegC_22s()));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(RSUB_INT)
     shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         inst->VRegC_22s() -
-                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)));
+                         SafeSub(inst->VRegC_22s(),
+                                 shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(MUL_INT_LIT16)
     shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) *
-                         inst->VRegC_22s());
+                         SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+                                 inst->VRegC_22s()));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
@@ -2211,22 +2227,22 @@
 
   HANDLE_INSTRUCTION_START(ADD_INT_LIT8)
     shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) +
-                         inst->VRegC_22b());
+                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()),
+                                 inst->VRegC_22b()));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(RSUB_INT_LIT8)
     shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         inst->VRegC_22b() -
-                         shadow_frame.GetVReg(inst->VRegB_22b()));
+                         SafeSub(inst->VRegC_22b(),
+                                 shadow_frame.GetVReg(inst->VRegB_22b())));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(MUL_INT_LIT8)
     shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) *
-                         inst->VRegC_22b());
+                         SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()),
+                                 inst->VRegC_22b()));
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
@@ -2287,103 +2303,87 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_3E)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_3F)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_40)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_41)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_42)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_43)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_79)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_7A)
-    UnexpectedOpcode(inst, mh);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_EF)
-    UnexpectedOpcode(inst, mh);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F0)
-    UnexpectedOpcode(inst, mh);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F1)
-    UnexpectedOpcode(inst, mh);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F2)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F3)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F4)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F5)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F6)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F7)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F8)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_F9)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_FA)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_FB)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_FC)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_FD)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_FE)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(UNUSED_FF)
-    UnexpectedOpcode(inst, mh);
+    UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
   exception_pending_label: {
@@ -2438,21 +2438,17 @@
 
 // Explicit definitions of ExecuteGotoImpl.
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
-                                    const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
                                     ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
-                                     const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
                                      ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
-                                    const DexFile::CodeItem* code_item,
+JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
+                                   ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
                                     ShadowFrame& shadow_frame, JValue result_register);
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
-                                     const DexFile::CodeItem* code_item,
-                                     ShadowFrame& shadow_frame, JValue result_register);
 
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index c6cef6a..38665c7 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -15,6 +15,7 @@
  */
 
 #include "interpreter_common.h"
+#include "safe_math.h"
 
 namespace art {
 namespace interpreter {
@@ -56,7 +57,7 @@
   } while (false)
 
 template<bool do_access_check, bool transaction_active>
-JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
                          ShadowFrame& shadow_frame, JValue result_register) {
   bool do_assignability_check = do_access_check;
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
@@ -81,7 +82,7 @@
   while (true) {
     dex_pc = inst->GetDexPc(insns);
     shadow_frame.SetDexPC(dex_pc);
-    TraceExecution(shadow_frame, inst, dex_pc, mh);
+    TraceExecution(shadow_frame, inst, dex_pc);
     inst_data = inst->Fetch16(0);
     switch (inst->Opcode(inst_data)) {
       case Instruction::NOP:
@@ -233,9 +234,7 @@
         const size_t ref_idx = inst->VRegA_11x(inst_data);
         Object* obj_result = shadow_frame.GetVRegReference(ref_idx);
         if (do_assignability_check && obj_result != NULL) {
-          StackHandleScope<1> hs(self);
-          MethodHelper mhs(hs.NewHandle(shadow_frame.GetMethod()));
-          Class* return_type = mhs.GetReturnType();
+          Class* return_type = shadow_frame.GetMethod()->GetReturnType();
           // Re-load since it might have moved.
           obj_result = shadow_frame.GetVRegReference(ref_idx);
           if (return_type == NULL) {
@@ -331,7 +330,7 @@
         break;
       case Instruction::CONST_STRING: {
         PREAMBLE();
-        String* s = ResolveString(self, mh,  inst->VRegB_21c());
+        String* s = ResolveString(self, shadow_frame,  inst->VRegB_21c());
         if (UNLIKELY(s == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -342,7 +341,7 @@
       }
       case Instruction::CONST_STRING_JUMBO: {
         PREAMBLE();
-        String* s = ResolveString(self, mh,  inst->VRegB_31c());
+        String* s = ResolveString(self, shadow_frame,  inst->VRegB_31c());
         if (UNLIKELY(s == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -456,7 +455,7 @@
         PREAMBLE();
         int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
         Object* obj = AllocArrayFromCode<do_access_check, true>(
-            inst->VRegC_22c(), shadow_frame.GetMethod(), length, self,
+            inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
             Runtime::Current()->GetHeap()->GetCurrentAllocator());
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
@@ -484,30 +483,18 @@
       }
       case Instruction::FILL_ARRAY_DATA: {
         PREAMBLE();
-        Object* obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
-        if (UNLIKELY(obj == NULL)) {
-          ThrowNullPointerException(NULL, "null array in FILL_ARRAY_DATA");
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        Array* array = obj->AsArray();
-        DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
         const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
         const Instruction::ArrayDataPayload* payload =
             reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
-        if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
-          self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
-                                   "Ljava/lang/ArrayIndexOutOfBoundsException;",
-                                   "failed FILL_ARRAY_DATA; length=%d, index=%d",
-                                   array->GetLength(), payload->element_count);
+        Object* obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
+        bool success = FillArrayData(obj, payload);
+        if (!success) {
           HANDLE_PENDING_EXCEPTION();
           break;
         }
         if (transaction_active) {
-          RecordArrayElementsInTransaction(array, payload->element_count);
+          RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
         }
-        uint32_t size_in_bytes = payload->element_count * payload->element_width;
-        memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
         inst = inst->Next_3xx();
         break;
       }
@@ -574,6 +561,12 @@
         inst = inst->RelativeAt(offset);
         break;
       }
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
       case Instruction::CMPL_FLOAT: {
         PREAMBLE();
         float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
@@ -639,6 +632,11 @@
         inst = inst->Next_2xx();
         break;
       }
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
       case Instruction::CMP_LONG: {
         PREAMBLE();
         int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
@@ -1130,6 +1128,30 @@
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
+      case Instruction::IGET_BOOLEAN_QUICK: {
+        PREAMBLE();
+        bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
+      case Instruction::IGET_BYTE_QUICK: {
+        PREAMBLE();
+        bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
+      case Instruction::IGET_CHAR_QUICK: {
+        PREAMBLE();
+        bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
+      case Instruction::IGET_SHORT_QUICK: {
+        PREAMBLE();
+        bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
       case Instruction::SGET_BOOLEAN: {
         PREAMBLE();
         bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
@@ -1498,25 +1520,26 @@
                              static_cast<int16_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
-      case Instruction::ADD_INT:
+      case Instruction::ADD_INT: {
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) +
-                             shadow_frame.GetVReg(inst->VRegC_23x()));
+                             SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                     shadow_frame.GetVReg(inst->VRegC_23x())));
         inst = inst->Next_2xx();
         break;
+      }
       case Instruction::SUB_INT:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) -
-                             shadow_frame.GetVReg(inst->VRegC_23x()));
+                             SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                     shadow_frame.GetVReg(inst->VRegC_23x())));
         inst = inst->Next_2xx();
         break;
       case Instruction::MUL_INT:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) *
-                             shadow_frame.GetVReg(inst->VRegC_23x()));
+                             SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                     shadow_frame.GetVReg(inst->VRegC_23x())));
         inst = inst->Next_2xx();
         break;
       case Instruction::DIV_INT: {
@@ -1580,29 +1603,29 @@
       case Instruction::ADD_LONG:
         PREAMBLE();
         shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) +
-                                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                                 SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                         shadow_frame.GetVRegLong(inst->VRegC_23x())));
         inst = inst->Next_2xx();
         break;
       case Instruction::SUB_LONG:
         PREAMBLE();
         shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) -
-                                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                                 SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                         shadow_frame.GetVRegLong(inst->VRegC_23x())));
         inst = inst->Next_2xx();
         break;
       case Instruction::MUL_LONG:
         PREAMBLE();
         shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) *
-                                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                                 SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                         shadow_frame.GetVRegLong(inst->VRegC_23x())));
         inst = inst->Next_2xx();
         break;
       case Instruction::DIV_LONG:
         PREAMBLE();
         DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
                      shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                    shadow_frame.GetVRegLong(inst->VRegC_23x()));
+                     shadow_frame.GetVRegLong(inst->VRegC_23x()));
         POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
         break;
       case Instruction::REM_LONG:
@@ -1727,9 +1750,8 @@
       case Instruction::ADD_INT_2ADDR: {
         PREAMBLE();
         uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) +
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+        shadow_frame.SetVReg(vregA, SafeAdd(shadow_frame.GetVReg(vregA),
+                                            shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
       }
@@ -1737,8 +1759,8 @@
         PREAMBLE();
         uint4_t vregA = inst->VRegA_12x(inst_data);
         shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) -
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+                             SafeSub(shadow_frame.GetVReg(vregA),
+                                     shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
       }
@@ -1746,8 +1768,8 @@
         PREAMBLE();
         uint4_t vregA = inst->VRegA_12x(inst_data);
         shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) *
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+                             SafeMul(shadow_frame.GetVReg(vregA),
+                                     shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
       }
@@ -1825,8 +1847,8 @@
         PREAMBLE();
         uint4_t vregA = inst->VRegA_12x(inst_data);
         shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) +
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+                                 SafeAdd(shadow_frame.GetVRegLong(vregA),
+                                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
       }
@@ -1834,8 +1856,8 @@
         PREAMBLE();
         uint4_t vregA = inst->VRegA_12x(inst_data);
         shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) -
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+                                 SafeSub(shadow_frame.GetVRegLong(vregA),
+                                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
       }
@@ -1843,8 +1865,8 @@
         PREAMBLE();
         uint4_t vregA = inst->VRegA_12x(inst_data);
         shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) *
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+                                 SafeMul(shadow_frame.GetVRegLong(vregA),
+                                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
         inst = inst->Next_1xx();
         break;
       }
@@ -2011,22 +2033,22 @@
       case Instruction::ADD_INT_LIT16:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) +
-                             inst->VRegC_22s());
+                             SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+                                     inst->VRegC_22s()));
         inst = inst->Next_2xx();
         break;
-      case Instruction::RSUB_INT:
+      case Instruction::RSUB_INT_LIT16:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             inst->VRegC_22s() -
-                             shadow_frame.GetVReg(inst->VRegB_22s(inst_data)));
+                             SafeSub(inst->VRegC_22s(),
+                                     shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
         inst = inst->Next_2xx();
         break;
       case Instruction::MUL_INT_LIT16:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) *
-                             inst->VRegC_22s());
+                             SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+                                     inst->VRegC_22s()));
         inst = inst->Next_2xx();
         break;
       case Instruction::DIV_INT_LIT16: {
@@ -2067,22 +2089,19 @@
       case Instruction::ADD_INT_LIT8:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) +
-                             inst->VRegC_22b());
+                             SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
         inst = inst->Next_2xx();
         break;
       case Instruction::RSUB_INT_LIT8:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             inst->VRegC_22b() -
-                             shadow_frame.GetVReg(inst->VRegB_22b()));
+                             SafeSub(inst->VRegC_22b(), shadow_frame.GetVReg(inst->VRegB_22b())));
         inst = inst->Next_2xx();
         break;
       case Instruction::MUL_INT_LIT8:
         PREAMBLE();
         shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) *
-                             inst->VRegC_22b());
+                             SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
         inst = inst->Next_2xx();
         break;
       case Instruction::DIV_INT_LIT8: {
@@ -2142,30 +2161,26 @@
         inst = inst->Next_2xx();
         break;
       case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
-      case Instruction::UNUSED_EF ... Instruction::UNUSED_FF:
+      case Instruction::UNUSED_F3 ... Instruction::UNUSED_FF:
       case Instruction::UNUSED_79:
       case Instruction::UNUSED_7A:
-        UnexpectedOpcode(inst, mh);
+        UnexpectedOpcode(inst, shadow_frame);
     }
   }
 }  // NOLINT(readability/fn_size)
 
 // Explicit definitions of ExecuteSwitchImpl.
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<true, false>(Thread* self, MethodHelper& mh,
-                                      const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
                                       ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<false, false>(Thread* self, MethodHelper& mh,
-                                       const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
                                        ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteSwitchImpl<true, true>(Thread* self, MethodHelper& mh,
-                                     const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
                                      ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-JValue ExecuteSwitchImpl<false, true>(Thread* self, MethodHelper& mh,
-                                      const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
                                       ShadowFrame& shadow_frame, JValue result_register);
 
 }  // namespace interpreter
diff --git a/runtime/interpreter/safe_math.h b/runtime/interpreter/safe_math.h
new file mode 100644
index 0000000..78b3539
--- /dev/null
+++ b/runtime/interpreter/safe_math.h
@@ -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.
+ */
+
+#ifndef ART_RUNTIME_INTERPRETER_SAFE_MATH_H_
+#define ART_RUNTIME_INTERPRETER_SAFE_MATH_H_
+
+#include <functional>
+#include <type_traits>
+
+namespace art {
+namespace interpreter {
+
+// Declares a type which is the larger in bit size of the two template parameters.
+template <typename T1, typename T2>
+struct select_bigger {
+  typedef typename std::conditional<sizeof(T1) >= sizeof(T2), T1, T2>::type type;
+};
+
+// Perform signed arithmetic Op on 'a' and 'b' with defined wrapping behavior.
+template<template <typename OpT> class Op, typename T1, typename T2>
+static inline typename select_bigger<T1, T2>::type SafeMath(T1 a, T2 b) {
+  typedef typename select_bigger<T1, T2>::type biggest_T;
+  typedef typename std::make_unsigned<biggest_T>::type unsigned_biggest_T;
+  static_assert(std::is_signed<T1>::value, "Expected T1 to be signed");
+  static_assert(std::is_signed<T2>::value, "Expected T2 to be signed");
+  unsigned_biggest_T val1 = static_cast<unsigned_biggest_T>(static_cast<biggest_T>(a));
+  unsigned_biggest_T val2 = static_cast<unsigned_biggest_T>(b);
+  return static_cast<biggest_T>(Op<unsigned_biggest_T>()(val1, val2));
+}
+
+// Perform signed a signed add on 'a' and 'b' with defined wrapping behavior.
+template<typename T1, typename T2>
+static inline typename select_bigger<T1, T2>::type SafeAdd(T1 a, T2 b) {
+  return SafeMath<std::plus>(a, b);
+}
+
+// Perform signed a signed substract on 'a' and 'b' with defined wrapping behavior.
+template<typename T1, typename T2>
+static inline typename select_bigger<T1, T2>::type SafeSub(T1 a, T2 b) {
+  return SafeMath<std::minus>(a, b);
+}
+
+// Perform signed a signed multiply on 'a' and 'b' with defined wrapping behavior.
+template<typename T1, typename T2>
+static inline typename select_bigger<T1, T2>::type SafeMul(T1 a, T2 b) {
+  return SafeMath<std::multiplies>(a, b);
+}
+
+}  // namespace interpreter
+}  // namespace art
+
+#endif  // ART_RUNTIME_INTERPRETER_SAFE_MATH_H_
diff --git a/runtime/interpreter/safe_math_test.cc b/runtime/interpreter/safe_math_test.cc
new file mode 100644
index 0000000..28087a3
--- /dev/null
+++ b/runtime/interpreter/safe_math_test.cc
@@ -0,0 +1,132 @@
+/*
+ * 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 "safe_math.h"
+
+#include <limits>
+
+#include "gtest/gtest.h"
+
+namespace art {
+namespace interpreter {
+
+TEST(SafeMath, Add) {
+  // Adding 1 overflows 0x7ff... to 0x800... aka max and min.
+  EXPECT_EQ(SafeAdd(std::numeric_limits<int32_t>::max(), 1),
+            std::numeric_limits<int32_t>::min());
+  EXPECT_EQ(SafeAdd(std::numeric_limits<int64_t>::max(), 1),
+            std::numeric_limits<int64_t>::min());
+
+  // Vanilla arithmetic should work too.
+  EXPECT_EQ(SafeAdd(std::numeric_limits<int32_t>::max() - 1, 1),
+            std::numeric_limits<int32_t>::max());
+  EXPECT_EQ(SafeAdd(std::numeric_limits<int64_t>::max() - 1, 1),
+            std::numeric_limits<int64_t>::max());
+
+  EXPECT_EQ(SafeAdd(std::numeric_limits<int32_t>::min() + 1, -1),
+            std::numeric_limits<int32_t>::min());
+  EXPECT_EQ(SafeAdd(std::numeric_limits<int64_t>::min() + 1, -1),
+            std::numeric_limits<int64_t>::min());
+
+  EXPECT_EQ(SafeAdd(int32_t(-1), -1), -2);
+  EXPECT_EQ(SafeAdd(int64_t(-1), -1), -2);
+
+  EXPECT_EQ(SafeAdd(int32_t(1), 1), 2);
+  EXPECT_EQ(SafeAdd(int64_t(1), 1), 2);
+
+  EXPECT_EQ(SafeAdd(int32_t(-1), 1), 0);
+  EXPECT_EQ(SafeAdd(int64_t(-1), 1), 0);
+
+  EXPECT_EQ(SafeAdd(int32_t(1), -1), 0);
+  EXPECT_EQ(SafeAdd(int64_t(1), -1), 0);
+
+  // Test sign extension of smaller operand sizes.
+  EXPECT_EQ(SafeAdd(int32_t(1), int8_t(-1)), 0);
+  EXPECT_EQ(SafeAdd(int64_t(1), int8_t(-1)), 0);
+}
+
+TEST(SafeMath, Sub) {
+  // Subtracting 1 underflows 0x800... to 0x7ff... aka min and max.
+  EXPECT_EQ(SafeSub(std::numeric_limits<int32_t>::min(), 1),
+            std::numeric_limits<int32_t>::max());
+  EXPECT_EQ(SafeSub(std::numeric_limits<int64_t>::min(), 1),
+            std::numeric_limits<int64_t>::max());
+
+  // Vanilla arithmetic should work too.
+  EXPECT_EQ(SafeSub(std::numeric_limits<int32_t>::max() - 1, -1),
+            std::numeric_limits<int32_t>::max());
+  EXPECT_EQ(SafeSub(std::numeric_limits<int64_t>::max() - 1, -1),
+            std::numeric_limits<int64_t>::max());
+
+  EXPECT_EQ(SafeSub(std::numeric_limits<int32_t>::min() + 1, 1),
+            std::numeric_limits<int32_t>::min());
+  EXPECT_EQ(SafeSub(std::numeric_limits<int64_t>::min() + 1, 1),
+            std::numeric_limits<int64_t>::min());
+
+  EXPECT_EQ(SafeSub(int32_t(-1), -1), 0);
+  EXPECT_EQ(SafeSub(int64_t(-1), -1), 0);
+
+  EXPECT_EQ(SafeSub(int32_t(1), 1), 0);
+  EXPECT_EQ(SafeSub(int64_t(1), 1), 0);
+
+  EXPECT_EQ(SafeSub(int32_t(-1), 1), -2);
+  EXPECT_EQ(SafeSub(int64_t(-1), 1), -2);
+
+  EXPECT_EQ(SafeSub(int32_t(1), -1), 2);
+  EXPECT_EQ(SafeSub(int64_t(1), -1), 2);
+
+  // Test sign extension of smaller operand sizes.
+  EXPECT_EQ(SafeAdd(int32_t(1), int8_t(-1)), 0);
+  EXPECT_EQ(SafeAdd(int64_t(1), int8_t(-1)), 0);
+}
+
+TEST(SafeMath, Mul) {
+  // Multiplying by 2 overflows 0x7ff...f to 0xfff...e aka max and -2.
+  EXPECT_EQ(SafeMul(std::numeric_limits<int32_t>::max(), 2),
+            -2);
+  EXPECT_EQ(SafeMul(std::numeric_limits<int64_t>::max(), 2),
+            -2);
+
+  // Vanilla arithmetic should work too.
+  EXPECT_EQ(SafeMul(std::numeric_limits<int32_t>::max() / 2, 2),
+            std::numeric_limits<int32_t>::max() - 1);  // -1 as LSB is lost by division.
+  EXPECT_EQ(SafeMul(std::numeric_limits<int64_t>::max() / 2, 2),
+            std::numeric_limits<int64_t>::max() - 1);  // -1 as LSB is lost by division.
+
+  EXPECT_EQ(SafeMul(std::numeric_limits<int32_t>::min() / 2, 2),
+            std::numeric_limits<int32_t>::min());
+  EXPECT_EQ(SafeMul(std::numeric_limits<int64_t>::min() / 2, 2),
+            std::numeric_limits<int64_t>::min());
+
+  EXPECT_EQ(SafeMul(int32_t(-1), -1), 1);
+  EXPECT_EQ(SafeMul(int64_t(-1), -1), 1);
+
+  EXPECT_EQ(SafeMul(int32_t(1), 1), 1);
+  EXPECT_EQ(SafeMul(int64_t(1), 1), 1);
+
+  EXPECT_EQ(SafeMul(int32_t(-1), 1), -1);
+  EXPECT_EQ(SafeMul(int64_t(-1), 1), -1);
+
+  EXPECT_EQ(SafeMul(int32_t(1), -1), -1);
+  EXPECT_EQ(SafeMul(int64_t(1), -1), -1);
+
+  // Test sign extension of smaller operand sizes.
+  EXPECT_EQ(SafeMul(int32_t(1), int8_t(-1)), -1);
+  EXPECT_EQ(SafeMul(int64_t(1), int8_t(-1)), -1);
+}
+
+}  // namespace interpreter
+}  // namespace art
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 1444d97..4643d14 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -18,9 +18,12 @@
 
 #include <dlfcn.h>
 
+#include "base/dumpable.h"
 #include "base/mutex.h"
 #include "base/stl_util.h"
 #include "check_jni.h"
+#include "dex_file-inl.h"
+#include "fault_handler.h"
 #include "indirect_reference_table-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/class-inl.h"
@@ -245,7 +248,7 @@
   }
 
  private:
-  AllocationTrackingSafeMap<std::string, SharedLibrary*, kAllocatorTagJNILibrarires> libraries_;
+  AllocationTrackingSafeMap<std::string, SharedLibrary*, kAllocatorTagJNILibraries> libraries_;
 };
 
 
@@ -688,6 +691,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) {
@@ -750,12 +757,15 @@
   }
 }
 
+void JavaVMExt::TrimGlobals() {
+  WriterMutexLock mu(Thread::Current(), globals_lock_);
+  globals_.Trim();
+}
+
 void JavaVMExt::VisitRoots(RootCallback* callback, void* arg) {
   Thread* self = Thread::Current();
-  {
-    ReaderMutexLock mu(self, globals_lock_);
-    globals_.VisitRoots(callback, arg, 0, kRootJNIGlobal);
-  }
+  ReaderMutexLock mu(self, globals_lock_);
+  globals_.VisitRoots(callback, arg, RootInfo(kRootJNIGlobal));
   // The weak_globals table is visited by the GC itself (because it mutates the table).
 }
 
@@ -789,13 +799,13 @@
   return JNI_OK;
 }
 
-extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize, jsize* vm_count) {
+extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms_buf, jsize buf_len, jsize* vm_count) {
   Runtime* runtime = Runtime::Current();
-  if (runtime == nullptr) {
+  if (runtime == nullptr || buf_len == 0) {
     *vm_count = 0;
   } else {
     *vm_count = 1;
-    vms[0] = runtime->GetJavaVM();
+    vms_buf[0] = runtime->GetJavaVM();
   }
   return JNI_OK;
 }
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 2957ba3..749b9fb 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -131,6 +131,9 @@
     return unchecked_functions_;
   }
 
+  void TrimGlobals() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(globals_lock_);
+
  private:
   Runtime* const runtime_;
 
diff --git a/runtime/java_vm_ext_test.cc b/runtime/java_vm_ext_test.cc
new file mode 100644
index 0000000..2cbfa81
--- /dev/null
+++ b/runtime/java_vm_ext_test.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+
+#include <pthread.h>
+
+#include "common_runtime_test.h"
+#include "java_vm_ext.h"
+#include "runtime.h"
+
+namespace art {
+
+class JavaVmExtTest : public CommonRuntimeTest {
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTest::SetUp();
+
+    vm_ = Runtime::Current()->GetJavaVM();
+  }
+
+
+  virtual void TearDown() OVERRIDE {
+    CommonRuntimeTest::TearDown();
+  }
+
+  JavaVMExt* vm_;
+};
+
+TEST_F(JavaVmExtTest, JNI_GetDefaultJavaVMInitArgs) {
+  jint err = JNI_GetDefaultJavaVMInitArgs(nullptr);
+  EXPECT_EQ(JNI_ERR, err);
+}
+
+TEST_F(JavaVmExtTest, JNI_GetCreatedJavaVMs) {
+  JavaVM* vms_buf[1];
+  jsize num_vms;
+  jint ok = JNI_GetCreatedJavaVMs(vms_buf, arraysize(vms_buf), &num_vms);
+  EXPECT_EQ(JNI_OK, ok);
+  EXPECT_EQ(1, num_vms);
+  EXPECT_EQ(vms_buf[0], vm_);
+}
+
+static bool gSmallStack = false;
+static bool gAsDaemon = false;
+
+static void* attach_current_thread_callback(void* arg ATTRIBUTE_UNUSED) {
+  JavaVM* vms_buf[1];
+  jsize num_vms;
+  JNIEnv* env;
+  jint ok = JNI_GetCreatedJavaVMs(vms_buf, arraysize(vms_buf), &num_vms);
+  EXPECT_EQ(JNI_OK, ok);
+  if (ok == JNI_OK) {
+    if (!gAsDaemon) {
+      ok = vms_buf[0]->AttachCurrentThread(&env, nullptr);
+    } else {
+      ok = vms_buf[0]->AttachCurrentThreadAsDaemon(&env, nullptr);
+    }
+    // TODO: Find a way to test with exact SMALL_STACK value, for which we would bail. The pthreads
+    //       spec says that the stack size argument is a lower bound, and bionic currently gives us
+    //       a chunk more on arm64.
+    if (!gSmallStack) {
+      EXPECT_EQ(JNI_OK, ok);
+    }
+    if (ok == JNI_OK) {
+      ok = vms_buf[0]->DetachCurrentThread();
+      EXPECT_EQ(JNI_OK, ok);
+    }
+  }
+  return nullptr;
+}
+
+TEST_F(JavaVmExtTest, AttachCurrentThread) {
+  pthread_t pthread;
+  const char* reason = __PRETTY_FUNCTION__;
+  gSmallStack = false;
+  gAsDaemon = false;
+  CHECK_PTHREAD_CALL(pthread_create, (&pthread, nullptr, attach_current_thread_callback,
+      nullptr), reason);
+  void* ret_val;
+  CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
+  EXPECT_EQ(ret_val, nullptr);
+}
+
+TEST_F(JavaVmExtTest, AttachCurrentThreadAsDaemon) {
+  pthread_t pthread;
+  const char* reason = __PRETTY_FUNCTION__;
+  gSmallStack = false;
+  gAsDaemon = true;
+  CHECK_PTHREAD_CALL(pthread_create, (&pthread, nullptr, attach_current_thread_callback,
+      nullptr), reason);
+  void* ret_val;
+  CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
+  EXPECT_EQ(ret_val, nullptr);
+}
+
+TEST_F(JavaVmExtTest, AttachCurrentThread_SmallStack) {
+  pthread_t pthread;
+  pthread_attr_t attr;
+  const char* reason = __PRETTY_FUNCTION__;
+  gSmallStack = true;
+  gAsDaemon = false;
+  CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
+  CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, PTHREAD_STACK_MIN), reason);
+  CHECK_PTHREAD_CALL(pthread_create, (&pthread, &attr, attach_current_thread_callback,
+      nullptr), reason);
+  CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
+  void* ret_val;
+  CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
+  EXPECT_EQ(ret_val, nullptr);
+}
+
+TEST_F(JavaVmExtTest, DetachCurrentThread) {
+  JNIEnv* env;
+  jint ok = vm_->AttachCurrentThread(&env, nullptr);
+  ASSERT_EQ(JNI_OK, ok);
+  ok = vm_->DetachCurrentThread();
+  EXPECT_EQ(JNI_OK, ok);
+
+  jint err = vm_->DetachCurrentThread();
+  EXPECT_EQ(JNI_ERR, err);
+}
+
+}  // namespace art
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 0c9451c..9309ab5 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -27,6 +27,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
+#include <vector>
 
 struct iovec;
 
@@ -188,7 +189,7 @@
    * The VM has finished initializing.  Only called when the debugger is
    * connected at the time initialization completes.
    */
-  bool PostVMStart() LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void PostVMStart() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
    * A location of interest has been reached.  This is used for breakpoints,
@@ -202,7 +203,7 @@
    *
    * "returnValue" is non-null for MethodExit events only.
    */
-  bool PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, int eventFlags,
+  void PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, int eventFlags,
                          const JValue* returnValue)
      LOCKS_EXCLUDED(event_list_lock_)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -214,7 +215,7 @@
    * "fieldValue" is non-null for field modification events only.
    * "is_modification" is true for field modification, false for field access.
    */
-  bool PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, mirror::Object* thisPtr,
+  void PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, mirror::Object* thisPtr,
                       const JValue* fieldValue, bool is_modification)
       LOCKS_EXCLUDED(event_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -224,7 +225,7 @@
    *
    * Pass in a zeroed-out "*pCatchLoc" if the exception wasn't caught.
    */
-  bool PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
+  void PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
                      const EventLocation* pCatchLoc, mirror::Object* thisPtr)
       LOCKS_EXCLUDED(event_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -232,14 +233,14 @@
   /*
    * A thread has started or stopped.
    */
-  bool PostThreadChange(Thread* thread, bool start)
+  void PostThreadChange(Thread* thread, bool start)
       LOCKS_EXCLUDED(event_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
    * Class has been prepared.
    */
-  bool PostClassPrepare(mirror::Class* klass)
+  void PostClassPrepare(mirror::Class* klass)
       LOCKS_EXCLUDED(event_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -251,6 +252,9 @@
   // Called if/when we realize we're talking to DDMS.
   void NotifyDdmsActive() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+
+  void SetupChunkHeader(uint32_t type, size_t data_len, size_t header_size, uint8_t* out_header);
+
   /*
    * Send up a chunk of DDM data.
    */
@@ -307,15 +311,16 @@
   void SendRequestAndPossiblySuspend(ExpandBuf* pReq, JdwpSuspendPolicy suspend_policy,
                                      ObjectId threadId)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CleanupMatchList(JdwpEvent** match_list,
-                        size_t match_count)
+  void CleanupMatchList(const std::vector<JdwpEvent*>& match_list)
       EXCLUSIVE_LOCKS_REQUIRED(event_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void EventFinish(ExpandBuf* pReq);
-  void FindMatchingEvents(JdwpEventKind eventKind,
-                          const ModBasket& basket,
-                          JdwpEvent** match_list,
-                          size_t* pMatchCount)
+  bool FindMatchingEvents(JdwpEventKind eventKind, const ModBasket& basket,
+                          std::vector<JdwpEvent*>* match_list)
+      LOCKS_EXCLUDED(event_list_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FindMatchingEventsLocked(JdwpEventKind eventKind, const ModBasket& basket,
+                                std::vector<JdwpEvent*>* match_list)
       EXCLUSIVE_LOCKS_REQUIRED(event_list_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UnregisterEvent(JdwpEvent* pEvent)
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index fe91bb6..adc2912 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -84,13 +84,13 @@
     shutting_down_ = true;
 
     int control_sock = this->control_sock_;
-    int clientSock = this->clientSock;
+    int local_clientSock = this->clientSock;
 
     /* clear these out so it doesn't wake up and try to reuse them */
     this->control_sock_ = this->clientSock = -1;
 
-    if (clientSock != -1) {
-      shutdown(clientSock, SHUT_RDWR);
+    if (local_clientSock != -1) {
+      shutdown(local_clientSock, SHUT_RDWR);
     }
 
     if (control_sock != -1) {
@@ -123,7 +123,7 @@
 bool InitAdbTransport(JdwpState* state, const JdwpOptions*) {
   VLOG(jdwp) << "ADB transport startup";
   state->netState = new JdwpAdbState(state);
-  return (state->netState != NULL);
+  return (state->netState != nullptr);
 }
 
 /*
@@ -145,7 +145,7 @@
   iov.iov_len        = 1;
 
   msghdr msg;
-  msg.msg_name       = NULL;
+  msg.msg_name       = nullptr;
   msg.msg_namelen    = 0;
   msg.msg_iov        = &iov;
   msg.msg_iovlen     = 1;
@@ -352,7 +352,7 @@
        * re-issue the select.  We're currently using #2, as it's more
        * reliable than #1 and generally better than #3.  Wastes two fds.
        */
-      selCount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+      selCount = select(maxfd + 1, &readfds, nullptr, nullptr, nullptr);
       if (selCount < 0) {
         if (errno == EINTR) {
           continue;
diff --git a/runtime/jdwp/jdwp_bits.h b/runtime/jdwp/jdwp_bits.h
index 9f80cbe..f9cf9ca 100644
--- a/runtime/jdwp/jdwp_bits.h
+++ b/runtime/jdwp/jdwp_bits.h
@@ -68,7 +68,7 @@
 
 // @deprecated
 static inline void Set1(uint8_t* buf, uint8_t val) {
-  *buf = (uint8_t)(val);
+  *buf = val;
 }
 
 // @deprecated
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 7c8c63c..a8eaa26 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -125,6 +125,10 @@
 };
 
 static bool NeedsFullDeoptimization(JdwpEventKind eventKind) {
+  if (!Dbg::RequiresDeoptimization()) {
+    // We don't need deoptimization for debugging.
+    return false;
+  }
   switch (eventKind) {
       case EK_METHOD_ENTRY:
       case EK_METHOD_EXIT:
@@ -138,7 +142,7 @@
     }
 }
 
-uint32_t GetInstrumentationEventFor(JdwpEventKind eventKind) {
+static uint32_t GetInstrumentationEventFor(JdwpEventKind eventKind) {
   switch (eventKind) {
     case EK_BREAKPOINT:
     case EK_SINGLE_STEP:
@@ -168,9 +172,9 @@
  * not be added to the list, and an appropriate error will be returned.
  */
 JdwpError JdwpState::RegisterEvent(JdwpEvent* pEvent) {
-  CHECK(pEvent != NULL);
-  CHECK(pEvent->prev == NULL);
-  CHECK(pEvent->next == NULL);
+  CHECK(pEvent != nullptr);
+  CHECK(pEvent->prev == nullptr);
+  CHECK(pEvent->next == nullptr);
 
   {
     /*
@@ -181,8 +185,14 @@
     for (int i = 0; i < pEvent->modCount; i++) {
       const JdwpEventMod* pMod = &pEvent->mods[i];
       if (pMod->modKind == MK_LOCATION_ONLY) {
-        /* should only be for Breakpoint, Step, and Exception */
-        Dbg::WatchLocation(&pMod->locationOnly.loc, &req);
+        // Should only concern breakpoint, field access, field modification, step, and exception
+        // events.
+        // However breakpoint requires specific handling. Field access, field modification and step
+        // events need full deoptimization to be reported while exception event is reported during
+        // exception handling.
+        if (pEvent->eventKind == EK_BREAKPOINT) {
+          Dbg::WatchLocation(&pMod->locationOnly.loc, &req);
+        }
       } else if (pMod->modKind == MK_STEP) {
         /* should only be for EK_SINGLE_STEP; should only be one */
         JdwpStepSize size = static_cast<JdwpStepSize>(pMod->step.size);
@@ -213,7 +223,7 @@
      * Add to list.
      */
     MutexLock mu(Thread::Current(), event_list_lock_);
-    if (event_list_ != NULL) {
+    if (event_list_ != nullptr) {
       pEvent->next = event_list_;
       event_list_->prev = pEvent;
     }
@@ -235,7 +245,7 @@
  * Grab the eventLock before calling here.
  */
 void JdwpState::UnregisterEvent(JdwpEvent* pEvent) {
-  if (pEvent->prev == NULL) {
+  if (pEvent->prev == nullptr) {
     /* head of the list */
     CHECK(event_list_ == pEvent);
 
@@ -244,11 +254,11 @@
     pEvent->prev->next = pEvent->next;
   }
 
-  if (pEvent->next != NULL) {
+  if (pEvent->next != nullptr) {
     pEvent->next->prev = pEvent->prev;
-    pEvent->next = NULL;
+    pEvent->next = nullptr;
   }
-  pEvent->prev = NULL;
+  pEvent->prev = nullptr;
 
   {
     /*
@@ -258,8 +268,10 @@
     for (int i = 0; i < pEvent->modCount; i++) {
       JdwpEventMod* pMod = &pEvent->mods[i];
       if (pMod->modKind == MK_LOCATION_ONLY) {
-        /* should only be for Breakpoint, Step, and Exception */
-        Dbg::UnwatchLocation(&pMod->locationOnly.loc, &req);
+        // Like in RegisterEvent, we need specific handling for breakpoint only.
+        if (pEvent->eventKind == EK_BREAKPOINT) {
+          Dbg::UnwatchLocation(&pMod->locationOnly.loc, &req);
+        }
       }
       if (pMod->modKind == MK_STEP) {
         /* should only be for EK_SINGLE_STEP; should only be one */
@@ -291,7 +303,7 @@
   }
 
   --event_list_size_;
-  CHECK(event_list_size_ != 0 || event_list_ == NULL);
+  CHECK(event_list_size_ != 0 || event_list_ == nullptr);
 }
 
 /*
@@ -331,7 +343,7 @@
   MutexLock mu(Thread::Current(), event_list_lock_);
 
   JdwpEvent* pEvent = event_list_;
-  while (pEvent != NULL) {
+  while (pEvent != nullptr) {
     JdwpEvent* pNextEvent = pEvent->next;
 
     UnregisterEvent(pEvent);
@@ -339,7 +351,7 @@
     pEvent = pNextEvent;
   }
 
-  event_list_ = NULL;
+  event_list_ = nullptr;
 }
 
 /*
@@ -360,13 +372,13 @@
  * Do not call this until the event has been removed from the list.
  */
 void EventFree(JdwpEvent* pEvent) {
-  if (pEvent == NULL) {
+  if (pEvent == nullptr) {
     return;
   }
 
   /* make sure it was removed from the list */
-  CHECK(pEvent->prev == NULL);
-  CHECK(pEvent->next == NULL);
+  CHECK(pEvent->prev == nullptr);
+  CHECK(pEvent->next == nullptr);
   /* want to check state->event_list_ != pEvent */
 
   /*
@@ -375,11 +387,11 @@
   for (int i = 0; i < pEvent->modCount; i++) {
     if (pEvent->mods[i].modKind == MK_CLASS_MATCH) {
       free(pEvent->mods[i].classMatch.classPattern);
-      pEvent->mods[i].classMatch.classPattern = NULL;
+      pEvent->mods[i].classMatch.classPattern = nullptr;
     }
     if (pEvent->mods[i].modKind == MK_CLASS_EXCLUDE) {
       free(pEvent->mods[i].classExclude.classPattern);
-      pEvent->mods[i].classExclude.classPattern = NULL;
+      pEvent->mods[i].classExclude.classPattern = nullptr;
     }
   }
 
@@ -387,26 +399,12 @@
 }
 
 /*
- * Allocate storage for matching events.  To keep things simple we
- * use an array with enough storage for the entire list.
- *
- * The state->eventLock should be held before calling.
- */
-static JdwpEvent** AllocMatchList(size_t event_count) {
-  return new JdwpEvent*[event_count];
-}
-
-/*
  * Run through the list and remove any entries with an expired "count" mod
- * from the event list, then free the match list.
+ * from the event list.
  */
-void JdwpState::CleanupMatchList(JdwpEvent** match_list, size_t match_count) {
-  JdwpEvent** ppEvent = match_list;
-
-  while (match_count--) {
-    JdwpEvent* pEvent = *ppEvent;
-
-    for (int i = 0; i < pEvent->modCount; i++) {
+void JdwpState::CleanupMatchList(const std::vector<JdwpEvent*>& match_list) {
+  for (JdwpEvent* pEvent : match_list) {
+    for (int i = 0; i < pEvent->modCount; ++i) {
       if (pEvent->mods[i].modKind == MK_COUNT && pEvent->mods[i].count.count == 0) {
         VLOG(jdwp) << StringPrintf("##### Removing expired event (requestId=%#" PRIx32 ")",
                                    pEvent->requestId);
@@ -415,11 +413,7 @@
         break;
       }
     }
-
-    ppEvent++;
   }
-
-  delete[] match_list;
 }
 
 /*
@@ -524,40 +518,55 @@
 }
 
 /*
- * Find all events of type "eventKind" with mods that match up with the
- * rest of the arguments.
+ * Find all events of type "event_kind" with mods that match up with the
+ * rest of the arguments while holding the event list lock. This method
+ * is used by FindMatchingEvents below.
  *
- * Found events are appended to "match_list", and "*pMatchCount" is advanced,
- * so this may be called multiple times for grouped events.
+ * Found events are appended to "match_list" so this may be called multiple times for grouped
+ * events.
  *
  * DO NOT call this multiple times for the same eventKind, as Count mods are
  * decremented during the scan.
  */
-void JdwpState::FindMatchingEvents(JdwpEventKind eventKind, const ModBasket& basket,
-                                   JdwpEvent** match_list, size_t* pMatchCount) {
-  /* start after the existing entries */
-  match_list += *pMatchCount;
-
+void JdwpState::FindMatchingEventsLocked(JdwpEventKind event_kind, const ModBasket& basket,
+                                         std::vector<JdwpEvent*>* match_list) {
   for (JdwpEvent* pEvent = event_list_; pEvent != nullptr; pEvent = pEvent->next) {
-    if (pEvent->eventKind == eventKind && ModsMatch(pEvent, basket)) {
-      *match_list++ = pEvent;
-      (*pMatchCount)++;
+    if (pEvent->eventKind == event_kind && ModsMatch(pEvent, basket)) {
+      match_list->push_back(pEvent);
     }
   }
 }
 
 /*
+ * Find all events of type "event_kind" with mods that match up with the
+ * rest of the arguments and return true if at least one event matches,
+ * false otherwise.
+ *
+ * Found events are appended to "match_list" so this may be called multiple
+ * times for grouped events.
+ *
+ * DO NOT call this multiple times for the same eventKind, as Count mods are
+ * decremented during the scan.
+ */
+bool JdwpState::FindMatchingEvents(JdwpEventKind event_kind, const ModBasket& basket,
+                                   std::vector<JdwpEvent*>* match_list) {
+  MutexLock mu(Thread::Current(), event_list_lock_);
+  match_list->reserve(event_list_size_);
+  FindMatchingEventsLocked(event_kind, basket, match_list);
+  return !match_list->empty();
+}
+
+/*
  * Scan through the list of matches and determine the most severe
  * suspension policy.
  */
-static JdwpSuspendPolicy scanSuspendPolicy(JdwpEvent** match_list, int match_count) {
+static JdwpSuspendPolicy ScanSuspendPolicy(const std::vector<JdwpEvent*>& match_list) {
   JdwpSuspendPolicy policy = SP_NONE;
 
-  while (match_count--) {
-    if ((*match_list)->suspend_policy > policy) {
-      policy = (*match_list)->suspend_policy;
+  for (JdwpEvent* pEvent : match_list) {
+    if (pEvent->suspend_policy > policy) {
+      policy = pEvent->suspend_policy;
     }
-    match_list++;
   }
 
   return policy;
@@ -614,19 +623,18 @@
 
 void JdwpState::SendRequestAndPossiblySuspend(ExpandBuf* pReq, JdwpSuspendPolicy suspend_policy,
                                               ObjectId threadId) {
-  Thread* self = Thread::Current();
+  Thread* const self = Thread::Current();
   self->AssertThreadSuspensionIsAllowable();
+  CHECK(pReq != nullptr);
   /* send request and possibly suspend ourselves */
-  if (pReq != NULL) {
-    JDWP::ObjectId thread_self_id = Dbg::GetThreadSelfId();
-    self->TransitionFromRunnableToSuspended(kWaitingForDebuggerSend);
-    if (suspend_policy != SP_NONE) {
-      SetWaitForEventThread(threadId);
-    }
-    EventFinish(pReq);
-    SuspendByPolicy(suspend_policy, thread_self_id);
-    self->TransitionFromSuspendedToRunnable();
+  JDWP::ObjectId thread_self_id = Dbg::GetThreadSelfId();
+  self->TransitionFromRunnableToSuspended(kWaitingForDebuggerSend);
+  if (suspend_policy != SP_NONE) {
+    SetWaitForEventThread(threadId);
   }
+  EventFinish(pReq);
+  SuspendByPolicy(suspend_policy, thread_self_id);
+  self->TransitionFromSuspendedToRunnable();
 }
 
 /*
@@ -717,10 +725,10 @@
   uint8_t* buf = expandBufGetBuffer(pReq);
 
   Set4BE(buf, expandBufGetLength(pReq));
-  Set4BE(buf+4, NextRequestSerial());
-  Set1(buf+8, 0);     /* flags */
-  Set1(buf+9, kJdwpEventCommandSet);
-  Set1(buf+10, kJdwpCompositeCommand);
+  Set4BE(buf + 4, NextRequestSerial());
+  Set1(buf + 8, 0);     /* flags */
+  Set1(buf + 9, kJdwpEventCommandSet);
+  Set1(buf + 10, kJdwpCompositeCommand);
 
   // Prevents from interleaving commands and events. Otherwise we could end up in sending an event
   // before sending the reply of the command being processed and would lead to bad synchronization
@@ -741,43 +749,30 @@
  * any application code has been executed".  The thread ID in the message
  * must be for the main thread.
  */
-bool JdwpState::PostVMStart() {
-  JdwpSuspendPolicy suspend_policy;
+void JdwpState::PostVMStart() {
+  JdwpSuspendPolicy suspend_policy = (options_->suspend) ? SP_ALL : SP_NONE;
   ObjectId threadId = Dbg::GetThreadSelfId();
 
-  if (options_->suspend) {
-    suspend_policy = SP_ALL;
-  } else {
-    suspend_policy = SP_NONE;
-  }
+  VLOG(jdwp) << "EVENT: " << EK_VM_START;
+  VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
 
   ExpandBuf* pReq = eventPrep();
-  {
-    MutexLock mu(Thread::Current(), event_list_lock_);  // probably don't need this here
-
-    VLOG(jdwp) << "EVENT: " << EK_VM_START;
-    VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
-
-    expandBufAdd1(pReq, suspend_policy);
-    expandBufAdd4BE(pReq, 1);
-
-    expandBufAdd1(pReq, EK_VM_START);
-    expandBufAdd4BE(pReq, 0);       /* requestId */
-    expandBufAdd8BE(pReq, threadId);
-  }
+  expandBufAdd1(pReq, suspend_policy);
+  expandBufAdd4BE(pReq, 1);
+  expandBufAdd1(pReq, EK_VM_START);
+  expandBufAdd4BE(pReq, 0);       /* requestId */
+  expandBufAddObjectId(pReq, threadId);
 
   Dbg::ManageDeoptimization();
 
   /* send request and possibly suspend ourselves */
   SendRequestAndPossiblySuspend(pReq, suspend_policy, threadId);
-
-  return true;
 }
 
-static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_count,
+static void LogMatchingEventsAndThread(const std::vector<JdwpEvent*> match_list,
                                        ObjectId thread_id)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  for (size_t i = 0; i < match_count; ++i) {
+  for (size_t i = 0, e = match_list.size(); i < e; ++i) {
     JdwpEvent* pEvent = match_list[i];
     VLOG(jdwp) << "EVENT #" << i << ": " << pEvent->eventKind
                << StringPrintf(" (requestId=%#" PRIx32 ")", pEvent->requestId);
@@ -819,7 +814,7 @@
  *  - Single-step to a line with a breakpoint.  Should get a single
  *    event message with both events in it.
  */
-bool JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr,
+void JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr,
                                   int eventFlags, const JValue* returnValue) {
   DCHECK(pLoc != nullptr);
   DCHECK(pLoc->method != nullptr);
@@ -840,7 +835,7 @@
    */
   if (basket.thread == GetDebugThread()) {
     VLOG(jdwp) << "Ignoring location event in JDWP thread";
-    return false;
+    return;
   }
 
   /*
@@ -854,73 +849,69 @@
    */
   if (InvokeInProgress()) {
     VLOG(jdwp) << "Not checking breakpoints during invoke (" << basket.className << ")";
-    return false;
+    return;
   }
 
-  size_t match_count = 0;
-  ExpandBuf* pReq = NULL;
-  JdwpSuspendPolicy suspend_policy = SP_NONE;
-  JdwpEvent** match_list = nullptr;
-  ObjectId thread_id = 0;
+  std::vector<JdwpEvent*> match_list;
   {
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      match_list = AllocMatchList(event_list_size_);
-      if ((eventFlags & Dbg::kBreakpoint) != 0) {
-        FindMatchingEvents(EK_BREAKPOINT, basket, match_list, &match_count);
-      }
-      if ((eventFlags & Dbg::kSingleStep) != 0) {
-        FindMatchingEvents(EK_SINGLE_STEP, basket, match_list, &match_count);
-      }
-      if ((eventFlags & Dbg::kMethodEntry) != 0) {
-        FindMatchingEvents(EK_METHOD_ENTRY, basket, match_list, &match_count);
-      }
-      if ((eventFlags & Dbg::kMethodExit) != 0) {
-        FindMatchingEvents(EK_METHOD_EXIT, basket, match_list, &match_count);
-        FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, match_list, &match_count);
-      }
+    // We use the locked version because we have multiple possible match events.
+    MutexLock mu(Thread::Current(), event_list_lock_);
+    match_list.reserve(event_list_size_);
+    if ((eventFlags & Dbg::kBreakpoint) != 0) {
+      FindMatchingEventsLocked(EK_BREAKPOINT, basket, &match_list);
     }
-    if (match_count != 0) {
-      suspend_policy = scanSuspendPolicy(match_list, match_count);
-
-      thread_id = Dbg::GetThreadId(basket.thread);
-      JDWP::JdwpLocation jdwp_location;
-      SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
-
-      if (VLOG_IS_ON(jdwp)) {
-        LogMatchingEventsAndThread(match_list, match_count, thread_id);
-        VLOG(jdwp) << "  location=" << jdwp_location;
-        VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
-      }
-
-      pReq = eventPrep();
-      expandBufAdd1(pReq, suspend_policy);
-      expandBufAdd4BE(pReq, match_count);
-
-      for (size_t i = 0; i < match_count; i++) {
-        expandBufAdd1(pReq, match_list[i]->eventKind);
-        expandBufAdd4BE(pReq, match_list[i]->requestId);
-        expandBufAdd8BE(pReq, thread_id);
-        expandBufAddLocation(pReq, jdwp_location);
-        if (match_list[i]->eventKind == EK_METHOD_EXIT_WITH_RETURN_VALUE) {
-          Dbg::OutputMethodReturnValue(jdwp_location.method_id, returnValue, pReq);
-        }
-      }
+    if ((eventFlags & Dbg::kSingleStep) != 0) {
+      FindMatchingEventsLocked(EK_SINGLE_STEP, basket, &match_list);
     }
-
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      CleanupMatchList(match_list, match_count);
+    if ((eventFlags & Dbg::kMethodEntry) != 0) {
+      FindMatchingEventsLocked(EK_METHOD_ENTRY, basket, &match_list);
     }
+    if ((eventFlags & Dbg::kMethodExit) != 0) {
+      FindMatchingEventsLocked(EK_METHOD_EXIT, basket, &match_list);
+      FindMatchingEventsLocked(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, &match_list);
+    }
+  }
+  if (match_list.empty()) {
+    // No matching event.
+    return;
+  }
+  JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+
+  ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+  JDWP::JdwpLocation jdwp_location;
+  SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
+
+  if (VLOG_IS_ON(jdwp)) {
+    LogMatchingEventsAndThread(match_list, thread_id);
+    VLOG(jdwp) << "  location=" << jdwp_location;
+    VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
+  }
+
+  ExpandBuf* pReq = eventPrep();
+  expandBufAdd1(pReq, suspend_policy);
+  expandBufAdd4BE(pReq, match_list.size());
+
+  for (const JdwpEvent* pEvent : match_list) {
+    expandBufAdd1(pReq, pEvent->eventKind);
+    expandBufAdd4BE(pReq, pEvent->requestId);
+    expandBufAddObjectId(pReq, thread_id);
+    expandBufAddLocation(pReq, jdwp_location);
+    if (pEvent->eventKind == EK_METHOD_EXIT_WITH_RETURN_VALUE) {
+      Dbg::OutputMethodReturnValue(jdwp_location.method_id, returnValue, pReq);
+    }
+  }
+
+  {
+    MutexLock mu(Thread::Current(), event_list_lock_);
+    CleanupMatchList(match_list);
   }
 
   Dbg::ManageDeoptimization();
 
   SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-  return match_count != 0;
 }
 
-bool JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field,
+void JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field,
                                mirror::Object* this_object, const JValue* fieldValue,
                                bool is_modification) {
   DCHECK(pLoc != nullptr);
@@ -938,86 +929,73 @@
 
   if (InvokeInProgress()) {
     VLOG(jdwp) << "Not posting field event during invoke";
-    return false;
+    return;
   }
 
-  size_t match_count = 0;
-  ExpandBuf* pReq = NULL;
-  JdwpSuspendPolicy suspend_policy = SP_NONE;
-  JdwpEvent** match_list = nullptr;
-  ObjectId thread_id = 0;
+  std::vector<JdwpEvent*> match_list;
+  const JdwpEventKind match_kind = (is_modification) ? EK_FIELD_MODIFICATION : EK_FIELD_ACCESS;
+  if (!FindMatchingEvents(match_kind, basket, &match_list)) {
+    // No matching event.
+    return;
+  }
+
+  JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+  ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+  ObjectRegistry* registry = Dbg::GetObjectRegistry();
+  ObjectId instance_id = registry->Add(basket.thisPtr);
+  RefTypeId field_type_id = registry->AddRefType(field->GetDeclaringClass());
+  FieldId field_id = Dbg::ToFieldId(field);
+  JDWP::JdwpLocation jdwp_location;
+  SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
+
+  if (VLOG_IS_ON(jdwp)) {
+    LogMatchingEventsAndThread(match_list, thread_id);
+    VLOG(jdwp) << "  location=" << jdwp_location;
+    VLOG(jdwp) << StringPrintf("  this=%#" PRIx64, instance_id);
+    VLOG(jdwp) << StringPrintf("  type=%#" PRIx64, field_type_id) << " "
+        << Dbg::GetClassName(field_id);
+    VLOG(jdwp) << StringPrintf("  field=%#" PRIx32, field_id) << " "
+        << Dbg::GetFieldName(field_id);
+    VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
+  }
+
+  ExpandBuf* pReq = eventPrep();
+  expandBufAdd1(pReq, suspend_policy);
+  expandBufAdd4BE(pReq, match_list.size());
+
+  // Get field's reference type tag.
+  JDWP::JdwpTypeTag type_tag = Dbg::GetTypeTag(field->GetDeclaringClass());
+
+  // Get instance type tag.
+  uint8_t tag;
   {
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      match_list = AllocMatchList(event_list_size_);
-      if (is_modification) {
-        FindMatchingEvents(EK_FIELD_MODIFICATION, basket, match_list, &match_count);
-      } else {
-        FindMatchingEvents(EK_FIELD_ACCESS, basket, match_list, &match_count);
-      }
+    ScopedObjectAccessUnchecked soa(Thread::Current());
+    tag = Dbg::TagFromObject(soa, basket.thisPtr);
+  }
+
+  for (const JdwpEvent* pEvent : match_list) {
+    expandBufAdd1(pReq, pEvent->eventKind);
+    expandBufAdd4BE(pReq, pEvent->requestId);
+    expandBufAddObjectId(pReq, thread_id);
+    expandBufAddLocation(pReq, jdwp_location);
+    expandBufAdd1(pReq, type_tag);
+    expandBufAddRefTypeId(pReq, field_type_id);
+    expandBufAddFieldId(pReq, field_id);
+    expandBufAdd1(pReq, tag);
+    expandBufAddObjectId(pReq, instance_id);
+    if (is_modification) {
+      Dbg::OutputFieldValue(field_id, fieldValue, pReq);
     }
-    if (match_count != 0) {
-      suspend_policy = scanSuspendPolicy(match_list, match_count);
+  }
 
-      thread_id = Dbg::GetThreadId(basket.thread);
-      ObjectRegistry* registry = Dbg::GetObjectRegistry();
-      ObjectId instance_id = registry->Add(basket.thisPtr);
-      RefTypeId field_type_id = registry->AddRefType(field->GetDeclaringClass());
-      FieldId field_id = Dbg::ToFieldId(field);
-      JDWP::JdwpLocation jdwp_location;
-      SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
-
-      if (VLOG_IS_ON(jdwp)) {
-        LogMatchingEventsAndThread(match_list, match_count, thread_id);
-        VLOG(jdwp) << "  location=" << jdwp_location;
-        VLOG(jdwp) << StringPrintf("  this=%#" PRIx64, instance_id);
-        VLOG(jdwp) << StringPrintf("  type=%#" PRIx64, field_type_id) << " "
-                   << Dbg::GetClassName(field_id);
-        VLOG(jdwp) << StringPrintf("  field=%#" PRIx32, field_id) << " "
-                   << Dbg::GetFieldName(field_id);
-        VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
-      }
-
-      pReq = eventPrep();
-      expandBufAdd1(pReq, suspend_policy);
-      expandBufAdd4BE(pReq, match_count);
-
-      // Get field's reference type tag.
-      JDWP::JdwpTypeTag type_tag = Dbg::GetTypeTag(field->GetDeclaringClass());
-
-      // Get instance type tag.
-      uint8_t tag;
-      {
-        ScopedObjectAccessUnchecked soa(Thread::Current());
-        tag = Dbg::TagFromObject(soa, basket.thisPtr);
-      }
-
-      for (size_t i = 0; i < match_count; i++) {
-        expandBufAdd1(pReq, match_list[i]->eventKind);
-        expandBufAdd4BE(pReq, match_list[i]->requestId);
-        expandBufAdd8BE(pReq, thread_id);
-        expandBufAddLocation(pReq, jdwp_location);
-        expandBufAdd1(pReq, type_tag);
-        expandBufAddRefTypeId(pReq, field_type_id);
-        expandBufAddFieldId(pReq, field_id);
-        expandBufAdd1(pReq, tag);
-        expandBufAddObjectId(pReq, instance_id);
-        if (is_modification) {
-          Dbg::OutputFieldValue(field_id, fieldValue, pReq);
-        }
-      }
-    }
-
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      CleanupMatchList(match_list, match_count);
-    }
+  {
+    MutexLock mu(Thread::Current(), event_list_lock_);
+    CleanupMatchList(match_list);
   }
 
   Dbg::ManageDeoptimization();
 
   SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-  return match_count != 0;
 }
 
 /*
@@ -1026,7 +1004,7 @@
  * Valid mods:
  *  Count, ThreadOnly
  */
-bool JdwpState::PostThreadChange(Thread* thread, bool start) {
+void JdwpState::PostThreadChange(Thread* thread, bool start) {
   CHECK_EQ(thread, Thread::Current());
 
   /*
@@ -1034,61 +1012,53 @@
    */
   if (InvokeInProgress()) {
     LOG(WARNING) << "Not posting thread change during invoke";
-    return false;
+    return;
+  }
+
+  // We need the java.lang.Thread object associated to the starting/ending
+  // thread to get its JDWP id. Therefore we can't report event if there
+  // is no Java peer. This happens when the runtime shuts down and re-attaches
+  // the current thread without creating a Java peer.
+  if (thread->GetPeer() == nullptr) {
+    return;
   }
 
   ModBasket basket;
   basket.thread = thread;
 
-  ExpandBuf* pReq = NULL;
-  JdwpSuspendPolicy suspend_policy = SP_NONE;
-  JdwpEvent** match_list = nullptr;
-  size_t match_count = 0;
-  ObjectId thread_id = 0;
+  std::vector<JdwpEvent*> match_list;
+  const JdwpEventKind match_kind = (start) ? EK_THREAD_START : EK_THREAD_DEATH;
+  if (!FindMatchingEvents(match_kind, basket, &match_list)) {
+    // No matching event.
+    return;
+  }
+
+  JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+  ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+
+  if (VLOG_IS_ON(jdwp)) {
+    LogMatchingEventsAndThread(match_list, thread_id);
+    VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
+  }
+
+  ExpandBuf* pReq = eventPrep();
+  expandBufAdd1(pReq, suspend_policy);
+  expandBufAdd4BE(pReq, match_list.size());
+
+  for (const JdwpEvent* pEvent : match_list) {
+    expandBufAdd1(pReq, pEvent->eventKind);
+    expandBufAdd4BE(pReq, pEvent->requestId);
+    expandBufAdd8BE(pReq, thread_id);
+  }
+
   {
-    {
-      // Don't allow the list to be updated while we scan it.
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      match_list = AllocMatchList(event_list_size_);
-      if (start) {
-        FindMatchingEvents(EK_THREAD_START, basket, match_list, &match_count);
-      } else {
-        FindMatchingEvents(EK_THREAD_DEATH, basket, match_list, &match_count);
-      }
-    }
-
-    if (match_count != 0) {
-      suspend_policy = scanSuspendPolicy(match_list, match_count);
-
-      thread_id = Dbg::GetThreadId(basket.thread);
-
-      if (VLOG_IS_ON(jdwp)) {
-        LogMatchingEventsAndThread(match_list, match_count, thread_id);
-        VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
-      }
-
-      pReq = eventPrep();
-      expandBufAdd1(pReq, suspend_policy);
-      expandBufAdd4BE(pReq, match_count);
-
-      for (size_t i = 0; i < match_count; i++) {
-        expandBufAdd1(pReq, match_list[i]->eventKind);
-        expandBufAdd4BE(pReq, match_list[i]->requestId);
-        expandBufAdd8BE(pReq, thread_id);
-      }
-    }
-
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      CleanupMatchList(match_list, match_count);
-    }
+    MutexLock mu(Thread::Current(), event_list_lock_);
+    CleanupMatchList(match_list);
   }
 
   Dbg::ManageDeoptimization();
 
   SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-
-  return match_count != 0;
 }
 
 /*
@@ -1120,7 +1090,7 @@
  * because there's a pretty good chance that we're not going to send it
  * up the debugger.
  */
-bool JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
+void JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
                               const EventLocation* pCatchLoc, mirror::Object* thisPtr) {
   DCHECK(exception_object != nullptr);
   DCHECK(pThrowLoc != nullptr);
@@ -1147,72 +1117,61 @@
   /* don't try to post an exception caused by the debugger */
   if (InvokeInProgress()) {
     VLOG(jdwp) << "Not posting exception hit during invoke (" << basket.className << ")";
-    return false;
+    return;
   }
 
-  size_t match_count = 0;
-  ExpandBuf* pReq = NULL;
-  JdwpSuspendPolicy suspend_policy = SP_NONE;
-  JdwpEvent** match_list = nullptr;
-  ObjectId thread_id = 0;
+  std::vector<JdwpEvent*> match_list;
+  if (!FindMatchingEvents(EK_EXCEPTION, basket, &match_list)) {
+    // No matching event.
+    return;
+  }
+
+  JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+  ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+  ObjectRegistry* registry = Dbg::GetObjectRegistry();
+  ObjectId exceptionId = registry->Add(exception_object);
+  JDWP::JdwpLocation jdwp_throw_location;
+  JDWP::JdwpLocation jdwp_catch_location;
+  SetJdwpLocationFromEventLocation(pThrowLoc, &jdwp_throw_location);
+  SetJdwpLocationFromEventLocation(pCatchLoc, &jdwp_catch_location);
+
+  if (VLOG_IS_ON(jdwp)) {
+    std::string exceptionClassName(PrettyDescriptor(exception_object->GetClass()));
+
+    LogMatchingEventsAndThread(match_list, thread_id);
+    VLOG(jdwp) << "  throwLocation=" << jdwp_throw_location;
+    if (jdwp_catch_location.class_id == 0) {
+      VLOG(jdwp) << "  catchLocation=uncaught";
+    } else {
+      VLOG(jdwp) << "  catchLocation=" << jdwp_catch_location;
+    }
+    VLOG(jdwp) << StringPrintf("  exception=%#" PRIx64, exceptionId) << " "
+        << exceptionClassName;
+    VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
+  }
+
+  ExpandBuf* pReq = eventPrep();
+  expandBufAdd1(pReq, suspend_policy);
+  expandBufAdd4BE(pReq, match_list.size());
+
+  for (const JdwpEvent* pEvent : match_list) {
+    expandBufAdd1(pReq, pEvent->eventKind);
+    expandBufAdd4BE(pReq, pEvent->requestId);
+    expandBufAddObjectId(pReq, thread_id);
+    expandBufAddLocation(pReq, jdwp_throw_location);
+    expandBufAdd1(pReq, JT_OBJECT);
+    expandBufAddObjectId(pReq, exceptionId);
+    expandBufAddLocation(pReq, jdwp_catch_location);
+  }
+
   {
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      match_list = AllocMatchList(event_list_size_);
-      FindMatchingEvents(EK_EXCEPTION, basket, match_list, &match_count);
-    }
-    if (match_count != 0) {
-      suspend_policy = scanSuspendPolicy(match_list, match_count);
-
-      thread_id = Dbg::GetThreadId(basket.thread);
-      ObjectRegistry* registry = Dbg::GetObjectRegistry();
-      ObjectId exceptionId = registry->Add(exception_object);
-      JDWP::JdwpLocation jdwp_throw_location;
-      JDWP::JdwpLocation jdwp_catch_location;
-      SetJdwpLocationFromEventLocation(pThrowLoc, &jdwp_throw_location);
-      SetJdwpLocationFromEventLocation(pCatchLoc, &jdwp_catch_location);
-
-      if (VLOG_IS_ON(jdwp)) {
-        std::string exceptionClassName(PrettyDescriptor(exception_object->GetClass()));
-
-        LogMatchingEventsAndThread(match_list, match_count, thread_id);
-        VLOG(jdwp) << "  throwLocation=" << jdwp_throw_location;
-        if (jdwp_catch_location.class_id == 0) {
-          VLOG(jdwp) << "  catchLocation=uncaught";
-        } else {
-          VLOG(jdwp) << "  catchLocation=" << jdwp_catch_location;
-        }
-        VLOG(jdwp) << StringPrintf("  exception=%#" PRIx64, exceptionId) << " "
-                   << exceptionClassName;
-        VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
-      }
-
-      pReq = eventPrep();
-      expandBufAdd1(pReq, suspend_policy);
-      expandBufAdd4BE(pReq, match_count);
-
-      for (size_t i = 0; i < match_count; i++) {
-        expandBufAdd1(pReq, match_list[i]->eventKind);
-        expandBufAdd4BE(pReq, match_list[i]->requestId);
-        expandBufAdd8BE(pReq, thread_id);
-        expandBufAddLocation(pReq, jdwp_throw_location);
-        expandBufAdd1(pReq, JT_OBJECT);
-        expandBufAdd8BE(pReq, exceptionId);
-        expandBufAddLocation(pReq, jdwp_catch_location);
-      }
-    }
-
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      CleanupMatchList(match_list, match_count);
-    }
+    MutexLock mu(Thread::Current(), event_list_lock_);
+    CleanupMatchList(match_list);
   }
 
   Dbg::ManageDeoptimization();
 
   SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-
-  return match_count != 0;
 }
 
 /*
@@ -1221,7 +1180,7 @@
  * Valid mods:
  *  Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude
  */
-bool JdwpState::PostClassPrepare(mirror::Class* klass) {
+void JdwpState::PostClassPrepare(mirror::Class* klass) {
   DCHECK(klass != nullptr);
 
   ModBasket basket;
@@ -1232,80 +1191,85 @@
   /* suppress class prep caused by debugger */
   if (InvokeInProgress()) {
     VLOG(jdwp) << "Not posting class prep caused by invoke (" << basket.className << ")";
-    return false;
+    return;
   }
 
-  ExpandBuf* pReq = NULL;
-  JdwpSuspendPolicy suspend_policy = SP_NONE;
-  JdwpEvent** match_list = nullptr;
-  size_t match_count = 0;
-  ObjectId thread_id = 0;
+  std::vector<JdwpEvent*> match_list;
+  if (!FindMatchingEvents(EK_CLASS_PREPARE, basket, &match_list)) {
+    // No matching event.
+    return;
+  }
+
+  JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+  ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+  ObjectRegistry* registry = Dbg::GetObjectRegistry();
+  RefTypeId class_id = registry->AddRefType(basket.locationClass);
+
+  // OLD-TODO - we currently always send both "verified" and "prepared" since
+  // debuggers seem to like that.  There might be some advantage to honesty,
+  // since the class may not yet be verified.
+  int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
+  JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass);
+  std::string temp;
+  std::string signature(basket.locationClass->GetDescriptor(&temp));
+
+  if (VLOG_IS_ON(jdwp)) {
+    LogMatchingEventsAndThread(match_list, thread_id);
+    VLOG(jdwp) << StringPrintf("  type=%#" PRIx64, class_id) << " " << signature;
+    VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
+  }
+
+  if (thread_id == debug_thread_id_) {
+    /*
+     * JDWP says that, for a class prep in the debugger thread, we
+     * should set thread to null and if any threads were supposed
+     * to be suspended then we suspend all other threads.
+     */
+    VLOG(jdwp) << "  NOTE: class prepare in debugger thread!";
+    thread_id = 0;
+    if (suspend_policy == SP_EVENT_THREAD) {
+      suspend_policy = SP_ALL;
+    }
+  }
+
+  ExpandBuf* pReq = eventPrep();
+  expandBufAdd1(pReq, suspend_policy);
+  expandBufAdd4BE(pReq, match_list.size());
+
+  for (const JdwpEvent* pEvent : match_list) {
+    expandBufAdd1(pReq, pEvent->eventKind);
+    expandBufAdd4BE(pReq, pEvent->requestId);
+    expandBufAddObjectId(pReq, thread_id);
+    expandBufAdd1(pReq, tag);
+    expandBufAddRefTypeId(pReq, class_id);
+    expandBufAddUtf8String(pReq, signature);
+    expandBufAdd4BE(pReq, status);
+  }
+
   {
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      match_list = AllocMatchList(event_list_size_);
-      FindMatchingEvents(EK_CLASS_PREPARE, basket, match_list, &match_count);
-    }
-    if (match_count != 0) {
-      suspend_policy = scanSuspendPolicy(match_list, match_count);
-
-      thread_id = Dbg::GetThreadId(basket.thread);
-      ObjectRegistry* registry = Dbg::GetObjectRegistry();
-      RefTypeId class_id = registry->AddRefType(basket.locationClass);
-
-      // OLD-TODO - we currently always send both "verified" and "prepared" since
-      // debuggers seem to like that.  There might be some advantage to honesty,
-      // since the class may not yet be verified.
-      int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
-      JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass);
-      std::string temp;
-      std::string signature(basket.locationClass->GetDescriptor(&temp));
-
-      if (VLOG_IS_ON(jdwp)) {
-        LogMatchingEventsAndThread(match_list, match_count, thread_id);
-        VLOG(jdwp) << StringPrintf("  type=%#" PRIx64, class_id) << " " << signature;
-        VLOG(jdwp) << "  suspend_policy=" << suspend_policy;
-      }
-
-      if (thread_id == debug_thread_id_) {
-        /*
-         * JDWP says that, for a class prep in the debugger thread, we
-         * should set thread to null and if any threads were supposed
-         * to be suspended then we suspend all other threads.
-         */
-        VLOG(jdwp) << "  NOTE: class prepare in debugger thread!";
-        thread_id = 0;
-        if (suspend_policy == SP_EVENT_THREAD) {
-          suspend_policy = SP_ALL;
-        }
-      }
-
-      pReq = eventPrep();
-      expandBufAdd1(pReq, suspend_policy);
-      expandBufAdd4BE(pReq, match_count);
-
-      for (size_t i = 0; i < match_count; i++) {
-        expandBufAdd1(pReq, match_list[i]->eventKind);
-        expandBufAdd4BE(pReq, match_list[i]->requestId);
-        expandBufAdd8BE(pReq, thread_id);
-        expandBufAdd1(pReq, tag);
-        expandBufAdd8BE(pReq, class_id);
-        expandBufAddUtf8String(pReq, signature);
-        expandBufAdd4BE(pReq, status);
-      }
-    }
-
-    {
-      MutexLock mu(Thread::Current(), event_list_lock_);
-      CleanupMatchList(match_list, match_count);
-    }
+    MutexLock mu(Thread::Current(), event_list_lock_);
+    CleanupMatchList(match_list);
   }
 
   Dbg::ManageDeoptimization();
 
   SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
+}
 
-  return match_count != 0;
+/*
+ * Setup the header for a chunk of DDM data.
+ */
+void JdwpState::SetupChunkHeader(uint32_t type, size_t data_len, size_t header_size,
+                                 uint8_t* out_header) {
+  CHECK_EQ(header_size, static_cast<size_t>(kJDWPHeaderLen + 8));
+  /* form the header (JDWP plus DDMS) */
+  Set4BE(out_header, header_size + data_len);
+  Set4BE(out_header + 4, NextRequestSerial());
+  Set1(out_header + 8, 0);     /* flags */
+  Set1(out_header + 9, kJDWPDdmCmdSet);
+  Set1(out_header + 10, kJDWPDdmCmd);
+  Set4BE(out_header + 11, type);
+  Set4BE(out_header + 15, data_len);
 }
 
 /*
@@ -1316,10 +1280,10 @@
  * the fun event token gymnastics.
  */
 void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count) {
-  uint8_t header[kJDWPHeaderLen + 8];
+  uint8_t header[kJDWPHeaderLen + 8] = { 0 };
   size_t dataLen = 0;
 
-  CHECK(iov != NULL);
+  CHECK(iov != nullptr);
   CHECK_GT(iov_count, 0);
   CHECK_LT(iov_count, 10);
 
@@ -1334,14 +1298,7 @@
     dataLen += iov[i].iov_len;
   }
 
-  /* form the header (JDWP plus DDMS) */
-  Set4BE(header, sizeof(header) + dataLen);
-  Set4BE(header+4, NextRequestSerial());
-  Set1(header+8, 0);     /* flags */
-  Set1(header+9, kJDWPDdmCmdSet);
-  Set1(header+10, kJDWPDdmCmd);
-  Set4BE(header+11, type);
-  Set4BE(header+15, dataLen);
+  SetupChunkHeader(type, dataLen, sizeof(header), header);
 
   wrapiov[0].iov_base = header;
   wrapiov[0].iov_len = sizeof(header);
@@ -1352,7 +1309,7 @@
   bool safe_to_release_mutator_lock_over_send = !Locks::mutator_lock_->IsExclusiveHeld(self);
   if (safe_to_release_mutator_lock_over_send) {
     for (size_t i = 0; i < kMutatorLock; ++i) {
-      if (self->GetHeldMutex(static_cast<LockLevel>(i)) != NULL) {
+      if (self->GetHeldMutex(static_cast<LockLevel>(i)) != nullptr) {
         safe_to_release_mutator_lock_over_send = false;
         break;
       }
diff --git a/runtime/jdwp/jdwp_expand_buf.cc b/runtime/jdwp/jdwp_expand_buf.cc
index 0a64f28..cc85cdd 100644
--- a/runtime/jdwp/jdwp_expand_buf.cc
+++ b/runtime/jdwp/jdwp_expand_buf.cc
@@ -57,7 +57,7 @@
  * Free a JdwpBuf and associated storage.
  */
 void expandBufFree(ExpandBuf* pBuf) {
-  if (pBuf == NULL) {
+  if (pBuf == nullptr) {
     return;
   }
 
@@ -93,7 +93,7 @@
   }
 
   uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen));
-  if (newPtr == NULL) {
+  if (newPtr == nullptr) {
     LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
   }
 
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 16a774f..a1d2a6c 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -106,8 +106,8 @@
                              Dbg::GetMethodName(method_id).c_str());
   VLOG(jdwp) << StringPrintf("        %d args:", arg_count);
 
-  std::unique_ptr<JdwpTag[]> argTypes(arg_count > 0 ? new JdwpTag[arg_count] : NULL);
-  std::unique_ptr<uint64_t[]> argValues(arg_count > 0 ? new uint64_t[arg_count] : NULL);
+  std::unique_ptr<JdwpTag[]> argTypes(arg_count > 0 ? new JdwpTag[arg_count] : nullptr);
+  std::unique_ptr<uint64_t[]> argValues(arg_count > 0 ? new uint64_t[arg_count] : nullptr);
   for (int32_t i = 0; i < arg_count; ++i) {
     argTypes[i] = request->ReadTag();
     size_t width = Dbg::GetTagWidth(argTypes[i]);
@@ -124,7 +124,9 @@
   JdwpTag resultTag;
   uint64_t resultValue;
   ObjectId exceptObjId;
-  JdwpError err = Dbg::InvokeMethod(thread_id, object_id, class_id, method_id, arg_count, argValues.get(), argTypes.get(), options, &resultTag, &resultValue, &exceptObjId);
+  JdwpError err = Dbg::InvokeMethod(thread_id, object_id, class_id, method_id, arg_count,
+                                    argValues.get(), argTypes.get(), options, &resultTag,
+                                    &resultValue, &exceptObjId);
   if (err != ERR_NONE) {
     return err;
   }
@@ -203,7 +205,7 @@
     // Get class vs. interface and status flags.
     JDWP::JdwpTypeTag type_tag;
     uint32_t class_status;
-    JDWP::JdwpError status = Dbg::GetClassInfo(ids[i], &type_tag, &class_status, NULL);
+    JDWP::JdwpError status = Dbg::GetClassInfo(ids[i], &type_tag, &class_status, nullptr);
     if (status != ERR_NONE) {
       return status;
     }
@@ -329,17 +331,17 @@
   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]);
+  for (const std::string& str : class_path) {
+    expandBufAddUtf8String(pReply, str);
   }
 
   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]);
+  for (const std::string& str : boot_class_path) {
+    expandBufAddUtf8String(pReply, str);
   }
 
   return ERR_NONE;
@@ -371,7 +373,7 @@
 static JdwpError VM_CapabilitiesNew(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // The first few capabilities are the same as those reported by the older call.
-  VM_Capabilities(NULL, request, reply);
+  VM_Capabilities(nullptr, request, reply);
 
   expandBufAdd1(reply, false);   // canRedefineClasses
   expandBufAdd1(reply, false);   // canAddMethod
@@ -507,7 +509,7 @@
   RefTypeId refTypeId = request->ReadRefTypeId();
   JDWP::JdwpTypeTag type_tag;
   uint32_t class_status;
-  JDWP::JdwpError status = Dbg::GetClassInfo(refTypeId, &type_tag, &class_status, NULL);
+  JDWP::JdwpError status = Dbg::GetClassInfo(refTypeId, &type_tag, &class_status, nullptr);
   if (status != ERR_NONE) {
     return status;
   }
@@ -1126,6 +1128,7 @@
 
 static JdwpError TR_Interrupt(JdwpState*, Request* request, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  UNUSED(reply);
   ObjectId thread_id = request->ReadThreadId();
   return Dbg::Interrupt(thread_id);
 }
@@ -1344,8 +1347,10 @@
       }
       break;
     default:
-      LOG(WARNING) << "GLITCH: unsupported modKind=" << mod.modKind;
-      break;
+      LOG(WARNING) << "Unsupported modifier " << mod.modKind << " for event " << pEvent->eventKind;
+      // Free allocated event to avoid leak before leaving.
+      EventFree(pEvent);
+      return JDWP::ERR_NOT_IMPLEMENTED;
     }
   }
 
@@ -1429,7 +1434,7 @@
 static JdwpError DDM_Chunk(JdwpState* state, Request* request, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   state->NotifyDdmsActive();
-  uint8_t* replyBuf = NULL;
+  uint8_t* replyBuf = nullptr;
   int replyLen = -1;
   if (Dbg::DdmHandlePacket(request, &replyBuf, &replyLen)) {
     // If they want to send something back, we copy it into the buffer.
@@ -1478,11 +1483,11 @@
   { 1,    12, VM_Capabilities,          "VirtualMachine.Capabilities" },
   { 1,    13, VM_ClassPaths,            "VirtualMachine.ClassPaths" },
   { 1,    14, VM_DisposeObjects,        "VirtualMachine.DisposeObjects" },
-  { 1,    15, NULL,                     "VirtualMachine.HoldEvents" },
-  { 1,    16, NULL,                     "VirtualMachine.ReleaseEvents" },
+  { 1,    15, nullptr,                  "VirtualMachine.HoldEvents" },
+  { 1,    16, nullptr,                  "VirtualMachine.ReleaseEvents" },
   { 1,    17, VM_CapabilitiesNew,       "VirtualMachine.CapabilitiesNew" },
-  { 1,    18, NULL,                     "VirtualMachine.RedefineClasses" },
-  { 1,    19, NULL,                     "VirtualMachine.SetDefaultStratum" },
+  { 1,    18, nullptr,                  "VirtualMachine.RedefineClasses" },
+  { 1,    19, nullptr,                  "VirtualMachine.SetDefaultStratum" },
   { 1,    20, VM_AllClassesWithGeneric, "VirtualMachine.AllClassesWithGeneric" },
   { 1,    21, VM_InstanceCounts,        "VirtualMachine.InstanceCounts" },
 
@@ -1494,7 +1499,7 @@
   { 2,    5,  RT_Methods,              "ReferenceType.Methods" },
   { 2,    6,  RT_GetValues,            "ReferenceType.GetValues" },
   { 2,    7,  RT_SourceFile,           "ReferenceType.SourceFile" },
-  { 2,    8,  NULL,                    "ReferenceType.NestedTypes" },
+  { 2,    8,  nullptr,                 "ReferenceType.NestedTypes" },
   { 2,    9,  RT_Status,               "ReferenceType.Status" },
   { 2,    10, RT_Interfaces,           "ReferenceType.Interfaces" },
   { 2,    11, RT_ClassObject,          "ReferenceType.ClassObject" },
@@ -1503,8 +1508,8 @@
   { 2,    14, RT_FieldsWithGeneric,    "ReferenceType.FieldsWithGeneric" },
   { 2,    15, RT_MethodsWithGeneric,   "ReferenceType.MethodsWithGeneric" },
   { 2,    16, RT_Instances,            "ReferenceType.Instances" },
-  { 2,    17, NULL,                    "ReferenceType.ClassFileVersion" },
-  { 2,    18, NULL,                    "ReferenceType.ConstantPool" },
+  { 2,    17, nullptr,                 "ReferenceType.ClassFileVersion" },
+  { 2,    18, nullptr,                 "ReferenceType.ConstantPool" },
 
   /* ClassType command set (3) */
   { 3,    1,  CT_Superclass,    "ClassType.Superclass" },
@@ -1521,7 +1526,7 @@
   { 6,    1,  M_LineTable,                "Method.LineTable" },
   { 6,    2,  M_VariableTable,            "Method.VariableTable" },
   { 6,    3,  M_Bytecodes,                "Method.Bytecodes" },
-  { 6,    4,  NULL,                       "Method.IsObsolete" },
+  { 6,    4,  nullptr,                    "Method.IsObsolete" },
   { 6,    5,  M_VariableTableWithGeneric, "Method.VariableTableWithGeneric" },
 
   /* Field command set (8) */
@@ -1530,7 +1535,7 @@
   { 9,    1,  OR_ReferenceType,     "ObjectReference.ReferenceType" },
   { 9,    2,  OR_GetValues,         "ObjectReference.GetValues" },
   { 9,    3,  OR_SetValues,         "ObjectReference.SetValues" },
-  { 9,    4,  NULL,                 "ObjectReference.UNUSED" },
+  { 9,    4,  nullptr,              "ObjectReference.UNUSED" },
   { 9,    5,  OR_MonitorInfo,       "ObjectReference.MonitorInfo" },
   { 9,    6,  OR_InvokeMethod,      "ObjectReference.InvokeMethod" },
   { 9,    7,  OR_DisableCollection, "ObjectReference.DisableCollection" },
@@ -1551,11 +1556,11 @@
   { 11,   7,  TR_FrameCount,                  "ThreadReference.FrameCount" },
   { 11,   8,  TR_OwnedMonitors,               "ThreadReference.OwnedMonitors" },
   { 11,   9,  TR_CurrentContendedMonitor,     "ThreadReference.CurrentContendedMonitor" },
-  { 11,   10, NULL,                           "ThreadReference.Stop" },
+  { 11,   10, nullptr,                        "ThreadReference.Stop" },
   { 11,   11, TR_Interrupt,                   "ThreadReference.Interrupt" },
   { 11,   12, TR_DebugSuspendCount,           "ThreadReference.SuspendCount" },
   { 11,   13, TR_OwnedMonitorsStackDepthInfo, "ThreadReference.OwnedMonitorsStackDepthInfo" },
-  { 11,   14, NULL,                           "ThreadReference.ForceEarlyReturn" },
+  { 11,   14, nullptr,                        "ThreadReference.ForceEarlyReturn" },
 
   /* ThreadGroupReference command set (12) */
   { 12,   1,  TGR_Name,         "ThreadGroupReference.Name" },
@@ -1573,26 +1578,27 @@
   /* EventRequest command set (15) */
   { 15,   1,  ER_Set,           "EventRequest.Set" },
   { 15,   2,  ER_Clear,         "EventRequest.Clear" },
-  { 15,   3,  NULL,             "EventRequest.ClearAllBreakpoints" },
+  { 15,   3,  nullptr,          "EventRequest.ClearAllBreakpoints" },
 
   /* StackFrame command set (16) */
   { 16,   1,  SF_GetValues,     "StackFrame.GetValues" },
   { 16,   2,  SF_SetValues,     "StackFrame.SetValues" },
   { 16,   3,  SF_ThisObject,    "StackFrame.ThisObject" },
-  { 16,   4,  NULL,             "StackFrame.PopFrames" },
+  { 16,   4,  nullptr,          "StackFrame.PopFrames" },
 
   /* ClassObjectReference command set (17) */
   { 17,   1,  COR_ReflectedType, "ClassObjectReference.ReflectedType" },
 
   /* Event command set (64) */
-  { 64, 100,  NULL, "Event.Composite" },  // sent from VM to debugger, never received by VM
+  { 64, 100,  nullptr, "Event.Composite" },  // sent from VM to debugger, never received by VM
 
   { 199,  1,  DDM_Chunk,        "DDM.Chunk" },
 };
 
 static const char* GetCommandName(Request* request) {
   for (size_t i = 0; i < arraysize(gHandlers); ++i) {
-    if (gHandlers[i].cmdSet == request->GetCommandSet() && gHandlers[i].cmd == request->GetCommand()) {
+    if (gHandlers[i].cmdSet == request->GetCommandSet() &&
+        gHandlers[i].cmd == request->GetCommand()) {
       return gHandlers[i].name;
     }
   }
@@ -1660,7 +1666,9 @@
 
   size_t i;
   for (i = 0; i < arraysize(gHandlers); ++i) {
-    if (gHandlers[i].cmdSet == request->GetCommandSet() && gHandlers[i].cmd == request->GetCommand() && gHandlers[i].func != NULL) {
+    if (gHandlers[i].cmdSet == request->GetCommandSet() &&
+        gHandlers[i].cmd == request->GetCommand() &&
+        gHandlers[i].func != nullptr) {
       VLOG(jdwp) << DescribeCommand(request);
       result = (*gHandlers[i].func)(this, request, pReply);
       if (result == ERR_NONE) {
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index c500ef5..40211de 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -135,11 +135,16 @@
  */
 ssize_t JdwpNetStateBase::WriteBufferedPacket(const std::vector<iovec>& iov) {
   MutexLock mu(Thread::Current(), socket_lock_);
+  return WriteBufferedPacketLocked(iov);
+}
+
+ssize_t JdwpNetStateBase::WriteBufferedPacketLocked(const std::vector<iovec>& iov) {
+  socket_lock_.AssertHeld(Thread::Current());
   return TEMP_FAILURE_RETRY(writev(clientSock, &iov[0], iov.size()));
 }
 
 bool JdwpState::IsConnected() {
-  return netState != NULL && netState->IsConnected();
+  return netState != nullptr && netState->IsConnected();
 }
 
 void JdwpState::SendBufferedRequest(uint32_t type, const std::vector<iovec>& iov) {
@@ -202,18 +207,18 @@
       thread_start_lock_("JDWP thread start lock", kJdwpStartLock),
       thread_start_cond_("JDWP thread start condition variable", thread_start_lock_),
       pthread_(0),
-      thread_(NULL),
+      thread_(nullptr),
       debug_thread_started_(false),
       debug_thread_id_(0),
       run(false),
-      netState(NULL),
+      netState(nullptr),
       attach_lock_("JDWP attach lock", kJdwpAttachLock),
       attach_cond_("JDWP attach condition variable", attach_lock_),
       last_activity_time_ms_(0),
       request_serial_(0x10000000),
       event_serial_(0x20000000),
       event_list_lock_("JDWP event list lock", kJdwpEventListLock),
-      event_list_(NULL),
+      event_list_(nullptr),
       event_list_size_(0),
       event_thread_lock_("JDWP event thread lock"),
       event_thread_cond_("JDWP event thread condition variable", event_thread_lock_),
@@ -289,7 +294,7 @@
     }
     if (!state->IsActive()) {
       LOG(ERROR) << "JDWP connection failed";
-      return NULL;
+      return nullptr;
     }
 
     LOG(INFO) << "JDWP connected";
@@ -317,7 +322,7 @@
   UnregisterAll();
   {
     MutexLock mu(Thread::Current(), event_list_lock_);
-    CHECK(event_list_ == NULL);
+    CHECK(event_list_ == nullptr);
   }
 
   Dbg::ProcessDelayedFullUndeoptimizations();
@@ -336,7 +341,7 @@
  * Tell the JDWP thread to shut down.  Frees "state".
  */
 JdwpState::~JdwpState() {
-  if (netState != NULL) {
+  if (netState != nullptr) {
     /*
      * Close down the network to inspire the thread to halt.
      */
@@ -353,9 +358,9 @@
 
     VLOG(jdwp) << "JDWP freeing netstate...";
     delete netState;
-    netState = NULL;
+    netState = nullptr;
   }
-  CHECK(netState == NULL);
+  CHECK(netState == nullptr);
 
   ResetState();
 }
@@ -398,10 +403,10 @@
  */
 static void* StartJdwpThread(void* arg) {
   JdwpState* state = reinterpret_cast<JdwpState*>(arg);
-  CHECK(state != NULL);
+  CHECK(state != nullptr);
 
   state->Run();
-  return NULL;
+  return nullptr;
 }
 
 void JdwpState::Run() {
diff --git a/runtime/jdwp/jdwp_priv.h b/runtime/jdwp/jdwp_priv.h
index 29ad185..f290be0 100644
--- a/runtime/jdwp/jdwp_priv.h
+++ b/runtime/jdwp/jdwp_priv.h
@@ -71,6 +71,10 @@
 
   ssize_t WritePacket(ExpandBuf* pReply, size_t length) LOCKS_EXCLUDED(socket_lock_);
   ssize_t WriteBufferedPacket(const std::vector<iovec>& iov) LOCKS_EXCLUDED(socket_lock_);
+  Mutex* GetSocketLock() {
+    return &socket_lock_;
+  }
+  ssize_t WriteBufferedPacketLocked(const std::vector<iovec>& iov);
 
   int clientSock;  // Active connection to debugger.
 
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 4a80957..cbdde24 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -77,12 +77,12 @@
       /* scan through a range of ports, binding to the first available */
       for (port = kBasePort; port <= kMaxPort; port++) {
         state->netState = SocketStartup(state, port, true);
-        if (state->netState != NULL) {
+        if (state->netState != nullptr) {
           break;
         }
       }
     }
-    if (state->netState == NULL) {
+    if (state->netState == nullptr) {
       LOG(ERROR) << "JDWP net startup failed (req port=" << options->port << ")";
       return false;
     }
@@ -157,7 +157,7 @@
  fail:
   netState->Shutdown();
   delete netState;
-  return NULL;
+  return nullptr;
 }
 
 /*
@@ -170,20 +170,20 @@
  * for an open port.)
  */
 void JdwpSocketState::Shutdown() {
-  int listenSock = this->listenSock;
-  int clientSock = this->clientSock;
+  int local_listenSock = this->listenSock;
+  int local_clientSock = this->clientSock;
 
   /* clear these out so it doesn't wake up and try to reuse them */
   this->listenSock = this->clientSock = -1;
 
   /* "shutdown" dislodges blocking read() and accept() calls */
-  if (listenSock != -1) {
-    shutdown(listenSock, SHUT_RDWR);
-    close(listenSock);
+  if (local_listenSock != -1) {
+    shutdown(local_listenSock, SHUT_RDWR);
+    close(local_listenSock);
   }
-  if (clientSock != -1) {
-    shutdown(clientSock, SHUT_RDWR);
-    close(clientSock);
+  if (local_clientSock != -1) {
+    shutdown(local_clientSock, SHUT_RDWR);
+    close(local_clientSock);
   }
 
   WakePipe();
@@ -272,7 +272,7 @@
   /*
    * Start by resolving the host name.
    */
-#ifdef HAVE_GETHOSTBYNAME_R
+#if defined(__linux__)
   hostent he;
   char auxBuf[128];
   int error;
@@ -284,7 +284,7 @@
 #else
   h_errno = 0;
   pEntry = gethostbyname(options->host.c_str());
-  if (pEntry == NULL) {
+  if (pEntry == nullptr) {
     PLOG(WARNING) << "gethostbyname('" << options->host << "') failed";
     return false;
   }
@@ -403,7 +403,7 @@
        * re-issue the select.  We're currently using #2, as it's more
        * reliable than #1 and generally better than #3.  Wastes two fds.
        */
-      selCount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+      selCount = select(maxfd + 1, &readfds, nullptr, nullptr, nullptr);
       if (selCount < 0) {
         if (errno == EINTR) {
           continue;
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 35aaf0a..e415c3d 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -16,6 +16,8 @@
 
 #include "object_registry.h"
 
+#include "handle_scope-inl.h"
+#include "jni_internal.h"
 #include "mirror/class.h"
 #include "scoped_thread_state_change.h"
 
@@ -46,12 +48,17 @@
     return 0;
   }
 
+  Thread* const self = Thread::Current();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Object> obj_h(hs.NewHandle(o));
+
   // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
-  int32_t identity_hash_code = o->IdentityHashCode();
-  ScopedObjectAccessUnchecked soa(Thread::Current());
+  int32_t identity_hash_code = obj_h->IdentityHashCode();
+
+  ScopedObjectAccessUnchecked soa(self);
   MutexLock mu(soa.Self(), lock_);
   ObjectRegistryEntry* entry = nullptr;
-  if (ContainsLocked(soa.Self(), o, identity_hash_code, &entry)) {
+  if (ContainsLocked(soa.Self(), obj_h.Get(), identity_hash_code, &entry)) {
     // This object was already in our map.
     ++entry->reference_count;
   } else {
@@ -66,7 +73,7 @@
     // This object isn't in the registry yet, so add it.
     JNIEnv* env = soa.Env();
 
-    jobject local_reference = soa.AddLocalReference<jobject>(o);
+    jobject local_reference = soa.AddLocalReference<jobject>(obj_h.Get());
 
     entry->jni_reference_type = JNIWeakGlobalRefType;
     entry->jni_reference = env->NewWeakGlobalRef(local_reference);
@@ -80,17 +87,6 @@
   return entry->id;
 }
 
-bool ObjectRegistry::Contains(mirror::Object* o, ObjectRegistryEntry** out_entry) {
-  if (o == nullptr) {
-    return false;
-  }
-  // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
-  int32_t identity_hash_code = o->IdentityHashCode();
-  Thread* self = Thread::Current();
-  MutexLock mu(self, lock_);
-  return ContainsLocked(self, o, identity_hash_code, out_entry);
-}
-
 bool ObjectRegistry::ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
                                     ObjectRegistryEntry** out_entry) {
   DCHECK(o != nullptr);
@@ -108,7 +104,20 @@
 }
 
 void ObjectRegistry::Clear() {
-  Thread* self = Thread::Current();
+  Thread* const self = Thread::Current();
+
+  // We must not hold the mutator lock exclusively if we want to delete weak global
+  // references. Otherwise this can lead to a deadlock with a running GC:
+  // 1. GC thread disables access to weak global references, then releases
+  //    mutator lock.
+  // 2. JDWP thread takes mutator lock exclusively after suspending all
+  //    threads.
+  // 3. GC thread waits for shared mutator lock which is held by JDWP
+  //    thread.
+  // 4. JDWP thread clears weak global references but need to wait for GC
+  //    thread to re-enable access to them.
+  Locks::mutator_lock_->AssertNotExclusiveHeld(self);
+
   MutexLock mu(self, lock_);
   VLOG(jdwp) << "Object registry contained " << object_to_entry_.size() << " entries";
   // Delete all the JNI references.
@@ -142,7 +151,7 @@
 
 jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) {
   if (id == 0) {
-    return NULL;
+    return nullptr;
   }
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
@@ -198,7 +207,7 @@
   ObjectRegistryEntry& entry = *it->second;
   if (entry.jni_reference_type == JNIWeakGlobalRefType) {
     JNIEnv* env = self->GetJniEnv();
-    return env->IsSameObject(entry.jni_reference, NULL);  // Has the jweak been collected?
+    return env->IsSameObject(entry.jni_reference, nullptr);  // Has the jweak been collected?
   } else {
     return false;  // We hold a strong reference, so we know this is live.
   }
@@ -218,10 +227,10 @@
     // Erase the object from the maps. Note object may be null if it's
     // a weak ref and the GC has cleared it.
     int32_t hash_code = entry->identity_hash_code;
-    for (auto it = object_to_entry_.lower_bound(hash_code), end = object_to_entry_.end();
-         it != end && it->first == hash_code; ++it) {
-      if (entry == it->second) {
-        object_to_entry_.erase(it);
+    for (auto inner_it = object_to_entry_.lower_bound(hash_code), end = object_to_entry_.end();
+         inner_it != end && inner_it->first == hash_code; ++inner_it) {
+      if (entry == inner_it->second) {
+        object_to_entry_.erase(inner_it);
         break;
       }
     }
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index faddff1..0693f33 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -75,10 +75,6 @@
     return down_cast<T>(InternalGet(id, error));
   }
 
-  bool Contains(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return Contains(o, nullptr);
-  }
-
   void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void DisableCollection(JDWP::ObjectId id)
@@ -114,9 +110,6 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
-  bool Contains(mirror::Object* o, ObjectRegistryEntry** out_entry)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
-
   bool ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
                       ObjectRegistryEntry** out_entry)
       EXCLUSIVE_LOCKS_REQUIRED(lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 180e3d7..b2d3835 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -28,9 +28,9 @@
 
 static constexpr size_t kLocalsInitial = 64;  // Arbitrary.
 
-JNIEnvExt::JNIEnvExt(Thread* self, JavaVMExt* vm)
-    : self(self),
-      vm(vm),
+JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in)
+    : self(self_in),
+      vm(vm_in),
       local_ref_cookie(IRT_FIRST_SEGMENT),
       locals(kLocalsInitial, kLocalsMax, kLocal),
       check_jni(false),
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index bf979c1..37ad46e 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"
@@ -44,6 +45,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
 #include "mirror/throwable.h"
+#include "nativebridge/native_bridge.h"
 #include "parsed_options.h"
 #include "reflection.h"
 #include "runtime.h"
@@ -56,6 +58,10 @@
 
 namespace art {
 
+// Consider turning this on when there is errors which could be related to JNI array copies such as
+// things not rendering correctly. E.g. b/16858794
+static constexpr bool kWarnJniAbort = false;
+
 // Section 12.3.2 of the JNI spec describes JNI class descriptors. They're
 // separated with slashes but aren't wrapped with "L;" like regular descriptors
 // (i.e. "a/b/C" rather than "La/b/C;"). Arrays of reference types are an
@@ -191,8 +197,8 @@
     // Failed to find type from the signature of the field.
     DCHECK(soa.Self()->IsExceptionPending());
     ThrowLocation throw_location;
-    StackHandleScope<1> hs(soa.Self());
-    Handle<mirror::Throwable> cause(hs.NewHandle(soa.Self()->GetException(&throw_location)));
+    StackHandleScope<1> hs2(soa.Self());
+    Handle<mirror::Throwable> cause(hs2.NewHandle(soa.Self()->GetException(&throw_location)));
     soa.Self()->ClearException();
     std::string temp;
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
@@ -354,7 +360,7 @@
     ScopedObjectAccess soa(env);
     mirror::ArtMethod* m = soa.DecodeMethod(mid);
     CHECK(!kMovingMethods);
-    jobject art_method = soa.AddLocalReference<jobject>(m);
+    ScopedLocalRef<jobject> art_method(env, soa.AddLocalReference<jobject>(m));
     jobject reflect_method;
     if (m->IsConstructor()) {
       reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Constructor);
@@ -365,7 +371,7 @@
       return nullptr;
     }
     SetObjectField(env, reflect_method,
-                   WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod, art_method);
+                   WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod, art_method.get());
     return reflect_method;
   }
 
@@ -373,13 +379,13 @@
     CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
     mirror::ArtField* f = soa.DecodeField(fid);
-    jobject art_field = soa.AddLocalReference<jobject>(f);
+    ScopedLocalRef<jobject> art_field(env, soa.AddLocalReference<jobject>(f));
     jobject reflect_field = env->AllocObject(WellKnownClasses::java_lang_reflect_Field);
     if (env->ExceptionCheck()) {
       return nullptr;
     }
     SetObjectField(env, reflect_field,
-                   WellKnownClasses::java_lang_reflect_Field_artField, art_field);
+                   WellKnownClasses::java_lang_reflect_Field_artField, art_field.get());
     return reflect_field;
   }
 
@@ -560,7 +566,8 @@
     return soa.AddLocalReference<jobject>(decoded_obj);
   }
 
-  static void DeleteLocalRef(JNIEnv* env, jobject obj) {
+  static void DeleteLocalRef(JNIEnv* env, jobject obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (obj == nullptr) {
       return;
     }
@@ -1744,6 +1751,7 @@
   }
 
   static void ReleaseStringCritical(JNIEnv* env, jstring java_string, const jchar* chars) {
+    UNUSED(chars);
     CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -1772,7 +1780,7 @@
     return bytes;
   }
 
-  static void ReleaseStringUTFChars(JNIEnv* env, jstring, const char* chars) {
+  static void ReleaseStringUTFChars(JNIEnv*, jstring, const char* chars) {
     delete[] chars;
   }
 
@@ -2140,7 +2148,7 @@
 
       VLOG(jni) << "[Registering JNI native method " << PrettyMethod(m) << "]";
 
-      m->RegisterNative(soa.Self(), fnPtr, is_fast);
+      m->RegisterNative(fnPtr, is_fast);
     }
     return JNI_OK;
   }
@@ -2156,14 +2164,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++;
       }
     }
@@ -2248,8 +2256,10 @@
         java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_capacity));
   }
 
-  static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
-    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNIInvalidRefType);
+  static jobjectRefType GetObjectRefType(JNIEnv* env ATTRIBUTE_UNUSED, jobject java_object) {
+    if (java_object == nullptr) {
+      return JNIInvalidRefType;
+    }
 
     // Do we definitely know what kind of reference this is?
     IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -2266,7 +2276,7 @@
       return JNILocalRefType;
     }
     LOG(FATAL) << "IndirectRefKind[" << kind << "]";
-    return JNIInvalidRefType;
+    UNREACHABLE();
   }
 
  private:
@@ -2375,10 +2385,13 @@
                             reinterpret_cast<void*>(elements), array_data);
         return;
       }
-    }
-    // Don't need to copy if we had a direct pointer.
-    if (mode != JNI_ABORT && is_copy) {
-      memcpy(array_data, elements, bytes);
+      if (mode != JNI_ABORT) {
+        memcpy(array_data, elements, bytes);
+      } else if (kWarnJniAbort && memcmp(array_data, elements, bytes) != 0) {
+        // Warn if we have JNI_ABORT and the arrays don't match since this is usually an error.
+        LOG(WARNING) << "Possible incorrect JNI_ABORT in Release*ArrayElements";
+        soa.Self()->DumpJavaStack(LOG(WARNING));
+      }
     }
     if (mode != JNI_COMMIT) {
       if (is_copy) {
@@ -2697,7 +2710,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/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 20d031c..906aa4c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -390,59 +390,72 @@
   void ReleasePrimitiveArrayElementsOfWrongType(bool check_jni) {
     bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
     CheckJniAbortCatcher jni_abort_catcher;
+    {
+      jbooleanArray array = env_->NewBooleanArray(10);
+      ASSERT_TRUE(array != nullptr);
+      jboolean is_copy;
+      jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
+      ASSERT_TRUE(elements != nullptr);
+      env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
+                                     reinterpret_cast<jbyte*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected byte[]"
+              : "attempt to release byte primitive array elements with an object of type boolean[]");
+      env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
+                                      reinterpret_cast<jshort*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected short[]"
+              : "attempt to release short primitive array elements with an object of type boolean[]");
+      env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
+                                     reinterpret_cast<jchar*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected char[]"
+              : "attempt to release char primitive array elements with an object of type boolean[]");
+      env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
+                                    reinterpret_cast<jint*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected int[]"
+              : "attempt to release int primitive array elements with an object of type boolean[]");
+      env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
+                                     reinterpret_cast<jlong*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected long[]"
+              : "attempt to release long primitive array elements with an object of type boolean[]");
+      env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
+                                      reinterpret_cast<jfloat*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected float[]"
+              : "attempt to release float primitive array elements with an object of type boolean[]");
+      env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
+                                       reinterpret_cast<jdouble*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type boolean[] expected double[]"
+              : "attempt to release double primitive array elements with an object of type boolean[]");
 
-    jbooleanArray array = env_->NewBooleanArray(10);
-    ASSERT_TRUE(array != nullptr);
-    jboolean is_copy;
-    jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
-    ASSERT_TRUE(elements != nullptr);
-    env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
-                                   reinterpret_cast<jbyte*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected byte[]"
-            : "attempt to release byte primitive array elements with an object of type boolean[]");
-    env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
-                                    reinterpret_cast<jshort*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected short[]"
-            : "attempt to release short primitive array elements with an object of type boolean[]");
-    env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
-                                   reinterpret_cast<jchar*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected char[]"
-            : "attempt to release char primitive array elements with an object of type boolean[]");
-    env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
-                                  reinterpret_cast<jint*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected int[]"
-            : "attempt to release int primitive array elements with an object of type boolean[]");
-    env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
-                                   reinterpret_cast<jlong*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected long[]"
-            : "attempt to release long primitive array elements with an object of type boolean[]");
-    env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
-                                    reinterpret_cast<jfloat*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected float[]"
-            : "attempt to release float primitive array elements with an object of type boolean[]");
-    env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
-                                     reinterpret_cast<jdouble*>(elements), 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type boolean[] expected double[]"
-            : "attempt to release double primitive array elements with an object of type boolean[]");
-    jbyteArray array2 = env_->NewByteArray(10);
-    env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), elements, 0);
-    jni_abort_catcher.Check(
-        check_jni ? "incompatible array type byte[] expected boolean[]"
-            : "attempt to release boolean primitive array elements with an object of type byte[]");
-    jobject object = env_->NewStringUTF("Test String");
-    env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
-    jni_abort_catcher.Check(
-        check_jni ? "jarray argument has non-array type: java.lang.String"
-            : "attempt to release boolean primitive array elements with an object of type "
+      // Don't leak the elements array.
+      env_->ReleaseBooleanArrayElements(array, elements, 0);
+    }
+    {
+      jbyteArray array = env_->NewByteArray(10);
+      jboolean is_copy;
+      jbyte* elements = env_->GetByteArrayElements(array, &is_copy);
+
+      env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array),
+                                        reinterpret_cast<jboolean*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "incompatible array type byte[] expected boolean[]"
+              : "attempt to release boolean primitive array elements with an object of type byte[]");
+      jobject object = env_->NewStringUTF("Test String");
+      env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object),
+                                        reinterpret_cast<jboolean*>(elements), 0);
+      jni_abort_catcher.Check(
+          check_jni ? "jarray argument has non-array type: java.lang.String"
+              : "attempt to release boolean primitive array elements with an object of type "
               "java.lang.String");
 
+      // Don't leak the elements array.
+      env_->ReleaseByteArrayElements(array, elements, 0);
+    }
     EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
   }
 
@@ -621,6 +634,9 @@
 }
 
 TEST_F(JniInternalTest, FindClass) {
+  // This tests leads to warnings in the log.
+  ScopedLogSeverity sls(LogSeverity::ERROR);
+
   FindClassTest(false);
   FindClassTest(true);
 }
@@ -799,6 +815,11 @@
   ASSERT_NE(fid, nullptr);
   // Turn the fid into a java.lang.reflect.Field...
   jobject field = env_->ToReflectedField(c, fid, JNI_FALSE);
+  for (size_t i = 0; i <= kLocalsMax; ++i) {
+    // Regression test for b/18396311, ToReflectedField leaking local refs causing a local
+    // reference table overflows with 512 references to ArtField
+    env_->DeleteLocalRef(env_->ToReflectedField(c, fid, JNI_FALSE));
+  }
   ASSERT_NE(c, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(field, jlrField));
   // ...and back again.
@@ -825,6 +846,11 @@
   ASSERT_NE(mid, nullptr);
   // Turn the mid into a java.lang.reflect.Constructor...
   jobject method = env_->ToReflectedMethod(c, mid, JNI_FALSE);
+  for (size_t i = 0; i <= kLocalsMax; ++i) {
+    // Regression test for b/18396311, ToReflectedMethod leaking local refs causing a local
+    // reference table overflows with 512 references to ArtMethod
+    env_->DeleteLocalRef(env_->ToReflectedMethod(c, mid, JNI_FALSE));
+  }
   ASSERT_NE(method, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(method, jlrConstructor));
   // ...and back again.
@@ -867,40 +893,44 @@
   // Sanity check that no exceptions are pending.
   ASSERT_FALSE(env_->ExceptionCheck());
 
-  // Check that registering method without name causes a NoSuchMethodError.
+  // The following can print errors to the log we'd like to ignore.
   {
-    JNINativeMethod methods[] = { { nullptr, "()V", native_function } };
-    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
-  }
-  ExpectException(jlnsme);
+    ScopedLogSeverity sls(LogSeverity::FATAL);
+    // Check that registering method without name causes a NoSuchMethodError.
+    {
+      JNINativeMethod methods[] = { { nullptr, "()V", native_function } };
+      EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
+    }
+    ExpectException(jlnsme);
 
-  // Check that registering method without signature causes a NoSuchMethodError.
-  {
-    JNINativeMethod methods[] = { { "notify", nullptr, native_function } };
-    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
-  }
-  ExpectException(jlnsme);
+    // Check that registering method without signature causes a NoSuchMethodError.
+    {
+      JNINativeMethod methods[] = { { "notify", nullptr, native_function } };
+      EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
+    }
+    ExpectException(jlnsme);
 
-  // Check that registering method without function causes a NoSuchMethodError.
-  {
-    JNINativeMethod methods[] = { { "notify", "()V", nullptr } };
-    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
-  }
-  ExpectException(jlnsme);
+    // Check that registering method without function causes a NoSuchMethodError.
+    {
+      JNINativeMethod methods[] = { { "notify", "()V", nullptr } };
+      EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
+    }
+    ExpectException(jlnsme);
 
-  // Check that registering to a non-existent java.lang.Object.foo() causes a NoSuchMethodError.
-  {
-    JNINativeMethod methods[] = { { "foo", "()V", native_function } };
-    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
-  }
-  ExpectException(jlnsme);
+    // Check that registering to a non-existent java.lang.Object.foo() causes a NoSuchMethodError.
+    {
+      JNINativeMethod methods[] = { { "foo", "()V", native_function } };
+      EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
+    }
+    ExpectException(jlnsme);
 
-  // Check that registering non-native methods causes a NoSuchMethodError.
-  {
-    JNINativeMethod methods[] = { { "equals", "(Ljava/lang/Object;)Z", native_function } };
-    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
+    // Check that registering non-native methods causes a NoSuchMethodError.
+    {
+      JNINativeMethod methods[] = { { "equals", "(Ljava/lang/Object;)Z", native_function } };
+      EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
+    }
+    ExpectException(jlnsme);
   }
-  ExpectException(jlnsme);
 
   // Check that registering native methods is successful.
   {
@@ -1170,7 +1200,15 @@
 }
 
 TEST_F(JniInternalTest, GetArrayLength) {
-  // Already tested in NewObjectArray/NewPrimitiveArray.
+  // Already tested in NewObjectArray/NewPrimitiveArray except for NULL.
+  CheckJniAbortCatcher jni_abort_catcher;
+  bool old_check_jni = vm_->SetCheckJniEnabled(false);
+  EXPECT_EQ(0, env_->GetArrayLength(nullptr));
+  jni_abort_catcher.Check("java_array == null");
+  EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+  EXPECT_EQ(JNI_ERR, env_->GetArrayLength(nullptr));
+  jni_abort_catcher.Check("jarray was NULL");
+  EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
 }
 
 TEST_F(JniInternalTest, GetObjectClass) {
@@ -1269,16 +1307,20 @@
   jweak weak_global = env_->NewWeakGlobalRef(local);
   EXPECT_EQ(JNIWeakGlobalRefType, env_->GetObjectRefType(weak_global));
 
-  CheckJniAbortCatcher jni_abort_catcher;
-  jobject invalid = reinterpret_cast<jobject>(this);
-  EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(invalid));
-  jni_abort_catcher.Check("use of invalid jobject");
+  {
+    CheckJniAbortCatcher jni_abort_catcher;
+    jobject invalid = reinterpret_cast<jobject>(this);
+    EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(invalid));
+    jni_abort_catcher.Check("use of invalid jobject");
+  }
 
   // TODO: invoke a native method and test that its arguments are considered local references.
 
-  // Null as object should fail.
+  // Null as pointer should not fail and return invalid-ref. b/18820997
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(nullptr));
-  jni_abort_catcher.Check("java_object == null");
+
+  // TODO: Null as reference should return the original type.
+  // This requires running a GC so a non-null object gets freed.
 }
 
 TEST_F(JniInternalTest, StaleWeakGlobal) {
@@ -1527,14 +1569,14 @@
   EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
 }
 
-#define EXPECT_STATIC_PRIMITIVE_FIELD(type, field_name, sig, value1, value2) \
+#define EXPECT_STATIC_PRIMITIVE_FIELD(expect_eq, type, field_name, sig, value1, value2) \
   do { \
     jfieldID fid = env_->GetStaticFieldID(c, field_name, sig); \
     EXPECT_NE(fid, nullptr); \
     env_->SetStatic ## type ## Field(c, fid, value1); \
-    EXPECT_EQ(value1, env_->GetStatic ## type ## Field(c, fid)); \
+    expect_eq(value1, env_->GetStatic ## type ## Field(c, fid)); \
     env_->SetStatic ## type ## Field(c, fid, value2); \
-    EXPECT_EQ(value2, env_->GetStatic ## type ## Field(c, fid)); \
+    expect_eq(value2, env_->GetStatic ## type ## Field(c, fid)); \
     \
     bool old_check_jni = vm_->SetCheckJniEnabled(false); \
     { \
@@ -1560,14 +1602,14 @@
     EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni)); \
   } while (false)
 
-#define EXPECT_PRIMITIVE_FIELD(instance, type, field_name, sig, value1, value2) \
+#define EXPECT_PRIMITIVE_FIELD(expect_eq, instance, type, field_name, sig, value1, value2) \
   do { \
     jfieldID fid = env_->GetFieldID(c, field_name, sig); \
     EXPECT_NE(fid, nullptr); \
     env_->Set ## type ## Field(instance, fid, value1); \
-    EXPECT_EQ(value1, env_->Get ## type ## Field(instance, fid)); \
+    expect_eq(value1, env_->Get ## type ## Field(instance, fid)); \
     env_->Set ## type ## Field(instance, fid, value2); \
-    EXPECT_EQ(value2, env_->Get ## type ## Field(instance, fid)); \
+    expect_eq(value2, env_->Get ## type ## Field(instance, fid)); \
     \
     bool old_check_jni = vm_->SetCheckJniEnabled(false); \
     CheckJniAbortCatcher jni_abort_catcher; \
@@ -1593,7 +1635,6 @@
 
 
 TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) {
-  TEST_DISABLED_FOR_PORTABLE();
   Thread::Current()->TransitionFromSuspendedToRunnable();
   LoadDex("AllFields");
   bool started = runtime_->Start();
@@ -1604,27 +1645,26 @@
   jobject o = env_->AllocObject(c);
   ASSERT_NE(o, nullptr);
 
-  EXPECT_STATIC_PRIMITIVE_FIELD(Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
-  EXPECT_STATIC_PRIMITIVE_FIELD(Byte, "sB", "B", 1, 2);
-  EXPECT_STATIC_PRIMITIVE_FIELD(Char, "sC", "C", 'a', 'b');
-  EXPECT_STATIC_PRIMITIVE_FIELD(Double, "sD", "D", 1.0, 2.0);
-  EXPECT_STATIC_PRIMITIVE_FIELD(Float, "sF", "F", 1.0, 2.0);
-  EXPECT_STATIC_PRIMITIVE_FIELD(Int, "sI", "I", 1, 2);
-  EXPECT_STATIC_PRIMITIVE_FIELD(Long, "sJ", "J", 1, 2);
-  EXPECT_STATIC_PRIMITIVE_FIELD(Short, "sS", "S", 1, 2);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Byte, "sB", "B", 1, 2);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Char, "sC", "C", 'a', 'b');
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, Double, "sD", "D", 1.0, 2.0);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, Float, "sF", "F", 1.0, 2.0);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Int, "sI", "I", 1, 2);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Long, "sJ", "J", 1, 2);
+  EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Short, "sS", "S", 1, 2);
 
-  EXPECT_PRIMITIVE_FIELD(o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
-  EXPECT_PRIMITIVE_FIELD(o, Byte, "iB", "B", 1, 2);
-  EXPECT_PRIMITIVE_FIELD(o, Char, "iC", "C", 'a', 'b');
-  EXPECT_PRIMITIVE_FIELD(o, Double, "iD", "D", 1.0, 2.0);
-  EXPECT_PRIMITIVE_FIELD(o, Float, "iF", "F", 1.0, 2.0);
-  EXPECT_PRIMITIVE_FIELD(o, Int, "iI", "I", 1, 2);
-  EXPECT_PRIMITIVE_FIELD(o, Long, "iJ", "J", 1, 2);
-  EXPECT_PRIMITIVE_FIELD(o, Short, "iS", "S", 1, 2);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Byte, "iB", "B", 1, 2);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Char, "iC", "C", 'a', 'b');
+  EXPECT_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, o, Double, "iD", "D", 1.0, 2.0);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, o, Float, "iF", "F", 1.0, 2.0);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Int, "iI", "I", 1, 2);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Long, "iJ", "J", 1, 2);
+  EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Short, "iS", "S", 1, 2);
 }
 
 TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
-  TEST_DISABLED_FOR_PORTABLE();
   Thread::Current()->TransitionFromSuspendedToRunnable();
   LoadDex("AllFields");
   runtime_->Start();
@@ -1674,6 +1714,9 @@
 }
 
 TEST_F(JniInternalTest, DeleteLocalRef) {
+  // This tests leads to warnings and errors in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   jstring s = env_->NewStringUTF("");
   ASSERT_NE(s, nullptr);
   env_->DeleteLocalRef(s);
@@ -1710,6 +1753,9 @@
   ASSERT_EQ(JNI_OK, env_->PushLocalFrame(0));
   env_->PopLocalFrame(nullptr);
 
+  // The following two tests will print errors to the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   // Negative capacities are not allowed.
   ASSERT_EQ(JNI_ERR, env_->PushLocalFrame(-1));
 
@@ -1718,6 +1764,9 @@
 }
 
 TEST_F(JniInternalTest, PushLocalFrame_PopLocalFrame) {
+  // This tests leads to errors in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   jobject original = env_->NewStringUTF("");
   ASSERT_NE(original, nullptr);
 
@@ -1782,6 +1831,9 @@
 }
 
 TEST_F(JniInternalTest, DeleteGlobalRef) {
+  // This tests leads to warnings and errors in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   jstring s = env_->NewStringUTF("");
   ASSERT_NE(s, nullptr);
 
@@ -1832,6 +1884,9 @@
 }
 
 TEST_F(JniInternalTest, DeleteWeakGlobalRef) {
+  // This tests leads to warnings and errors in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   jstring s = env_->NewStringUTF("");
   ASSERT_NE(s, nullptr);
 
@@ -1956,6 +2011,9 @@
 }
 
 TEST_F(JniInternalTest, MonitorEnterExit) {
+  // This will print some error messages. Suppress.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   // Create an object to torture.
   jclass object_class = env_->FindClass("java/lang/Object");
   ASSERT_NE(object_class, nullptr);
@@ -2011,14 +2069,4 @@
   }
 }
 
-TEST_F(JniInternalTest, DetachCurrentThread) {
-  CleanUpJniEnv();  // cleanup now so TearDown won't have junk from wrong JNIEnv
-  jint ok = vm_->DetachCurrentThread();
-  EXPECT_EQ(JNI_OK, ok);
-
-  jint err = vm_->DetachCurrentThread();
-  EXPECT_EQ(JNI_ERR, err);
-  vm_->AttachCurrentThread(&env_, nullptr);  // need attached thread for CommonRuntimeTest::TearDown
-}
-
 }  // namespace art
diff --git a/runtime/jobject_comparator.cc b/runtime/jobject_comparator.cc
index e22d75f..77f93ff 100644
--- a/runtime/jobject_comparator.cc
+++ b/runtime/jobject_comparator.cc
@@ -40,7 +40,7 @@
   }
   // Sort by class...
   if (obj1->GetClass() != obj2->GetClass()) {
-    return obj1->GetClass()->IdentityHashCode() < obj2->IdentityHashCode();
+    return obj1->GetClass()->IdentityHashCode() < obj2->GetClass()->IdentityHashCode();
   } else {
     // ...then by size...
     size_t count1 = obj1->SizeOf();
diff --git a/runtime/lock_word-inl.h b/runtime/lock_word-inl.h
index cf6f83c..c52578f 100644
--- a/runtime/lock_word-inl.h
+++ b/runtime/lock_word-inl.h
@@ -34,13 +34,13 @@
 
 inline Monitor* LockWord::FatLockMonitor() const {
   DCHECK_EQ(GetState(), kFatLocked);
-  MonitorId mon_id = static_cast<MonitorId>(value_ & ~(kStateMask << kStateShift));
+  MonitorId mon_id = value_ & ~(kStateMask << kStateShift);
   return MonitorPool::MonitorFromMonitorId(mon_id);
 }
 
 inline size_t LockWord::ForwardingAddress() const {
   DCHECK_EQ(GetState(), kForwardingAddress);
-  return static_cast<size_t>(value_ << kStateSize);
+  return value_ << kStateSize;
 }
 
 inline LockWord::LockWord() : value_(0) {
diff --git a/runtime/lock_word.h b/runtime/lock_word.h
index 13cc3b0..2d5c71b 100644
--- a/runtime/lock_word.h
+++ b/runtime/lock_word.h
@@ -52,7 +52,7 @@
  */
 class LockWord {
  public:
-  enum {
+  enum SizeShiftsAndMasks {  // private marker to avoid generate-operator-out.py from processing.
     // Number of bits to encode the state, currently just fat or thin/unlocked or hash code.
     kStateSize = 2,
     // Number of bits to encode the thin lock owner.
diff --git a/runtime/log_severity.h b/runtime/log_severity.h
deleted file mode 100644
index 31682df..0000000
--- a/runtime/log_severity.h
+++ /dev/null
@@ -1,25 +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.
- */
-
-#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_
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index d755cb9..a722813 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__
@@ -27,7 +28,13 @@
 #endif
 
 #include "base/stringprintf.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
 #include "ScopedFd.h"
+#pragma GCC diagnostic pop
+
+#include "thread-inl.h"
 #include "utils.h"
 
 #define USE_ASHMEM 1
@@ -70,7 +77,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.
@@ -189,7 +196,7 @@
 // non-null, we check that pointer is the actual_ptr == expected_ptr,
 // and if not, report in error_msg what the conflict mapping was if
 // found, or a generic error in other cases.
-static bool CheckMapRequest(byte* expected_ptr, void* actual_ptr, size_t byte_count,
+static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte_count,
                             std::string* error_msg) {
   // Handled first by caller for more specific error messages.
   CHECK(actual_ptr != MAP_FAILED);
@@ -234,8 +241,11 @@
   return false;
 }
 
-MemMap* MemMap::MapAnonymous(const char* name, byte* expected_ptr, size_t byte_count, int prot,
+MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byte_count, int prot,
                              bool low_4gb, std::string* error_msg) {
+#ifndef __LP64__
+  UNUSED(low_4gb);
+#endif
   if (byte_count == 0) {
     return new MemMap(name, nullptr, 0, nullptr, 0, prot, false);
   }
@@ -377,11 +387,11 @@
   if (!CheckMapRequest(expected_ptr, actual, page_aligned_byte_count, error_msg)) {
     return nullptr;
   }
-  return new MemMap(name, reinterpret_cast<byte*>(actual), byte_count, actual,
+  return new MemMap(name, reinterpret_cast<uint8_t*>(actual), byte_count, actual,
                     page_aligned_byte_count, prot, false);
 }
 
-MemMap* MemMap::MapFileAtAddress(byte* expected_ptr, size_t byte_count, int prot, int flags, int fd,
+MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int prot, int flags, int fd,
                                  off_t start, bool reuse, const char* filename,
                                  std::string* error_msg) {
   CHECK_NE(0, prot);
@@ -414,9 +424,9 @@
   size_t page_aligned_byte_count = RoundUp(byte_count + page_offset, kPageSize);
   // The 'expected_ptr' is modified (if specified, ie non-null) to be page aligned to the file but
   // not necessarily to virtual memory. mmap will page align 'expected' for us.
-  byte* page_aligned_expected = (expected_ptr == nullptr) ? nullptr : (expected_ptr - page_offset);
+  uint8_t* page_aligned_expected = (expected_ptr == nullptr) ? nullptr : (expected_ptr - page_offset);
 
-  byte* actual = reinterpret_cast<byte*>(mmap(page_aligned_expected,
+  uint8_t* actual = reinterpret_cast<uint8_t*>(mmap(page_aligned_expected,
                                               page_aligned_byte_count,
                                               prot,
                                               flags,
@@ -457,18 +467,19 @@
   // 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;
     }
   }
   CHECK(found) << "MemMap not found";
 }
 
-MemMap::MemMap(const std::string& name, byte* begin, size_t size, void* base_begin,
+MemMap::MemMap(const std::string& name, uint8_t* begin, size_t size, void* base_begin,
                size_t base_size, int prot, bool reuse)
     : name_(name), begin_(begin), size_(size), base_begin_(base_begin), base_size_(base_size),
       prot_(prot), reuse_(reuse) {
@@ -483,31 +494,32 @@
 
     // 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));
   }
 }
 
-MemMap* MemMap::RemapAtEnd(byte* new_end, const char* tail_name, int tail_prot,
+MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_prot,
                            std::string* error_msg) {
   DCHECK_GE(new_end, Begin());
   DCHECK_LE(new_end, End());
-  DCHECK_LE(begin_ + size_, reinterpret_cast<byte*>(base_begin_) + base_size_);
+  DCHECK_LE(begin_ + size_, reinterpret_cast<uint8_t*>(base_begin_) + base_size_);
   DCHECK(IsAligned<kPageSize>(begin_));
   DCHECK(IsAligned<kPageSize>(base_begin_));
-  DCHECK(IsAligned<kPageSize>(reinterpret_cast<byte*>(base_begin_) + base_size_));
+  DCHECK(IsAligned<kPageSize>(reinterpret_cast<uint8_t*>(base_begin_) + base_size_));
   DCHECK(IsAligned<kPageSize>(new_end));
-  byte* old_end = begin_ + size_;
-  byte* old_base_end = reinterpret_cast<byte*>(base_begin_) + base_size_;
-  byte* new_base_end = new_end;
+  uint8_t* old_end = begin_ + size_;
+  uint8_t* old_base_end = reinterpret_cast<uint8_t*>(base_begin_) + base_size_;
+  uint8_t* new_base_end = new_end;
   DCHECK_LE(new_base_end, old_base_end);
   if (new_base_end == old_base_end) {
     return new MemMap(tail_name, nullptr, 0, nullptr, 0, tail_prot, false);
   }
-  size_ = new_end - reinterpret_cast<byte*>(begin_);
-  base_size_ = new_base_end - reinterpret_cast<byte*>(base_begin_);
-  DCHECK_LE(begin_ + size_, reinterpret_cast<byte*>(base_begin_) + base_size_);
+  size_ = new_end - reinterpret_cast<uint8_t*>(begin_);
+  base_size_ = new_base_end - reinterpret_cast<uint8_t*>(base_begin_);
+  DCHECK_LE(begin_ + size_, reinterpret_cast<uint8_t*>(base_begin_) + base_size_);
   size_t tail_size = old_end - new_end;
-  byte* tail_base_begin = new_base_end;
+  uint8_t* tail_base_begin = new_base_end;
   size_t tail_base_size = old_base_end - new_base_end;
   DCHECK_EQ(tail_base_begin + tail_base_size, old_base_end);
   DCHECK(IsAligned<kPageSize>(tail_base_size));
@@ -543,7 +555,7 @@
   // calls. Otherwise, libc (or something else) might take this memory
   // region. Note this isn't perfect as there's no way to prevent
   // other threads to try to take this memory region here.
-  byte* actual = reinterpret_cast<byte*>(mmap(tail_base_begin, tail_base_size, tail_prot,
+  uint8_t* actual = reinterpret_cast<uint8_t*>(mmap(tail_base_begin, tail_base_size, tail_prot,
                                               flags, fd.get(), 0));
   if (actual == MAP_FAILED) {
     std::string maps;
@@ -614,7 +626,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 +638,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 +651,33 @@
   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;
+}
+
+void MemMap::SetSize(size_t new_size) {
+  if (new_size == base_size_) {
+    return;
+  }
+  CHECK_ALIGNED(new_size, kPageSize);
+  CHECK_EQ(base_size_, size_) << "Unsupported";
+  CHECK_LE(new_size, base_size_);
+  CHECK_EQ(munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) + new_size),
+                  base_size_ - new_size), 0) << new_size << " " << base_size_;
+  base_size_ = new_size;
+  size_ = new_size;
+}
+
 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 e49ed48..dc337e0 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -60,7 +60,7 @@
   // a name.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t byte_count, int prot,
+  static MemMap* MapAnonymous(const char* ashmem_name, uint8_t* addr, size_t byte_count, int prot,
                               bool low_4gb, std::string* error_msg);
 
   // Map part of a file, taking care of non-page aligned offsets.  The
@@ -80,7 +80,7 @@
   //
   // On success, returns returns a MemMap instance.  On failure, returns a
   // nullptr;
-  static MemMap* MapFileAtAddress(byte* addr, size_t byte_count, int prot, int flags, int fd,
+  static MemMap* MapFileAtAddress(uint8_t* addr, size_t byte_count, int prot, int flags, int fd,
                                   off_t start, bool reuse, const char* filename,
                                   std::string* error_msg);
 
@@ -99,7 +99,7 @@
     return prot_;
   }
 
-  byte* Begin() const {
+  uint8_t* Begin() const {
     return begin_;
   }
 
@@ -107,7 +107,10 @@
     return size_;
   }
 
-  byte* End() const {
+  // Resize the mem-map by unmapping pages at the end. Currently only supports shrinking.
+  void SetSize(size_t new_size);
+
+  uint8_t* End() const {
     return Begin() + Size();
   }
 
@@ -120,7 +123,7 @@
   }
 
   void* BaseEnd() const {
-    return reinterpret_cast<byte*>(BaseBegin()) + BaseSize();
+    return reinterpret_cast<uint8_t*>(BaseBegin()) + BaseSize();
   }
 
   bool HasAddress(const void* addr) const {
@@ -128,7 +131,7 @@
   }
 
   // Unmap the pages at end and remap them to create another memory map.
-  MemMap* RemapAtEnd(byte* new_end, const char* tail_name, int tail_prot,
+  MemMap* RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_prot,
                      std::string* error_msg);
 
   static bool CheckNoGaps(MemMap* begin_map, MemMap* end_map)
@@ -138,8 +141,11 @@
 
   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, byte* begin, size_t size, void* base_begin, size_t base_size,
+  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_);
 
   static void DumpMapsLocked(std::ostream& os)
@@ -150,7 +156,7 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mem_maps_lock_);
 
   const std::string name_;
-  byte* const begin_;  // Start of data.
+  uint8_t* const begin_;  // Start of data.
   size_t size_;  // Length of data.
 
   void* const base_begin_;  // Page-aligned base address.
@@ -167,11 +173,12 @@
 #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_.
 };
 std::ostream& operator<<(std::ostream& os, const MemMap& mem_map);
+std::ostream& operator<<(std::ostream& os, const MemMap::Maps& mem_maps);
 
 }  // namespace art
 
diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc
index e54d0e0..14a72b9 100644
--- a/runtime/mem_map_test.cc
+++ b/runtime/mem_map_test.cc
@@ -26,8 +26,8 @@
 
 class MemMapTest : public testing::Test {
  public:
-  static byte* BaseBegin(MemMap* mem_map) {
-    return reinterpret_cast<byte*>(mem_map->base_begin_);
+  static uint8_t* BaseBegin(MemMap* mem_map) {
+    return reinterpret_cast<uint8_t*>(mem_map->base_begin_);
   }
   static size_t BaseSize(MemMap* mem_map) {
     return mem_map->base_size_;
@@ -45,7 +45,7 @@
                                       low_4gb,
                                       &error_msg);
     // Check its state and write to it.
-    byte* base0 = m0->Begin();
+    uint8_t* base0 = m0->Begin();
     ASSERT_TRUE(base0 != nullptr) << error_msg;
     size_t size0 = m0->Size();
     EXPECT_EQ(m0->Size(), 2 * page_size);
@@ -62,7 +62,7 @@
     EXPECT_EQ(m0->Size(), page_size);
     EXPECT_EQ(BaseBegin(m0), base0);
     EXPECT_EQ(BaseSize(m0), page_size);
-    byte* base1 = m1->Begin();
+    uint8_t* base1 = m1->Begin();
     size_t size1 = m1->Size();
     EXPECT_EQ(base1, base0 + page_size);
     EXPECT_EQ(size1, page_size);
@@ -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,10 +163,11 @@
 #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",
-                                              reinterpret_cast<byte*>(ART_BASE_ADDRESS),
+                                              reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS),
                                               kPageSize,
                                               PROT_READ | PROT_WRITE,
                                               false,
@@ -180,7 +187,7 @@
   ASSERT_TRUE(map1->BaseBegin() != nullptr);
   // Attempt to map at the same address, which should fail.
   std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
-                                              reinterpret_cast<byte*>(map1->BaseBegin()),
+                                              reinterpret_cast<uint8_t*>(map1->BaseBegin()),
                                               kPageSize,
                                               PROT_READ | PROT_WRITE,
                                               false,
@@ -200,12 +207,13 @@
 #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;
     std::string error_msg;
     std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
-                                                     reinterpret_cast<byte*>(start_addr),
+                                                     reinterpret_cast<uint8_t*>(start_addr),
                                                      0x21000000,
                                                      PROT_READ | PROT_WRITE,
                                                      true,
@@ -217,11 +225,12 @@
 }
 
 TEST_F(MemMapTest, MapAnonymousOverflow) {
+  CommonInit();
   std::string error_msg;
   uintptr_t ptr = 0;
   ptr -= kPageSize;  // Now it's close to the top.
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousOverflow",
-                                             reinterpret_cast<byte*>(ptr),
+                                             reinterpret_cast<uint8_t*>(ptr),
                                              2 * kPageSize,  // brings it over the top.
                                              PROT_READ | PROT_WRITE,
                                              false,
@@ -232,9 +241,10 @@
 
 #ifdef __LP64__
 TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
+  CommonInit();
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
-                                             reinterpret_cast<byte*>(UINT64_C(0x100000000)),
+                                             reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
                                              kPageSize,
                                              PROT_READ | PROT_WRITE,
                                              true,
@@ -244,9 +254,10 @@
 }
 
 TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
+  CommonInit();
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
-                                             reinterpret_cast<byte*>(0xF0000000),
+                                             reinterpret_cast<uint8_t*>(0xF0000000),
                                              0x20000000,
                                              PROT_READ | PROT_WRITE,
                                              true,
@@ -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.
@@ -269,7 +281,7 @@
   ASSERT_TRUE(map.get() != nullptr) << error_msg;
   ASSERT_TRUE(error_msg.empty());
   // Record the base address.
-  byte* map_base = reinterpret_cast<byte*>(map->BaseBegin());
+  uint8_t* map_base = reinterpret_cast<uint8_t*>(map->BaseBegin());
   // Unmap it.
   map.reset();
 
diff --git a/runtime/memory_region.h b/runtime/memory_region.h
index bab2e86..b3820be 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,10 +29,10 @@
 // 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(void* pointer, uword size) : pointer_(pointer), size_(size) {}
+  MemoryRegion() : pointer_(nullptr), size_(0) {}
+  MemoryRegion(void* pointer_in, uintptr_t size_in) : pointer_(pointer_in), size_(size_in) {}
 
   void* pointer() const { return pointer_; }
   size_t size() const { return size_; }
@@ -41,8 +42,8 @@
     return OFFSETOF_MEMBER(MemoryRegion, pointer_);
   }
 
-  byte* start() const { return reinterpret_cast<byte*>(pointer_); }
-  byte* end() const { return start() + size_; }
+  uint8_t* start() const { return reinterpret_cast<uint8_t*>(pointer_); }
+  uint8_t* end() const { return start() + size_; }
 
   template<typename T> T Load(uintptr_t offset) const {
     return *ComputeInternalPointer<T>(offset);
@@ -77,10 +78,10 @@
   void CopyFrom(size_t offset, const MemoryRegion& from) const;
 
   // Compute a sub memory region based on an existing one.
-  MemoryRegion Subregion(uintptr_t offset, uintptr_t size) const {
-    CHECK_GE(this->size(), size);
-    CHECK_LE(offset,  this->size() - size);
-    return MemoryRegion(reinterpret_cast<void*>(start() + offset), size);
+  MemoryRegion Subregion(uintptr_t offset, uintptr_t size_in) const {
+    CHECK_GE(this->size(), size_in);
+    CHECK_LE(offset,  this->size() - size_in);
+    return MemoryRegion(reinterpret_cast<void*>(start() + offset), size_in);
   }
 
   // Compute an extended memory region based on an existing one.
@@ -98,11 +99,11 @@
 
   // Locate the bit with the given offset. Returns a pointer to the byte
   // containing the bit, and sets bit_mask to the bit within that byte.
-  byte* ComputeBitPointer(uintptr_t bit_offset, byte* bit_mask) const {
+  uint8_t* ComputeBitPointer(uintptr_t bit_offset, uint8_t* bit_mask) const {
     uintptr_t bit_remainder = (bit_offset & (kBitsPerByte - 1));
     *bit_mask = (1U << bit_remainder);
     uintptr_t byte_offset = (bit_offset >> kBitsPerByteLog2);
-    return ComputeInternalPointer<byte>(byte_offset);
+    return ComputeInternalPointer<uint8_t>(byte_offset);
   }
 
   void* pointer_;
diff --git a/runtime/method_helper-inl.h b/runtime/method_helper-inl.h
deleted file mode 100644
index 143f4bc..0000000
--- a/runtime/method_helper-inl.h
+++ /dev/null
@@ -1,85 +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.
- */
-
-#ifndef ART_RUNTIME_METHOD_HELPER_INL_H_
-#define ART_RUNTIME_METHOD_HELPER_INL_H_
-
-#include "method_helper.h"
-
-#include "class_linker.h"
-#include "mirror/object_array.h"
-#include "runtime.h"
-#include "thread-inl.h"
-
-namespace art {
-
-template <template <class T> class HandleKind>
-template <template <class T2> class HandleKind2>
-inline bool MethodHelperT<HandleKind>::HasSameNameAndSignature(MethodHelperT<HandleKind2>* other) {
-  const DexFile* dex_file = method_->GetDexFile();
-  const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex());
-  if (method_->GetDexCache() == other->method_->GetDexCache()) {
-    const DexFile::MethodId& other_mid =
-        dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
-    return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_;
-  }
-  const DexFile* other_dex_file = other->method_->GetDexFile();
-  const DexFile::MethodId& other_mid =
-      other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
-  if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) {
-    return false;  // Name mismatch.
-  }
-  return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid);
-}
-
-template <template <class T> class HandleKind>
-inline mirror::Class* MethodHelperT<HandleKind>::GetClassFromTypeIdx(uint16_t type_idx,
-                                                                     bool resolve) {
-  mirror::ArtMethod* method = GetMethod();
-  mirror::Class* type = method->GetDexCacheResolvedType(type_idx);
-  if (type == nullptr && resolve) {
-    type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
-  }
-  return type;
-}
-
-template <template <class T> class HandleKind>
-inline mirror::Class* MethodHelperT<HandleKind>::GetReturnType(bool resolve) {
-  mirror::ArtMethod* method = GetMethod();
-  const DexFile* dex_file = method->GetDexFile();
-  const DexFile::MethodId& method_id = dex_file->GetMethodId(method->GetDexMethodIndex());
-  const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
-  uint16_t return_type_idx = proto_id.return_type_idx_;
-  return GetClassFromTypeIdx(return_type_idx, resolve);
-}
-
-template <template <class T> class HandleKind>
-inline mirror::String* MethodHelperT<HandleKind>::ResolveString(uint32_t string_idx) {
-  mirror::ArtMethod* method = GetMethod();
-  mirror::String* s = method->GetDexCacheStrings()->Get(string_idx);
-  if (UNLIKELY(s == nullptr)) {
-    StackHandleScope<1> hs(Thread::Current());
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
-    s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx,
-                                                            dex_cache);
-  }
-  return s;
-}
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_METHOD_HELPER_INL_H_
diff --git a/runtime/method_helper.cc b/runtime/method_helper.cc
deleted file mode 100644
index 79c2b91..0000000
--- a/runtime/method_helper.cc
+++ /dev/null
@@ -1,176 +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 "method_helper-inl.h"
-
-#include "class_linker.h"
-#include "dex_file-inl.h"
-#include "handle_scope-inl.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/dex_cache.h"
-#include "runtime.h"
-
-namespace art {
-
-template <template <class T> class HandleKind>
-mirror::String* MethodHelperT<HandleKind>::GetNameAsString(Thread* self) {
-  const DexFile* dex_file = method_->GetDexFile();
-  mirror::ArtMethod* method = method_->GetInterfaceMethodIfProxy();
-  uint32_t dex_method_idx = method->GetDexMethodIndex();
-  const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx);
-  StackHandleScope<1> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
-  return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_,
-                                                             dex_cache);
-}
-
-template <template <class T> class HandleKind>
-template <template <class T2> class HandleKind2>
-bool MethodHelperT<HandleKind>::HasSameSignatureWithDifferentClassLoaders(
-    MethodHelperT<HandleKind2>* other) {
-  if (UNLIKELY(GetReturnType() != other->GetReturnType())) {
-    return false;
-  }
-  const DexFile::TypeList* types = method_->GetParameterTypeList();
-  const DexFile::TypeList* other_types = other->method_->GetParameterTypeList();
-  if (types == nullptr) {
-    return (other_types == nullptr) || (other_types->Size() == 0);
-  } else if (UNLIKELY(other_types == nullptr)) {
-    return types->Size() == 0;
-  }
-  uint32_t num_types = types->Size();
-  if (UNLIKELY(num_types != other_types->Size())) {
-    return false;
-  }
-  for (uint32_t i = 0; i < num_types; ++i) {
-    mirror::Class* param_type = GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
-    mirror::Class* other_param_type =
-        other->GetClassFromTypeIdx(other_types->GetTypeItem(i).type_idx_);
-    if (UNLIKELY(param_type != other_param_type)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-template <template <class T> class HandleKind>
-uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtMethod* method = GetMethod();
-  const DexFile* dexfile = method->GetDexFile();
-  if (dexfile == &other_dexfile) {
-    return method->GetDexMethodIndex();
-  }
-  const DexFile::MethodId& mid = dexfile->GetMethodId(method->GetDexMethodIndex());
-  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
-  const DexFile::StringId* other_descriptor =
-      other_dexfile.FindStringId(mid_declaring_class_descriptor);
-  if (other_descriptor != nullptr) {
-    const DexFile::TypeId* other_type_id =
-        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
-    if (other_type_id != nullptr) {
-      const char* mid_name = dexfile->GetMethodName(mid);
-      const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name);
-      if (other_name != nullptr) {
-        uint16_t other_return_type_idx;
-        std::vector<uint16_t> other_param_type_idxs;
-        bool success = other_dexfile.CreateTypeList(
-            dexfile->GetMethodSignature(mid).ToString(), &other_return_type_idx,
-            &other_param_type_idxs);
-        if (success) {
-          const DexFile::ProtoId* other_sig =
-              other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs);
-          if (other_sig != nullptr) {
-            const  DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
-                *other_type_id, *other_name, *other_sig);
-            if (other_mid != nullptr) {
-              return other_dexfile.GetIndexForMethodId(*other_mid);
-            }
-          }
-        }
-      }
-    }
-  }
-  return DexFile::kDexNoIndex;
-}
-
-template <template <typename> class HandleKind>
-uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(
-    const DexFile& other_dexfile, uint32_t name_and_signature_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtMethod* method = GetMethod();
-  const DexFile* dexfile = method->GetDexFile();
-  const uint32_t dex_method_idx = method->GetDexMethodIndex();
-  const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
-  const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
-  DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
-  DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
-  if (dexfile == &other_dexfile) {
-    return dex_method_idx;
-  }
-  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
-  const DexFile::StringId* other_descriptor =
-      other_dexfile.FindStringId(mid_declaring_class_descriptor);
-  if (other_descriptor != nullptr) {
-    const DexFile::TypeId* other_type_id =
-        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
-    if (other_type_id != nullptr) {
-      const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
-          *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
-          other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
-      if (other_mid != nullptr) {
-        return other_dexfile.GetIndexForMethodId(*other_mid);
-      }
-    }
-  }
-  return DexFile::kDexNoIndex;
-}
-
-// Instantiate methods.
-template mirror::String* MethodHelperT<Handle>::GetNameAsString(Thread* self);
-
-template mirror::String* MethodHelperT<MutableHandle>::GetNameAsString(Thread* self);
-
-template
-uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile);
-template
-uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
-    const DexFile& other_dexfile);
-
-template
-uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
-                                                                 uint32_t name_and_signature_idx);
-template
-uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
-    const DexFile& other_dexfile, uint32_t name_and_signature_idx);
-
-template
-bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<Handle>(
-    MethodHelperT<Handle>* other);
-
-template
-bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<MutableHandle>(
-    MethodHelperT<MutableHandle>* other);
-
-template
-bool MethodHelperT<MutableHandle>::HasSameSignatureWithDifferentClassLoaders<Handle>(
-    MethodHelperT<Handle>* other);
-
-template
-bool MethodHelperT<MutableHandle>::HasSameSignatureWithDifferentClassLoaders<MutableHandle>(
-    MethodHelperT<MutableHandle>* other);
-
-}  // namespace art
diff --git a/runtime/method_helper.h b/runtime/method_helper.h
deleted file mode 100644
index fe364d3..0000000
--- a/runtime/method_helper.h
+++ /dev/null
@@ -1,168 +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.
- */
-
-#ifndef ART_RUNTIME_METHOD_HELPER_H_
-#define ART_RUNTIME_METHOD_HELPER_H_
-
-#include "base/macros.h"
-#include "handle.h"
-#include "mirror/art_method.h"
-#include "primitive.h"
-
-namespace art {
-
-template <template <class T> class HandleKind>
-class MethodHelperT {
- public:
-  explicit MethodHelperT(HandleKind<mirror::ArtMethod> m)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : method_(m), shorty_(nullptr), shorty_len_(0) {
-  }
-
-  mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetInterfaceMethodIfProxy();
-  }
-
-  // GetMethod() != Get() for proxy methods.
-  mirror::ArtMethod* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_.Get();
-  }
-
-  mirror::String* GetNameAsString(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const char* result = shorty_;
-    if (result == nullptr) {
-      result = method_->GetShorty(&shorty_len_);
-      shorty_ = result;
-    }
-    return result;
-  }
-
-  uint32_t GetShortyLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (shorty_ == nullptr) {
-      GetShorty();
-    }
-    return shorty_len_;
-  }
-
-  // Counts the number of references in the parameter list of the corresponding method.
-  // Note: Thus does _not_ include "this" for non-static methods.
-  uint32_t GetNumberOfReferenceArgsWithoutReceiver() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const char* shorty = GetShorty();
-    uint32_t refs = 0;
-    for (uint32_t i = 1; i < shorty_len_ ; ++i) {
-      if (shorty[i] == 'L') {
-        refs++;
-      }
-    }
-
-    return refs;
-  }
-
-  // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
-  // number of bugs at call sites.
-  mirror::Class* GetReturnType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // "1 +" because the first in Args is the receiver.
-    // "- 1" because we don't count the return type.
-    return (method_->IsStatic() ? 0 : 1) + GetShortyLength() - 1;
-  }
-
-  // Get the primitive type associated with the given parameter.
-  Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_LT(param, NumArgs());
-    if (GetMethod()->IsStatic()) {
-      param++;  // 0th argument must skip return value at start of the shorty
-    } else if (param == 0) {
-      return Primitive::kPrimNot;
-    }
-    return Primitive::GetType(GetShorty()[param]);
-  }
-
-  // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods.
-  bool IsParamALongOrDouble(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Primitive::Type type = GetParamPrimitiveType(param);
-    return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
-  }
-
-  // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods.
-  bool IsParamAReference(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetParamPrimitiveType(param) == Primitive::kPrimNot;
-  }
-
-  template <template <class T> class HandleKind2>
-  ALWAYS_INLINE bool HasSameNameAndSignature(MethodHelperT<HandleKind2>* other)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  template <template <class T> class HandleKind2>
-  bool HasSameSignatureWithDifferentClassLoaders(MethodHelperT<HandleKind2>* other)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  mirror::String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // The name_and_signature_idx MUST point to a MethodId with the same name and signature in the
-  // other_dexfile, such as the method index used to resolve this method in the other_dexfile.
-  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
-                                            uint32_t name_and_signature_idx)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- protected:
-  HandleKind<mirror::ArtMethod> method_;
-
-  const char* shorty_;
-  uint32_t shorty_len_;
-
- private:
-  template <template <class T2> class HandleKind2> friend class MethodHelperT;
-
-  DISALLOW_COPY_AND_ASSIGN(MethodHelperT);
-};
-
-class MethodHelper : public MethodHelperT<Handle> {
-  using MethodHelperT<Handle>::MethodHelperT;
- private:
-  DISALLOW_COPY_AND_ASSIGN(MethodHelper);
-};
-
-class MutableMethodHelper : public MethodHelperT<MutableHandle> {
-  using MethodHelperT<MutableHandle>::MethodHelperT;
- public:
-  void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(new_m != nullptr);
-    SetMethod(new_m);
-    shorty_ = nullptr;
-  }
-
- private:
-  // Set the method_ field, for proxy methods looking up the interface method via the resolved
-  // methods table.
-  void SetMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    method_.Assign(method);
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(MutableMethodHelper);
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_METHOD_HELPER_H_
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 6582226..048d8ba 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -19,6 +19,7 @@
 
 #include "array.h"
 
+#include "base/stringprintf.h"
 #include "class.h"
 #include "gc/heap-inl.h"
 #include "thread.h"
@@ -45,6 +46,14 @@
   return header_size + data_size;
 }
 
+inline MemberOffset Array::DataOffset(size_t component_size) {
+  DCHECK(IsPowerOfTwo(component_size)) << component_size;
+  size_t data_offset = RoundUp(OFFSETOF_MEMBER(Array, first_element_), component_size);
+  DCHECK_EQ(RoundUp(data_offset, component_size), data_offset)
+      << "Array data offset isn't aligned with component size";
+  return MemberOffset(data_offset);
+}
+
 template<VerifyObjectFlags kVerifyFlags>
 inline bool Array::CheckIsValidIndex(int32_t index) {
   if (UNLIKELY(static_cast<uint32_t>(index) >=
@@ -73,6 +82,7 @@
   // 64-bit. No overflow as component_count is 32-bit and the maximum
   // component size is 8.
   DCHECK_LE((1U << component_size_shift), 8U);
+  UNUSED(self);
 #else
   // 32-bit.
   DCHECK_NE(header_size, 0U);
@@ -128,10 +138,10 @@
     // DCHECK(array->IsArrayInstance());
     int32_t length = (usable_size - header_size_) >> component_size_shift_;
     DCHECK_GE(length, minimum_length_);
-    byte* old_end = reinterpret_cast<byte*>(array->GetRawData(1U << component_size_shift_,
-                                                              minimum_length_));
-    byte* new_end = reinterpret_cast<byte*>(array->GetRawData(1U << component_size_shift_,
-                                                              length));
+    uint8_t* old_end = reinterpret_cast<uint8_t*>(array->GetRawData(1U << component_size_shift_,
+                                                                    minimum_length_));
+    uint8_t* new_end = reinterpret_cast<uint8_t*>(array->GetRawData(1U << component_size_shift_,
+                                                                    length));
     // Ensure space beyond original allocation is zeroed.
     memset(old_end, 0, new_end - old_end);
     array->SetLength(length);
@@ -190,9 +200,7 @@
 
 template<class T>
 inline void PrimitiveArray<T>::VisitRoots(RootCallback* callback, void* arg) {
-  if (!array_class_.IsNull()) {
-    array_class_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  array_class_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 template<typename T>
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 636be33..b92f017 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -58,8 +58,8 @@
   if (current_dimension + 1 < dimensions->GetLength()) {
     // Create a new sub-array in every element of the array.
     for (int32_t i = 0; i < array_length; i++) {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::Class> h_component_type(hs.NewHandle(array_class->GetComponentType()));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::Class> h_component_type(hs2.NewHandle(array_class->GetComponentType()));
       Array* sub_array = RecursiveCreateMultiArray(self, h_component_type,
                                                    current_dimension + 1, dimensions);
       if (UNLIKELY(sub_array == nullptr)) {
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 521d7e7..83e3688 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -49,7 +49,7 @@
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Array, length_));
   }
 
@@ -64,13 +64,7 @@
     return OFFSET_OF_OBJECT_MEMBER(Array, length_);
   }
 
-  static MemberOffset DataOffset(size_t component_size) {
-    DCHECK(IsPowerOfTwo(component_size)) << component_size;
-    size_t data_offset = RoundUp(OFFSETOF_MEMBER(Array, first_element_), component_size);
-    DCHECK_EQ(RoundUp(data_offset, component_size), data_offset)
-        << "Array data offset isn't aligned with component size";
-    return MemberOffset(data_offset);
-  }
+  static MemberOffset DataOffset(size_t component_size);
 
   void* GetRawData(size_t component_size, int32_t index)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -88,7 +82,7 @@
   // Returns true if the index is valid. If not, throws an ArrayIndexOutOfBoundsException and
   // returns false.
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  bool CheckIsValidIndex(int32_t index) ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE bool CheckIsValidIndex(int32_t index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
   void ThrowArrayStoreException(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h
index 03425cc..2b406bd 100644
--- a/runtime/mirror/art_field-inl.h
+++ b/runtime/mirror/art_field-inl.h
@@ -20,6 +20,7 @@
 #include "art_field.h"
 
 #include "base/logging.h"
+#include "class_linker.h"
 #include "dex_cache.h"
 #include "gc/accounting/card_table-inl.h"
 #include "jvalue.h"
@@ -289,6 +290,22 @@
   return GetTypeAsPrimitiveType() != Primitive::kPrimNot;
 }
 
+inline Class* ArtField::GetType(bool resolve) {
+  uint32_t field_index = GetDexFieldIndex();
+  if (UNLIKELY(GetDeclaringClass()->IsProxyClass())) {
+    return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
+                                                                 GetTypeDescriptor());
+  }
+  const DexFile* dex_file = GetDexFile();
+  const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index);
+  mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
+  if (resolve && (type == nullptr)) {
+    type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, this);
+    CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
+  }
+  return type;
+}
+
 inline size_t ArtField::FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return Primitive::ComponentSize(GetTypeAsPrimitiveType());
 }
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index 7e20076..5a4ebd1 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -56,9 +56,7 @@
 }
 
 void ArtField::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_reflect_ArtField_.IsNull()) {
-    java_lang_reflect_ArtField_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_reflect_ArtField_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 // TODO: we could speed up the search if fields are ordered by offsets.
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 50299b6..a1d8844 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -161,6 +161,8 @@
 
   bool IsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  Class* GetType(bool resolve) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   size_t FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 8447616..7d31148 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -24,8 +24,7 @@
 #include "class_linker.h"
 #include "dex_cache.h"
 #include "dex_file.h"
-#include "entrypoints/entrypoint_utils.h"
-#include "method_helper.h"
+#include "dex_file-inl.h"
 #include "object-inl.h"
 #include "object_array.h"
 #include "oat.h"
@@ -69,19 +68,13 @@
   return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_));
 }
 
-inline uint32_t ArtMethod::GetDexMethodIndex() {
-#ifdef ART_SEA_IR_MODE
-  // TODO: Re-add this check for (PORTABLE + SMALL + ) SEA IR when PORTABLE IS fixed!
-  // DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-#else
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-#endif
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_));
+inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
+  return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_));
 }
 
-inline ObjectArray<String>* ArtMethod::GetDexCacheStrings() {
-  return GetFieldObject<ObjectArray<String>>(
-      OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_));
+inline uint32_t ArtMethod::GetDexMethodIndex() {
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
+  return GetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_));
 }
 
 inline ObjectArray<ArtMethod>* ArtMethod::GetDexCacheResolvedMethods() {
@@ -143,6 +136,15 @@
   return GetDexCacheResolvedTypes() == other->GetDexCacheResolvedTypes();
 }
 
+inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx, bool resolve) {
+  mirror::Class* type = GetDexCacheResolvedType(type_idx);
+  if (type == nullptr && resolve) {
+    type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
+    CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
+  }
+  return type;
+}
+
 inline uint32_t ArtMethod::GetCodeSize() {
   DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
   const void* code = EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode());
@@ -172,88 +174,31 @@
     }
     default:
       LOG(FATAL) << "Unreachable - invocation type: " << type;
-      return true;
+      UNREACHABLE();
   }
 }
 
-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());
 }
 
-inline uint32_t ArtMethod::GetPortableOatCodeOffset() {
-  DCHECK(!Runtime::Current()->IsStarted());
-  return PointerToLowMemUInt32(GetEntryPointFromPortableCompiledCode());
-}
-
 inline void ArtMethod::SetQuickOatCodeOffset(uint32_t code_offset) {
   DCHECK(!Runtime::Current()->IsStarted());
   SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>(code_offset));
 }
 
-inline void ArtMethod::SetPortableOatCodeOffset(uint32_t code_offset) {
-  DCHECK(!Runtime::Current()->IsStarted());
-  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();
+inline const uint8_t* ArtMethod::GetMappingTable(size_t pointer_size) {
+  const void* code_pointer = GetQuickOatCodePointer(pointer_size);
   if (code_pointer == nullptr) {
     return nullptr;
   }
-  return GetMappingTable(code_pointer);
+  return GetMappingTable(code_pointer, pointer_size);
 }
 
-inline const uint8_t* ArtMethod::GetMappingTable(const void* code_pointer) {
+inline const uint8_t* ArtMethod::GetMappingTable(const void* code_pointer, size_t pointer_size) {
   DCHECK(code_pointer != nullptr);
-  DCHECK(code_pointer == GetQuickOatCodePointer());
+  DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
   uint32_t offset =
       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].mapping_table_offset_;
   if (UNLIKELY(offset == 0u)) {
@@ -262,20 +207,18 @@
   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
 }
 
-inline const uint8_t* ArtMethod::GetVmapTable() {
-  const void* code_pointer = GetQuickOatCodePointer();
+inline const uint8_t* ArtMethod::GetVmapTable(size_t pointer_size) {
+  const void* code_pointer = GetQuickOatCodePointer(pointer_size);
   if (code_pointer == nullptr) {
     return nullptr;
   }
-  return GetVmapTable(code_pointer);
+  return GetVmapTable(code_pointer, pointer_size);
 }
 
-inline const uint8_t* ArtMethod::GetVmapTable(const void* code_pointer) {
-  if (IsOptimized()) {
-    LOG(FATAL) << "Unimplemented vmap table for optimized compiler";
-  }
+inline const uint8_t* ArtMethod::GetVmapTable(const void* code_pointer, size_t pointer_size) {
+  CHECK(!IsOptimized(pointer_size)) << "Unimplemented vmap table for optimized compiler";
   DCHECK(code_pointer != nullptr);
-  DCHECK(code_pointer == GetQuickOatCodePointer());
+  DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
   uint32_t offset =
       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
   if (UNLIKELY(offset == 0u)) {
@@ -289,8 +232,8 @@
 }
 
 inline CodeInfo ArtMethod::GetOptimizedCodeInfo() {
-  DCHECK(IsOptimized());
-  const void* code_pointer = GetQuickOatCodePointer();
+  DCHECK(IsOptimized(sizeof(void*)));
+  const void* code_pointer = GetQuickOatCodePointer(sizeof(void*));
   DCHECK(code_pointer != nullptr);
   uint32_t offset =
       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
@@ -298,14 +241,23 @@
   return CodeInfo(data);
 }
 
-inline void ArtMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) {
-  DCHECK(!Runtime::Current()->IsStarted());
-  SetNativeGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
+inline const uint8_t* ArtMethod::GetNativeGcMap(size_t pointer_size) {
+  const void* code_pointer = GetQuickOatCodePointer(pointer_size);
+  if (code_pointer == nullptr) {
+    return nullptr;
+  }
+  return GetNativeGcMap(code_pointer, pointer_size);
 }
 
-inline uint32_t ArtMethod::GetOatNativeGcMapOffset() {
-  DCHECK(!Runtime::Current()->IsStarted());
-  return PointerToLowMemUInt32(GetNativeGcMap());
+inline const uint8_t* ArtMethod::GetNativeGcMap(const void* code_pointer, size_t pointer_size) {
+  DCHECK(code_pointer != nullptr);
+  DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
+  uint32_t offset =
+      reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].gc_map_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
 }
 
 inline bool ArtMethod::IsRuntimeMethod() {
@@ -341,77 +293,27 @@
   return result;
 }
 
-inline uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc) {
-  const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
+inline bool ArtMethod::IsImtUnimplementedMethod() {
+  bool result = this == Runtime::Current()->GetImtUnimplementedMethod();
+  // Check that if we do think it is phony it looks like the imt unimplemented method.
+  DCHECK(!result || IsRuntimeMethod());
+  return result;
+}
+
+inline uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc) {
+  const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(
+      this, sizeof(void*));
   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
-                                - kPointerSize  // 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());
+  DCHECK_EQ(code_pointer, GetQuickOatCodePointer(sizeof(void*)));
   return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
 }
 
 inline const DexFile* ArtMethod::GetDexFile() {
-  return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetDexCache()->GetDexFile();
+  return GetDexCache()->GetDexFile();
 }
 
 inline const char* ArtMethod::GetDeclaringClassDescriptor() {
@@ -464,8 +366,7 @@
 }
 
 inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
-  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
-  return method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset());
+  return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
 }
 
 inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx) {
@@ -531,11 +432,15 @@
   return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetDexCache();
 }
 
+inline bool ArtMethod::IsProxyMethod() {
+  return GetDeclaringClass()->IsProxyClass();
+}
+
 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy() {
-  mirror::Class* klass = GetDeclaringClass();
-  if (LIKELY(!klass->IsProxyClass())) {
+  if (LIKELY(!IsProxyMethod())) {
     return this;
   }
+  mirror::Class* klass = GetDeclaringClass();
   mirror::ArtMethod* interface_method = GetDexCacheResolvedMethods()->Get(GetDexMethodIndex());
   DCHECK(interface_method != nullptr);
   DCHECK_EQ(interface_method,
@@ -543,6 +448,40 @@
   return interface_method;
 }
 
+inline void ArtMethod::SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) {
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
+                        new_dex_cache_methods);
+}
+
+inline void ArtMethod::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
+                        new_dex_cache_classes);
+}
+
+inline mirror::Class* ArtMethod::GetReturnType(bool resolve) {
+  DCHECK(!IsProxyMethod());
+  const DexFile* dex_file = GetDexFile();
+  const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
+  const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
+  uint16_t return_type_idx = proto_id.return_type_idx_;
+  mirror::Class* type = GetDexCacheResolvedType(return_type_idx);
+  if (type == nullptr && resolve) {
+    type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
+    CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
+  }
+  return type;
+}
+
+inline void ArtMethod::CheckObjectSizeEqualsMirrorSize() {
+  // Using the default, check the class object size to make sure it matches the size of the
+  // object.
+  size_t this_size = sizeof(*this);
+#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+  this_size += sizeof(void*) - sizeof(uint32_t);
+#endif
+  DCHECK_EQ(GetClass()->GetObjectSize(), this_size);
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 787c767..288f6a6 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -23,11 +23,12 @@
 #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"
 #include "mapping_table.h"
-#include "method_helper-inl.h"
 #include "object_array-inl.h"
 #include "object_array.h"
 #include "object-inl.h"
@@ -38,10 +39,9 @@
 namespace art {
 namespace mirror {
 
-extern "C" void art_portable_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
 extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
                                       const char*);
-#ifdef __LP64__
+#if defined(__LP64__) || defined(__arm__)
 extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
                                              const char*);
 #endif
@@ -60,9 +60,18 @@
 
 
 void ArtMethod::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_reflect_ArtMethod_.IsNull()) {
-    java_lang_reflect_ArtMethod_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_reflect_ArtMethod_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
+}
+
+mirror::String* ArtMethod::GetNameAsString(Thread* self) {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  const DexFile* dex_file = method->GetDexFile();
+  uint32_t dex_method_idx = method->GetDexMethodIndex();
+  const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx);
+  StackHandleScope<1> hs(self);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+  return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_,
+                                                             dex_cache);
 }
 
 InvokeType ArtMethod::GetInvokeType() {
@@ -80,7 +89,7 @@
 
 void ArtMethod::SetClass(Class* java_lang_reflect_ArtMethod) {
   CHECK(java_lang_reflect_ArtMethod_.IsNull());
-  CHECK(java_lang_reflect_ArtMethod != NULL);
+  CHECK(java_lang_reflect_ArtMethod != nullptr);
   java_lang_reflect_ArtMethod_ = GcRoot<Class>(java_lang_reflect_ArtMethod);
 }
 
@@ -89,21 +98,6 @@
   java_lang_reflect_ArtMethod_ = GcRoot<Class>(nullptr);
 }
 
-void ArtMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
-                        new_dex_cache_strings);
-}
-
-void ArtMethod::SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) {
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
-                        new_dex_cache_methods);
-}
-
-void ArtMethod::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
-                        new_dex_cache_classes);
-}
-
 size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) {
   CHECK_LE(1U, shorty.length());
   uint32_t num_registers = 0;
@@ -118,18 +112,31 @@
   return num_registers;
 }
 
-bool ArtMethod::IsProxyMethod() {
-  return GetDeclaringClass()->IsProxyClass();
+static bool HasSameNameAndSignature(ArtMethod* method1, ArtMethod* method2)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedAssertNoThreadSuspension ants(Thread::Current(), "HasSameNameAndSignature");
+  const DexFile* dex_file = method1->GetDexFile();
+  const DexFile::MethodId& mid = dex_file->GetMethodId(method1->GetDexMethodIndex());
+  if (method1->GetDexCache() == method2->GetDexCache()) {
+    const DexFile::MethodId& mid2 = dex_file->GetMethodId(method2->GetDexMethodIndex());
+    return mid.name_idx_ == mid2.name_idx_ && mid.proto_idx_ == mid2.proto_idx_;
+  }
+  const DexFile* dex_file2 = method2->GetDexFile();
+  const DexFile::MethodId& mid2 = dex_file2->GetMethodId(method2->GetDexMethodIndex());
+  if (!DexFileStringEquals(dex_file, mid.name_idx_, dex_file2, mid2.name_idx_)) {
+    return false;  // Name mismatch.
+  }
+  return dex_file->GetMethodSignature(mid) == dex_file2->GetMethodSignature(mid2);
 }
 
 ArtMethod* ArtMethod::FindOverriddenMethod() {
   if (IsStatic()) {
-    return NULL;
+    return nullptr;
   }
   Class* declaring_class = GetDeclaringClass();
   Class* super_class = declaring_class->GetSuperClass();
   uint16_t method_index = GetMethodIndex();
-  ArtMethod* result = NULL;
+  ArtMethod* result = nullptr;
   // Did this method override a super class method? If so load the result from the super class'
   // vtable
   if (super_class->HasVTable() && method_index < super_class->GetVTableLength()) {
@@ -141,16 +148,13 @@
       CHECK_EQ(result,
                Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
     } else {
-      StackHandleScope<2> hs(Thread::Current());
-      MethodHelper mh(hs.NewHandle(this));
-      MutableMethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
       IfTable* iftable = GetDeclaringClass()->GetIfTable();
-      for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
+      for (size_t i = 0; i < iftable->Count() && result == nullptr; i++) {
         Class* interface = iftable->GetInterface(i);
         for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
-          interface_mh.ChangeMethod(interface->GetVirtualMethod(j));
-          if (mh.HasSameNameAndSignature(&interface_mh)) {
-            result = interface_mh.GetMethod();
+          mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j);
+          if (HasSameNameAndSignature(this, interface_method)) {
+            result = interface_method;
             break;
           }
         }
@@ -158,29 +162,56 @@
     }
   }
   if (kIsDebugBuild) {
-    StackHandleScope<2> hs(Thread::Current());
-    MethodHelper result_mh(hs.NewHandle(result));
-    MethodHelper this_mh(hs.NewHandle(this));
-    DCHECK(result == nullptr || this_mh.HasSameNameAndSignature(&result_mh));
+    DCHECK(result == nullptr || HasSameNameAndSignature(this, result));
   }
   return result;
 }
 
-uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
-  if (IsPortableCompiled()) {
-    // Portable doesn't use the machine pc, we just use dex pc instead.
-    return static_cast<uint32_t>(pc);
+uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+                                                     uint32_t name_and_signature_idx) {
+  const DexFile* dexfile = GetDexFile();
+  const uint32_t dex_method_idx = GetDexMethodIndex();
+  const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
+  const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
+  DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
+  DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
+  if (dexfile == &other_dexfile) {
+    return dex_method_idx;
   }
-  const void* entry_point = GetQuickOatEntryPoint();
-  MappingTable table(
-      entry_point != nullptr ? GetMappingTable(EntryPointToCodePointer(entry_point)) : nullptr);
+  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
+  const DexFile::StringId* other_descriptor =
+      other_dexfile.FindStringId(mid_declaring_class_descriptor);
+  if (other_descriptor != nullptr) {
+    const DexFile::TypeId* other_type_id =
+        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
+    if (other_type_id != nullptr) {
+      const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
+          *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
+          other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
+      if (other_mid != nullptr) {
+        return other_dexfile.GetIndexForMethodId(*other_mid);
+      }
+    }
+  }
+  return DexFile::kDexNoIndex;
+}
+
+uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
+  const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
+  uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
+  if (IsOptimized(sizeof(void*))) {
+    uint32_t ret = GetStackMap(sought_offset).GetDexPc();
+    return ret;
+  }
+
+  MappingTable table(entry_point != nullptr ?
+      GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
   if (table.TotalSize() == 0) {
     // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
     // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
     DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
     return DexFile::kDexNoIndex;   // Special no mapping case
   }
-  uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
   // Assume the caller wants a pc-to-dex mapping so check here first.
   typedef MappingTable::PcToDexIterator It;
   for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
@@ -203,10 +234,10 @@
   return DexFile::kDexNoIndex;
 }
 
-uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) {
-  const void* entry_point = GetQuickOatEntryPoint();
-  MappingTable table(
-      entry_point != nullptr ? GetMappingTable(EntryPointToCodePointer(entry_point)) : nullptr);
+uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure) {
+  const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
+  MappingTable table(entry_point != nullptr ?
+      GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
   if (table.TotalSize() == 0) {
     DCHECK_EQ(dex_pc, 0U);
     return 0;   // Special no mapping/pc == 0 case
@@ -225,14 +256,15 @@
       return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
     }
   }
-  LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
-             << " in " << PrettyMethod(this);
-  return 0;
+  if (abort_on_failure) {
+    LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
+               << " in " << PrettyMethod(this);
+  }
+  return UINTPTR_MAX;
 }
 
 uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type,
                                    uint32_t dex_pc, bool* has_no_move_exception) {
-  MethodHelper mh(h_this);
   const DexFile::CodeItem* code_item = h_this->GetCodeItem();
   // Set aside the exception while we resolve its type.
   Thread* self = Thread::Current();
@@ -252,7 +284,7 @@
       break;
     }
     // Does this catch exception type apply?
-    Class* iter_exception_type = mh.GetClassFromTypeIdx(iter_type_idx);
+    Class* iter_exception_type = h_this->GetClassFromTypeIndex(iter_type_idx, true);
     if (UNLIKELY(iter_exception_type == nullptr)) {
       // Now have a NoClassDefFoundError as exception. Ignore in case the exception class was
       // removed by a pro-guard like tool.
@@ -281,19 +313,67 @@
   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.
-    return oat_quick_code == nullptr ||
-        oat_quick_code != GetEntryPointFromQuickCompiledCode();
-  } else {  // Portable.
-    return oat_portable_code == nullptr ||
-        oat_portable_code != GetEntryPointFromPortableCompiledCode();
-  }
+  return oat_quick_code == nullptr || oat_quick_code != GetEntryPointFromQuickCompiledCode();
 }
 
+const void* ArtMethod::GetQuickOatEntryPoint(size_t pointer_size) {
+  if (IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
+    return nullptr;
+  }
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(this, pointer_size);
+  // 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, sizeof(void*)));
+  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())) {
@@ -323,53 +403,44 @@
   } else {
     const bool kLogInvocationStartAndReturn = false;
     bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;
-    bool have_portable_code = GetEntryPointFromPortableCompiledCode() != nullptr;
-    if (LIKELY(have_quick_code || have_portable_code)) {
+    if (LIKELY(have_quick_code)) {
       if (kLogInvocationStartAndReturn) {
-        LOG(INFO) << StringPrintf("Invoking '%s' %s code=%p", PrettyMethod(this).c_str(),
-                                  have_quick_code ? "quick" : "portable",
-                                  have_quick_code ? GetEntryPointFromQuickCompiledCode()
-                                                  : GetEntryPointFromPortableCompiledCode());
+        LOG(INFO) << StringPrintf("Invoking '%s' quick code=%p", PrettyMethod(this).c_str(),
+                                  GetEntryPointFromQuickCompiledCode());
       }
 
-      // Ensure that we won't be accidentally calling quick/portable compiled code when -Xint.
+      // Ensure that we won't be accidentally calling quick compiled code when -Xint.
       if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()) {
         CHECK(IsEntrypointInterpreter())
             << "Don't call compiled code when -Xint " << PrettyMethod(this);
       }
 
-      if (!IsPortableCompiled()) {
-#ifdef __LP64__
-        if (!IsStatic()) {
-          (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
-        } else {
-          (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
-        }
-#else
+#if defined(__LP64__) || defined(__arm__)
+      if (!IsStatic()) {
         (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
-#endif
       } else {
-        (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
+        (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
       }
+#else
+      (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
+#endif
       if (UNLIKELY(self->GetException(nullptr) == Thread::GetDeoptimizationException())) {
         // Unusual case where we were running generated code and an
         // exception was thrown to force the activations to be removed from the
         // stack. Continue execution in the interpreter.
         self->ClearException();
         ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
-        self->SetTopOfStack(nullptr, 0);
+        self->SetTopOfStack(nullptr);
         self->SetTopOfShadowStack(shadow_frame);
         interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
       }
       if (kLogInvocationStartAndReturn) {
-        LOG(INFO) << StringPrintf("Returned '%s' %s code=%p", PrettyMethod(this).c_str(),
-                                  have_quick_code ? "quick" : "portable",
-                                  have_quick_code ? GetEntryPointFromQuickCompiledCode()
-                                                  : GetEntryPointFromPortableCompiledCode());
+        LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod(this).c_str(),
+                                  GetEntryPointFromQuickCompiledCode());
       }
     } else {
       LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null";
-      if (result != NULL) {
+      if (result != nullptr) {
         result->SetJ(0);
       }
     }
@@ -379,21 +450,90 @@
   self->PopManagedStackFragment(fragment);
 }
 
-void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_fast) {
-  DCHECK(Thread::Current() == self);
+// Counts the number of references in the parameter list of the corresponding method.
+// Note: Thus does _not_ include "this" for non-static methods.
+static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  uint32_t shorty_len;
+  const char* shorty = method->GetShorty(&shorty_len);
+  uint32_t refs = 0;
+  for (uint32_t i = 1; i < shorty_len ; ++i) {
+    if (shorty[i] == 'L') {
+      refs++;
+    }
+  }
+  return refs;
+}
+
+QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
+  Runtime* runtime = Runtime::Current();
+
+  if (UNLIKELY(IsAbstract())) {
+    return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+  }
+
+  // For Proxy method we add special handling for the direct method case  (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. However, if instrumentation stubs are installed, the
+  // instrumentation->GetQuickCodeFor() returns the artQuickProxyInvokeHandler instead of an
+  // oat code pointer, thus we have to add a special case here.
+  if (UNLIKELY(IsProxyMethod())) {
+    if (IsDirect()) {
+      CHECK(IsConstructor());
+      return GetQuickFrameInfo(EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode()));
+    } else {
+      return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+    }
+  }
+
+  if (UNLIKELY(IsRuntimeMethod())) {
+    return runtime->GetRuntimeMethodFrameInfo(this);
+  }
+
+  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this, sizeof(void*));
+  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 = GetNumberOfReferenceArgsWithoutReceiver(this) + 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);
+  CHECK(native_method != nullptr) << PrettyMethod(this);
   if (is_fast) {
     SetAccessFlags(GetAccessFlags() | kAccFastNative);
   }
-  SetNativeMethod(native_method);
+  SetEntryPointFromJni(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 de6ec05..f33ca94 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -20,11 +20,13 @@
 #include "dex_file.h"
 #include "gc_root.h"
 #include "invoke_type.h"
+#include "method_reference.h"
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
 #include "quick/quick_method_frame_info.h"
 #include "read_barrier_option.h"
+#include "stack.h"
 #include "stack_map.h"
 
 namespace art {
@@ -32,15 +34,16 @@
 struct ArtMethodOffsets;
 struct ConstructorMethodOffsets;
 union JValue;
-class MethodHelper;
 class ScopedObjectAccessAlreadyRunnable;
 class StringPiece;
 class ShadowFrame;
 
 namespace mirror {
 
-typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
-    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
+typedef void (EntryPointFromInterpreter)(Thread* self, const DexFile::CodeItem* code_item,
+                                         ShadowFrame* shadow_frame, JValue* result);
+
+#define ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
 
 // C++ mirror of java.lang.reflect.ArtMethod.
 class MANAGED ArtMethod FINAL : public Object {
@@ -48,11 +51,6 @@
   // Size of java.lang.reflect.ArtMethod.class.
   static uint32_t ClassSize();
 
-  // Size of an instance of java.lang.reflect.ArtMethod not including its value array.
-  static constexpr uint32_t InstanceSize() {
-    return sizeof(ArtMethod);
-  }
-
   static ArtMethod* FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
                                         jobject jlr_method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -65,7 +63,7 @@
     return MemberOffset(OFFSETOF_MEMBER(ArtMethod, declaring_class_));
   }
 
-  uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Not called within a transaction.
@@ -151,33 +149,23 @@
     SetAccessFlags(GetAccessFlags() | kAccPreverified);
   }
 
-  bool IsOptimized() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  bool IsOptimized(size_t pointer_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Temporary solution for detecting if a method has been optimized: the compiler
     // does not create a GC map. Instead, the vmap table contains the stack map
     // (as in stack_map.h).
-    return (GetEntryPointFromQuickCompiledCode() != nullptr)
-        && (GetQuickOatCodePointer() != nullptr)
-        && (GetNativeGcMap() == nullptr);
-  }
-
-  bool IsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return (GetAccessFlags() & kAccPortableCompiled) != 0;
-  }
-
-  void SetIsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(!IsPortableCompiled());
-    SetAccessFlags(GetAccessFlags() | kAccPortableCompiled);
-  }
-
-  void ClearIsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(IsPortableCompiled());
-    SetAccessFlags(GetAccessFlags() & ~kAccPortableCompiled);
+    return !IsNative()
+        && GetEntryPointFromQuickCompiledCodePtrSize(pointer_size) != nullptr
+        && GetQuickOatCodePointer(pointer_size) != nullptr
+        && GetNativeGcMap(pointer_size) == nullptr;
   }
 
   bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint16_t GetMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Doesn't do erroneous / unresolved class checks.
+  uint16_t GetMethodIndexDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   size_t GetVtableIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetMethodIndex();
   }
@@ -203,21 +191,13 @@
   // Number of 32bit registers that would be required to hold all the arguments
   static size_t NumArgRegisters(const StringPiece& shorty);
 
-  uint32_t GetDexMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE uint32_t GetDexMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetDexMethodIndex(uint32_t new_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Not called within a transaction.
     SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx);
   }
 
-  ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  static MemberOffset DexCacheStringsOffset() {
-    return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_);
-  }
-
   static MemberOffset DexCacheResolvedMethodsOffset() {
     return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_);
   }
@@ -226,11 +206,11 @@
     return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_);
   }
 
-  ArtMethod* GetDexCacheResolvedMethod(uint16_t method_idx)
+  ALWAYS_INLINE ArtMethod* GetDexCacheResolvedMethod(uint16_t method_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetDexCacheResolvedMethod(uint16_t method_idx, ArtMethod* new_method)
+  ALWAYS_INLINE void SetDexCacheResolvedMethod(uint16_t method_idx, ArtMethod* new_method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods)
+  ALWAYS_INLINE void SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool HasDexCacheResolvedMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool HasSameDexCacheResolvedMethods(ArtMethod* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -246,63 +226,85 @@
   bool HasSameDexCacheResolvedTypes(ObjectArray<Class>* other_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Find the method that this method overrides
+  // Get the Class* from the type index into this method's dex cache.
+  mirror::Class* GetClassFromTypeIndex(uint16_t type_idx, bool resolve)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Find the method that this method overrides.
   ArtMethod* FindOverriddenMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Find the method index for this method within other_dexfile. If this method isn't present then
+  // return DexFile::kDexNoIndex. The name_and_signature_idx MUST refer to a MethodId with the same
+  // name and signature in the other_dexfile, such as the method index used to resolve this method
+  // in the other_dexfile.
+  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+                                            uint32_t name_and_signature_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   EntryPointFromInterpreter* GetEntryPointFromInterpreter()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldPtr<EntryPointFromInterpreter*, kVerifyFlags>(
-        OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_));
+    CheckObjectSizeEqualsMirrorSize();
+    return GetEntryPointFromInterpreterPtrSize(sizeof(void*));
+  }
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  EntryPointFromInterpreter* GetEntryPointFromInterpreterPtrSize(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetFieldPtrWithSize<EntryPointFromInterpreter*, kVerifyFlags>(
+        EntryPointFromInterpreterOffset(pointer_size), pointer_size);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetFieldPtr<false, true, kVerifyFlags>(
-        OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_),
-        entry_point_from_interpreter);
+    CheckObjectSizeEqualsMirrorSize();
+    SetEntryPointFromInterpreterPtrSize(entry_point_from_interpreter, sizeof(void*));
   }
-
-  static MemberOffset EntryPointFromPortableCompiledCodeOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(ArtMethod, entry_point_from_portable_compiled_code_));
-  }
-
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  const void* GetEntryPointFromPortableCompiledCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldPtr<const void*, kVerifyFlags>(
-        EntryPointFromPortableCompiledCodeOffset());
-  }
-
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetEntryPointFromPortableCompiledCode(const void* entry_point_from_portable_compiled_code)
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void SetEntryPointFromInterpreterPtrSize(EntryPointFromInterpreter* entry_point_from_interpreter,
+                                           size_t pointer_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetFieldPtr<false, true, kVerifyFlags>(
-        EntryPointFromPortableCompiledCodeOffset(), entry_point_from_portable_compiled_code);
+    SetFieldPtrWithSize<false, true, kVerifyFlags>(
+        EntryPointFromInterpreterOffset(pointer_size), entry_point_from_interpreter, pointer_size);
   }
 
-  static MemberOffset EntryPointFromQuickCompiledCodeOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(ArtMethod, entry_point_from_quick_compiled_code_));
-  }
-
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   const void* GetEntryPointFromQuickCompiledCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldPtr<const void*, kVerifyFlags>(EntryPointFromQuickCompiledCodeOffset());
+    CheckObjectSizeEqualsMirrorSize();
+    return GetEntryPointFromQuickCompiledCodePtrSize(sizeof(void*));
+  }
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ALWAYS_INLINE const void* GetEntryPointFromQuickCompiledCodePtrSize(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetFieldPtrWithSize<const void*, kVerifyFlags>(
+        EntryPointFromQuickCompiledCodeOffset(pointer_size), pointer_size);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetEntryPointFromQuickCompiledCode(const void* entry_point_from_quick_compiled_code)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetFieldPtr<false, true, kVerifyFlags>(
-        EntryPointFromQuickCompiledCodeOffset(), entry_point_from_quick_compiled_code);
+    CheckObjectSizeEqualsMirrorSize();
+    SetEntryPointFromQuickCompiledCodePtrSize(entry_point_from_quick_compiled_code,
+                                              sizeof(void*));
+  }
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ALWAYS_INLINE void SetEntryPointFromQuickCompiledCodePtrSize(
+      const void* entry_point_from_quick_compiled_code, size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetFieldPtrWithSize<false, true, kVerifyFlags>(
+        EntryPointFromQuickCompiledCodeOffset(pointer_size), entry_point_from_quick_compiled_code,
+        pointer_size);
   }
 
   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;
@@ -325,45 +327,45 @@
   bool IsEntrypointInterpreter() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint32_t GetQuickOatCodeOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  uint32_t GetPortableOatCodeOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   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.
-  const void* GetQuickOatEntryPoint() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const void* GetQuickOatEntryPoint(size_t pointer_size)
+      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(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size));
+  }
 
   // Callers should wrap the uint8_t* in a MappingTable instance for convenient access.
-  const uint8_t* GetMappingTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const uint8_t* GetMappingTable(const void* code_pointer)
+  const uint8_t* GetMappingTable(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const uint8_t* GetMappingTable(const void* code_pointer, size_t pointer_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Callers should wrap the uint8_t* in a VmapTable instance for convenient access.
-  const uint8_t* GetVmapTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const uint8_t* GetVmapTable(const void* code_pointer)
+  const uint8_t* GetVmapTable(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const uint8_t* GetVmapTable(const void* code_pointer, size_t pointer_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   StackMap GetStackMap(uint32_t native_pc_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   CodeInfo GetOptimizedCodeInfo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const uint8_t* GetNativeGcMap() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_));
-  }
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetNativeGcMap(const uint8_t* data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetFieldPtr<false, true, kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), data);
-  }
-
-  // When building the oat need a convenient place to stuff the offset of the native GC map.
-  void SetOatNativeGcMapOffset(uint32_t gc_map_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  uint32_t GetOatNativeGcMapOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Callers should wrap the uint8_t* in a GcMap instance for convenient access.
+  const uint8_t* GetNativeGcMap(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const uint8_t* GetNativeGcMap(const void* code_pointer, size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template <bool kCheckFrameSize = true>
   uint32_t GetFrameSizeInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -378,35 +380,62 @@
   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 - kPointerSize;
+    return FrameOffset(frame_size_in_bytes - sizeof(void*));
   }
 
-  size_t GetHandleScopeOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return kPointerSize;
+  FrameOffset GetHandleScopeOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    constexpr size_t handle_scope_offset = sizeof(StackReference<mirror::ArtMethod>);
+    DCHECK_LT(handle_scope_offset, GetFrameSizeInBytes());
+    return FrameOffset(handle_scope_offset);
   }
 
-  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_);
+  static MemberOffset EntryPointFromInterpreterOffset(size_t pointer_size) {
+    return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
+        PtrSizedFields, entry_point_from_interpreter_) / sizeof(void*) * pointer_size);
   }
 
-  const void* GetNativeMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldPtr<const void*>(NativeMethodOffset());
+  static MemberOffset EntryPointFromJniOffset(size_t pointer_size) {
+    return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
+        PtrSizedFields, entry_point_from_jni_) / sizeof(void*) * pointer_size);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetNativeMethod(const void*) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static MemberOffset EntryPointFromQuickCompiledCodeOffset(size_t pointer_size) {
+    return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
+        PtrSizedFields, entry_point_from_quick_compiled_code_) / sizeof(void*) * pointer_size);
+  }
+
+  void* GetEntryPointFromJni() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CheckObjectSizeEqualsMirrorSize();
+    return GetEntryPointFromJniPtrSize(sizeof(void*));
+  }
+  ALWAYS_INLINE void* GetEntryPointFromJniPtrSize(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetFieldPtrWithSize<void*>(EntryPointFromJniOffset(pointer_size), pointer_size);
+  }
+
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void SetEntryPointFromJni(const void* entrypoint) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CheckObjectSizeEqualsMirrorSize();
+    SetEntryPointFromJniPtrSize<kVerifyFlags>(entrypoint, sizeof(void*));
+  }
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ALWAYS_INLINE void SetEntryPointFromJniPtrSize(const void* entrypoint, size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetFieldPtrWithSize<false, true, kVerifyFlags>(
+        EntryPointFromJniOffset(pointer_size), entrypoint, pointer_size);
+  }
 
   static MemberOffset GetMethodIndexOffset() {
     return OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_);
@@ -423,16 +452,30 @@
 
   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)
+  bool IsImtUnimplementedMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  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, bool abort_on_failure = true)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  MethodReference ToMethodReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return MethodReference(GetDexFile(), GetDexMethodIndex());
+  }
 
   // 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
@@ -466,6 +509,8 @@
 
   ALWAYS_INLINE const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  mirror::String* GetNameAsString(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::CodeItem* GetCodeItem() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsResolvedTypeIdx(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -487,12 +532,31 @@
   const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
+  // number of bugs at call sites.
+  mirror::Class* GetReturnType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  static size_t SizeWithoutPointerFields(size_t pointer_size) {
+    size_t total = sizeof(ArtMethod) - sizeof(PtrSizedFields);
+#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+    // Add 4 bytes if 64 bit, otherwise 0.
+    total += pointer_size - sizeof(uint32_t);
+#endif
+    return total;
+  }
+
+  // Size of an instance of java.lang.reflect.ArtMethod not including its value array.
+  static size_t InstanceSize(size_t pointer_size) {
+    return SizeWithoutPointerFields(pointer_size) +
+        (sizeof(PtrSizedFields) / sizeof(void*)) * pointer_size;
+  }
+
  protected:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // The class we are a part of.
@@ -504,29 +568,6 @@
   // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
   HeapReference<ObjectArray<Class>> dex_cache_resolved_types_;
 
-  // Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
-  HeapReference<ObjectArray<String>> dex_cache_strings_;
-
-  // Method dispatch from the interpreter invokes this pointer which may cause a bridge into
-  // compiled code.
-  uint64_t entry_point_from_interpreter_;
-
-  // Pointer to JNI function registered to this method, or a function to resolve the JNI function.
-  uint64_t entry_point_from_jni_;
-
-  // Method dispatch from portable compiled code invokes this pointer which may cause bridging into
-  // quick compiled code or the interpreter.
-  uint64_t entry_point_from_portable_compiled_code_;
-
-  // Method dispatch from quick compiled code invokes this pointer which may cause bridging into
-  // portable compiled code or the interpreter.
-  uint64_t entry_point_from_quick_compiled_code_;
-
-  // Pointer to a data structure created by the compiler and used by the garbage collector to
-  // determine which registers hold live references to objects within the heap. Keyed by native PC
-  // offsets for the quick compiler and dex PCs for the portable.
-  uint64_t gc_map_;
-
   // Access flags; low 16 bits are defined by spec.
   uint32_t access_flags_;
 
@@ -545,12 +586,41 @@
   // ifTable.
   uint32_t method_index_;
 
+  // Fake padding field gets inserted here.
+
+  // Must be the last fields in the method.
+  struct PACKED(4) PtrSizedFields {
+    // Method dispatch from the interpreter invokes this pointer which may cause a bridge into
+    // compiled code.
+    void* entry_point_from_interpreter_;
+
+    // Pointer to JNI function registered to this method, or a function to resolve the JNI function.
+    void* entry_point_from_jni_;
+
+    // Method dispatch from quick compiled code invokes this pointer which may cause bridging into
+    // the interpreter.
+    void* entry_point_from_quick_compiled_code_;
+  } ptr_sized_fields_;
+
   static GcRoot<Class> java_lang_reflect_ArtMethod_;
 
  private:
-  ObjectArray<ArtMethod>* GetDexCacheResolvedMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE void CheckObjectSizeEqualsMirrorSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ObjectArray<Class>* GetDexCacheResolvedTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ObjectArray<ArtMethod>* GetDexCacheResolvedMethods()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ALWAYS_INLINE ObjectArray<Class>* GetDexCacheResolvedTypes()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  static size_t PtrSizedFieldsOffset(size_t pointer_size) {
+    size_t offset = OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_);
+#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
+    // Add 4 bytes if 64 bit, otherwise 0.
+    offset += pointer_size - sizeof(uint32_t);
+#endif
+    return offset;
+  }
 
   friend struct art::ArtMethodOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(ArtMethod);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 3d3ae16..3dc9e08 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -112,20 +112,21 @@
 
 template<VerifyObjectFlags kVerifyFlags>
 inline ArtMethod* Class::GetVirtualMethod(uint32_t i) {
-  DCHECK(IsResolved<kVerifyFlags>() || IsErroneous<kVerifyFlags>());
-  return GetVirtualMethods()->Get(i);
+  DCHECK(IsResolved<kVerifyFlags>() || IsErroneous<kVerifyFlags>())
+      << PrettyClass(this) << " status=" << GetStatus();
+  return GetVirtualMethods()->GetWithoutChecks(i);
 }
 
 inline ArtMethod* Class::GetVirtualMethodDuringLinking(uint32_t i) {
   DCHECK(IsLoaded() || IsErroneous());
-  return GetVirtualMethods()->Get(i);
+  return GetVirtualMethods()->GetWithoutChecks(i);
 }
 
 inline void Class::SetVirtualMethod(uint32_t i, ArtMethod* f)  // TODO: uint16_t
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ObjectArray<ArtMethod>* virtual_methods =
       GetFieldObject<ObjectArray<ArtMethod>>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_));
-  virtual_methods->Set<false>(i, f);
+  virtual_methods->SetWithoutChecks<false>(i, f);
 }
 
 inline ObjectArray<ArtMethod>* Class::GetVTable() {
@@ -142,14 +143,6 @@
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable);
 }
 
-inline ObjectArray<ArtMethod>* Class::GetImTable() {
-  return GetFieldObject<ObjectArray<ArtMethod>>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_));
-}
-
-inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) {
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable);
-}
-
 inline ArtMethod* Class::GetEmbeddedImTableEntry(uint32_t i) {
   uint32_t offset = EmbeddedImTableOffset().Uint32Value() + i * sizeof(ImTableEntry);
   return GetFieldObject<mirror::ArtMethod>(MemberOffset(offset));
@@ -158,7 +151,6 @@
 inline void Class::SetEmbeddedImTableEntry(uint32_t i, ArtMethod* method) {
   uint32_t offset = EmbeddedImTableOffset().Uint32Value() + i * sizeof(ImTableEntry);
   SetFieldObject<false>(MemberOffset(offset), method);
-  CHECK(method == GetImTable()->Get(i));
 }
 
 inline bool Class::HasVTable() {
@@ -287,7 +279,7 @@
 template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type>
 inline bool Class::ResolvedMethodAccessTest(Class* access_to, ArtMethod* method,
                                             uint32_t method_idx, DexCache* dex_cache) {
-  COMPILE_ASSERT(throw_on_failure || throw_invoke_type == kStatic, non_default_throw_invoke_type);
+  static_assert(throw_on_failure || throw_invoke_type == kStatic, "Non-default throw invoke type");
   DCHECK_EQ(use_referrers_cache, dex_cache == nullptr);
   if (UNLIKELY(!this->CanAccess(access_to))) {
     // The referrer class can't access the method's declaring class but may still be able
@@ -410,6 +402,36 @@
   return GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
 }
 
+inline MemberOffset Class::GetFirstReferenceInstanceFieldOffset() {
+  Class* super_class = GetSuperClass();
+  return (super_class != nullptr)
+      ? MemberOffset(RoundUp(super_class->GetObjectSize(),
+                             sizeof(mirror::HeapReference<mirror::Object>)))
+      : ClassOffset();
+}
+
+inline MemberOffset Class::GetFirstReferenceStaticFieldOffset() {
+  DCHECK(IsResolved());
+  uint32_t base = sizeof(mirror::Class);  // Static fields come after the class.
+  if (ShouldHaveEmbeddedImtAndVTable()) {
+    // Static fields come after the embedded tables.
+    base = mirror::Class::ComputeClassSize(true, GetEmbeddedVTableLength(),
+                                           0, 0, 0, 0, 0);
+  }
+  return MemberOffset(base);
+}
+
+inline MemberOffset Class::GetFirstReferenceStaticFieldOffsetDuringLinking() {
+  DCHECK(IsLoaded());
+  uint32_t base = sizeof(mirror::Class);  // Static fields come after the class.
+  if (ShouldHaveEmbeddedImtAndVTable()) {
+    // Static fields come after the embedded tables.
+    base = mirror::Class::ComputeClassSize(true, GetVTableDuringLinking()->GetLength(),
+                                           0, 0, 0, 0, 0);
+  }
+  return MemberOffset(base);
+}
+
 inline void Class::SetIFields(ObjectArray<ArtField>* new_ifields)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(NULL == GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_)));
@@ -492,7 +514,15 @@
          IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() ||
          this == String::GetJavaLangString() ||
          this == ArtField::GetJavaLangReflectArtField() ||
-         this == ArtMethod::GetJavaLangReflectArtMethod());
+         this == ArtMethod::GetJavaLangReflectArtMethod())
+      << "IsIdxLoaded=" << IsIdxLoaded<kVerifyFlags>()
+      << " IsRetired=" << IsRetired<kVerifyFlags>()
+      << " IsErroneous=" <<
+          IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>()
+      << " IsString=" << (this == String::GetJavaLangString())
+      << " IsArtField=" << (this == ArtField::GetJavaLangReflectArtField())
+      << " IsArtMethod=" << (this == ArtMethod::GetJavaLangReflectArtMethod())
+      << " descriptor=" << PrettyDescriptor(this);
   return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
 }
 
@@ -553,6 +583,10 @@
                                                              allocator_type, VoidFunctor());
   if (add_finalizer && LIKELY(obj != nullptr)) {
     heap->AddFinalizerReference(self, &obj);
+    if (UNLIKELY(self->IsExceptionPending())) {
+      // Failed to allocate finalizer reference, it means that the whole allocation failed.
+      obj = nullptr;
+    }
   }
   return obj;
 }
@@ -615,12 +649,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);
@@ -761,6 +794,32 @@
   }
 }
 
+inline uint32_t Class::NumDirectInterfaces() {
+  if (IsPrimitive()) {
+    return 0;
+  } else if (IsArrayClass()) {
+    return 2;
+  } else if (IsProxyClass()) {
+    mirror::ObjectArray<mirror::Class>* interfaces = GetInterfaces();
+    return interfaces != nullptr ? interfaces->GetLength() : 0;
+  } else {
+    const DexFile::TypeList* interfaces = GetInterfaceTypeList();
+    if (interfaces == nullptr) {
+      return 0;
+    } else {
+      return interfaces->Size();
+    }
+  }
+}
+
+inline void Class::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
+  SetFieldObject<false>(DexCacheStringsOffset(), new_dex_cache_strings);
+}
+
+inline ObjectArray<String>* Class::GetDexCacheStrings() {
+  return GetFieldObject<ObjectArray<String>>(DexCacheStringsOffset());
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 3fcb188..ae684b1 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -52,9 +52,7 @@
 }
 
 void Class::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_Class_.IsNull()) {
-    java_lang_Class_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_Class_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 void Class::SetStatus(Status new_status, Thread* self) {
@@ -117,7 +115,7 @@
     self->SetException(gc_safe_throw_location, old_exception.Get());
     self->SetExceptionReportedToInstrumentation(is_exception_reported);
   }
-  COMPILE_ASSERT(sizeof(Status) == sizeof(uint32_t), size_of_status_not_uint32);
+  static_assert(sizeof(Status) == sizeof(uint32_t), "Size of status not equal to uint32");
   if (Runtime::Current()->IsActiveTransaction()) {
     SetField32Volatile<true>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status);
   } else {
@@ -149,6 +147,7 @@
 
 void Class::SetDexCache(DexCache* new_dex_cache) {
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache);
+  SetDexCacheStrings(new_dex_cache != nullptr ? new_dex_cache->GetStrings() : nullptr);
 }
 
 void Class::SetClassSize(uint32_t new_class_size) {
@@ -278,14 +277,15 @@
 }
 
 void Class::SetReferenceInstanceOffsets(uint32_t new_reference_offsets) {
-  if (new_reference_offsets != CLASS_WALK_SUPER) {
+  if (kIsDebugBuild && (new_reference_offsets != kClassWalkSuper)) {
     // Sanity check that the number of bits set in the reference offset bitmap
     // agrees with the number of references
-    size_t count = 0;
+    uint32_t count = 0;
     for (Class* c = this; c != nullptr; c = c->GetSuperClass()) {
       count += c->NumReferenceInstanceFieldsDuringLinking();
     }
-    CHECK_EQ((size_t)POPCOUNT(new_reference_offsets), count);
+    // +1 for the Class in Object.
+    CHECK_EQ(static_cast<uint32_t>(POPCOUNT(new_reference_offsets)) + 1, count);
   }
   // Not called within a transaction.
   SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
@@ -488,7 +488,10 @@
   if (GetDexCache() == dex_cache) {
     for (size_t i = 0; i < NumVirtualMethods(); ++i) {
       ArtMethod* method = GetVirtualMethod(i);
-      if (method->GetDexMethodIndex() == dex_method_idx) {
+      if (method->GetDexMethodIndex() == dex_method_idx &&
+          // A miranda method may have a different DexCache and is always created by linking,
+          // never *declared* in the class.
+          !method->IsMiranda()) {
         return method;
       }
     }
@@ -624,8 +627,8 @@
     HandleWrapper<mirror::Class> h_k(hs.NewHandleWrapper(&k));
     // Is this field in any of this class' interfaces?
     for (uint32_t i = 0; i < h_k->NumDirectInterfaces(); ++i) {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::Class> interface(hs.NewHandle(GetDirectInterface(self, h_k, i)));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::Class> interface(hs2.NewHandle(GetDirectInterface(self, h_k, i)));
       f = FindStaticField(self, interface, name, type);
       if (f != nullptr) {
         return f;
@@ -648,8 +651,8 @@
     HandleWrapper<mirror::Class> h_k(hs.NewHandleWrapper(&k));
     // Is this field in any of this class' interfaces?
     for (uint32_t i = 0; i < h_k->NumDirectInterfaces(); ++i) {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::Class> interface(hs.NewHandle(GetDirectInterface(self, h_k, i)));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::Class> interface(hs2.NewHandle(GetDirectInterface(self, h_k, i)));
       f = FindStaticField(self, interface, dex_cache, dex_field_idx);
       if (f != nullptr) {
         return f;
@@ -676,8 +679,8 @@
     StackHandleScope<1> hs(self);
     HandleWrapper<mirror::Class> h_k(hs.NewHandleWrapper(&k));
     for (uint32_t i = 0; i < h_k->NumDirectInterfaces(); ++i) {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::Class> interface(hs.NewHandle(GetDirectInterface(self, h_k, i)));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::Class> interface(hs2.NewHandle(GetDirectInterface(self, h_k, i)));
       f = interface->FindStaticField(self, interface, name, type);
       if (f != nullptr) {
         return f;
@@ -737,24 +740,6 @@
   return &GetDexFile().GetClassDef(class_def_idx);
 }
 
-uint32_t Class::NumDirectInterfaces() {
-  if (IsPrimitive()) {
-    return 0;
-  } else if (IsArrayClass()) {
-    return 2;
-  } else if (IsProxyClass()) {
-    mirror::ObjectArray<mirror::Class>* interfaces = GetInterfaces();
-    return interfaces != nullptr ? interfaces->GetLength() : 0;
-  } else {
-    const DexFile::TypeList* interfaces = GetInterfaceTypeList();
-    if (interfaces == nullptr) {
-      return 0;
-    } else {
-      return interfaces->Size();
-    }
-  }
-}
-
 uint16_t Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
   DCHECK(!IsPrimitive());
   DCHECK(!IsArrayClass());
@@ -816,22 +801,21 @@
   return GetDexFile().GetInterfacesList(*class_def);
 }
 
-void Class::PopulateEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ObjectArray<ArtMethod>* table = GetImTable();
-  if (table != nullptr) {
-    for (uint32_t i = 0; i < kImtSize; i++) {
-      SetEmbeddedImTableEntry(i, table->Get(i));
-    }
+void Class::PopulateEmbeddedImtAndVTable(StackHandleScope<kImtSize>* imt_handle_scope) {
+  for (uint32_t i = 0; i < kImtSize; i++) {
+    // Replace null with conflict.
+    mirror::Object* obj = imt_handle_scope->GetReference(i);
+    DCHECK(obj != nullptr);
+    SetEmbeddedImTableEntry(i, obj->AsArtMethod());
   }
 
-  table = GetVTableDuringLinking();
+  ObjectArray<ArtMethod>* table = GetVTableDuringLinking();
   CHECK(table != nullptr) << PrettyClass(this);
   SetEmbeddedVTableLength(table->GetLength());
   for (int32_t i = 0; i < table->GetLength(); i++) {
-    SetEmbeddedVTableEntry(i, table->Get(i));
+    SetEmbeddedVTableEntry(i, table->GetWithoutChecks(i));
   }
 
-  SetImTable(nullptr);
   // Keep java.lang.Object class's vtable around for since it's easier
   // to be reused by array classes during their linking.
   if (!IsObjectClass()) {
@@ -843,9 +827,10 @@
 class CopyClassVisitor {
  public:
   explicit CopyClassVisitor(Thread* self, Handle<mirror::Class>* orig,
-                            size_t new_length, size_t copy_bytes)
+                            size_t new_length, size_t copy_bytes,
+                            StackHandleScope<mirror::Class::kImtSize>* imt_handle_scope)
       : self_(self), orig_(orig), new_length_(new_length),
-        copy_bytes_(copy_bytes) {
+        copy_bytes_(copy_bytes), imt_handle_scope_(imt_handle_scope) {
   }
 
   void operator()(Object* obj, size_t usable_size) const
@@ -854,7 +839,7 @@
     mirror::Class* new_class_obj = obj->AsClass();
     mirror::Object::CopyObject(self_, new_class_obj, orig_->Get(), copy_bytes_);
     new_class_obj->SetStatus(Class::kStatusResolving, self_);
-    new_class_obj->PopulateEmbeddedImtAndVTable();
+    new_class_obj->PopulateEmbeddedImtAndVTable(imt_handle_scope_);
     new_class_obj->SetClassSize(new_length_);
   }
 
@@ -863,10 +848,12 @@
   Handle<mirror::Class>* const orig_;
   const size_t new_length_;
   const size_t copy_bytes_;
+  StackHandleScope<mirror::Class::kImtSize>* const imt_handle_scope_;
   DISALLOW_COPY_AND_ASSIGN(CopyClassVisitor);
 };
 
-Class* Class::CopyOf(Thread* self, int32_t new_length) {
+Class* Class::CopyOf(Thread* self, int32_t new_length,
+                     StackHandleScope<kImtSize>* imt_handle_scope) {
   DCHECK_GE(new_length, static_cast<int32_t>(sizeof(Class)));
   // We may get copied by a compacting GC.
   StackHandleScope<1> hs(self);
@@ -874,17 +861,15 @@
   gc::Heap* heap = Runtime::Current()->GetHeap();
   // The num_bytes (3rd param) is sizeof(Class) as opposed to SizeOf()
   // to skip copying the tail part that we will overwrite here.
-  CopyClassVisitor visitor(self, &h_this, new_length, sizeof(Class));
-
+  CopyClassVisitor visitor(self, &h_this, new_length, sizeof(Class), imt_handle_scope);
   mirror::Object* new_class =
       kMovingClasses
          ? heap->AllocObject<true>(self, java_lang_Class_.Read(), new_length, visitor)
          : heap->AllocNonMovableObject<true>(self, java_lang_Class_.Read(), new_length, visitor);
   if (UNLIKELY(new_class == nullptr)) {
     CHECK(self->IsExceptionPending());  // Expect an OOME.
-    return NULL;
+    return nullptr;
   }
-
   return new_class->AsClass();
 }
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 0acf695..bd49754 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -27,40 +27,11 @@
 #include "object_callbacks.h"
 #include "primitive.h"
 #include "read_barrier_option.h"
+#include "utils.h"
 
-/*
- * A magic value for refOffsets. Ignore the bits and walk the super
- * chain when this is the value.
- * [This is an unlikely "natural" value, since it would be 30 non-ref instance
- * fields followed by 2 ref instance fields.]
- */
-#define CLASS_WALK_SUPER 3U
-#define CLASS_BITS_PER_WORD (sizeof(uint32_t) * 8)
-#define CLASS_OFFSET_ALIGNMENT 4
-#define CLASS_HIGH_BIT (1U << (CLASS_BITS_PER_WORD - 1))
-/*
- * Given an offset, return the bit number which would encode that offset.
- * Local use only.
- */
-#define _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) \
-    ((unsigned int)(byteOffset) / \
-     CLASS_OFFSET_ALIGNMENT)
-/*
- * Is the given offset too large to be encoded?
- */
-#define CLASS_CAN_ENCODE_OFFSET(byteOffset) \
-    (_CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) < CLASS_BITS_PER_WORD)
-/*
- * Return a single bit, encoding the offset.
- * Undefined if the offset is too large, as defined above.
- */
-#define CLASS_BIT_FROM_OFFSET(byteOffset) \
-    (CLASS_HIGH_BIT >> _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset))
-/*
- * Return an offset, given a bit number as returned from CLZ.
- */
-#define CLASS_OFFSET_FROM_CLZ(rshift) \
-    MemberOffset((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT))
+#ifndef IMT_SIZE
+#error IMT_SIZE not defined
+#endif
 
 namespace art {
 
@@ -69,6 +40,7 @@
 template<class T> class Handle;
 class Signature;
 class StringPiece;
+template<size_t kNumReferences> class PACKED(4) StackHandleScope;
 
 namespace mirror {
 
@@ -81,10 +53,16 @@
 // C++ mirror of java.lang.Class
 class MANAGED Class FINAL : public Object {
  public:
+  // A magic value for reference_instance_offsets_. Ignore the bits and walk the super chain when
+  // this is the value.
+  // [This is an unlikely "natural" value, since it would be 30 non-ref instance fields followed by
+  // 2 ref instance fields.]
+  static constexpr uint32_t kClassWalkSuper = 0xC0000000;
+
   // Interface method table size. Increasing this value reduces the chance of two interface methods
   // colliding in the interface method table but increases the size of classes that implement
   // (non-marker) interfaces.
-  static constexpr size_t kImtSize = 64;
+  static constexpr size_t kImtSize = IMT_SIZE;
 
   // imtable entry embedded in class object.
   struct MANAGED ImTableEntry {
@@ -157,7 +135,7 @@
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   Status GetStatus() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    COMPILE_ASSERT(sizeof(Status) == sizeof(uint32_t), size_of_status_not_uint32);
+    static_assert(sizeof(Status) == sizeof(uint32_t), "Size of status not equal to uint32");
     return static_cast<Status>(
         GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, status_)));
   }
@@ -223,46 +201,46 @@
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns true if the class is an interface.
-  bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccInterface) != 0;
   }
 
   // Returns true if the class is declared public.
-  bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccPublic) != 0;
   }
 
   // Returns true if the class is declared final.
-  bool IsFinal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsFinal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccFinal) != 0;
   }
 
-  bool IsFinalizable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsFinalizable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccClassIsFinalizable) != 0;
   }
 
-  void SetFinalizable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE void SetFinalizable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
     SetAccessFlags(flags | kAccClassIsFinalizable);
   }
 
   // Returns true if the class is abstract.
-  bool IsAbstract() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsAbstract() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccAbstract) != 0;
   }
 
   // Returns true if the class is an annotation.
-  bool IsAnnotation() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsAnnotation() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccAnnotation) != 0;
   }
 
   // Returns true if the class is synthetic.
-  bool IsSynthetic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsSynthetic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccSynthetic) != 0;
   }
 
@@ -535,7 +513,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);
   }
 
@@ -554,6 +532,13 @@
     return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size);
   }
 
+  void SetObjectSizeWithoutChecks(uint32_t new_object_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // Not called within a transaction.
+    return SetField32<false, false, kVerifyNone>(
+        OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size);
+  }
+
   // Returns true if this class is in the same packages as that class.
   bool IsInSamePackage(Class* that) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -619,7 +604,7 @@
   // downcast would be necessary. Similarly for interfaces, a class that implements (or an interface
   // that extends) another can be assigned to its parent, but not vice-versa. All Classes may assign
   // to themselves. Classes for primitive types may not assign to each other.
-  inline bool IsAssignableFrom(Class* src) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE bool IsAssignableFrom(Class* src) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(src != NULL);
     if (this == src) {
       // Can always assign to things of the same type.
@@ -636,7 +621,7 @@
     }
   }
 
-  Class* GetSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE Class* GetSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetSuperClass(Class *new_super_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Super class is assigned once, except during class linker initialization.
@@ -673,14 +658,16 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Also updates the dex_cache_strings_ variable from new_dex_cache.
   void SetDexCache(DexCache* new_dex_cache) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ObjectArray<ArtMethod>* GetDirectMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ObjectArray<ArtMethod>* GetDirectMethods()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetDirectMethods(ObjectArray<ArtMethod>* new_direct_methods)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ArtMethod* GetDirectMethod(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ArtMethod* GetDirectMethod(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetDirectMethod(uint32_t i, ArtMethod* f)  // TODO: uint16_t
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -689,13 +676,14 @@
   uint32_t NumDirectMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ObjectArray<ArtMethod>* GetVirtualMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ObjectArray<ArtMethod>* GetVirtualMethods()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetVirtualMethods(ObjectArray<ArtMethod>* new_virtual_methods)
+  ALWAYS_INLINE void SetVirtualMethods(ObjectArray<ArtMethod>* new_virtual_methods)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns the number of non-inherited virtual methods.
-  uint32_t NumVirtualMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE uint32_t NumVirtualMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtMethod* GetVirtualMethod(uint32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -705,9 +693,10 @@
   void SetVirtualMethod(uint32_t i, ArtMethod* f)  // TODO: uint16_t
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ObjectArray<ArtMethod>* GetVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ObjectArray<ArtMethod>* GetVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ObjectArray<ArtMethod>* GetVTableDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE ObjectArray<ArtMethod>* GetVTableDuringLinking()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetVTable(ObjectArray<ArtMethod>* new_vtable)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -716,13 +705,6 @@
     return OFFSET_OF_OBJECT_MEMBER(Class, vtable_);
   }
 
-  void SetImTable(ObjectArray<ArtMethod>* new_imtable)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  static MemberOffset ImTableOffset() {
-    return OFFSET_OF_OBJECT_MEMBER(Class, imtable_);
-  }
-
   static MemberOffset EmbeddedImTableOffset() {
     return MemberOffset(sizeof(Class));
   }
@@ -732,7 +714,7 @@
   }
 
   static MemberOffset EmbeddedVTableOffset() {
-    return MemberOffset(sizeof(Class) + kImtSize * sizeof(mirror::Class::ImTableEntry) + sizeof(int32_t));
+    return MemberOffset(sizeof(Class) + kImtSize * sizeof(ImTableEntry) + sizeof(int32_t));
   }
 
   bool ShouldHaveEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -757,7 +739,8 @@
 
   void SetEmbeddedVTableEntry(uint32_t i, ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void PopulateEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void PopulateEmbeddedImtAndVTable(StackHandleScope<kImtSize>* imt_handle_scope)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Given a method implemented by this class but potentially from a super class, return the
   // specific implementation method for this class.
@@ -825,11 +808,11 @@
 
   ArtMethod* FindClassInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  int32_t GetIfTableCount() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE int32_t GetIfTableCount() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  IfTable* GetIfTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE IfTable* GetIfTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetIfTable(IfTable* new_iftable) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE void SetIfTable(IfTable* new_iftable) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get instance fields of the class (See also GetSFields).
   ObjectArray<ArtField>* GetIFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -866,6 +849,9 @@
   void SetReferenceInstanceOffsets(uint32_t new_reference_offsets)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Get the offset of the first reference instance field. Other reference instance fields follow.
+  MemberOffset GetFirstReferenceInstanceFieldOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Returns the number of static fields containing reference types.
   uint32_t NumReferenceStaticFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(IsResolved() || IsErroneous());
@@ -882,6 +868,13 @@
     SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num);
   }
 
+  // Get the offset of the first reference static field. Other reference static fields follow.
+  MemberOffset GetFirstReferenceStaticFieldOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Get the offset of the first reference static field. Other reference static fields follow.
+  MemberOffset GetFirstReferenceStaticFieldOffsetDuringLinking()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Gets the static fields of the class.
   ObjectArray<ArtField>* GetSFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -997,7 +990,7 @@
 
   const DexFile::ClassDef* GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -1017,7 +1010,7 @@
   void AssertInitializedOrInitializingInThread(Thread* self)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  Class* CopyOf(Thread* self, int32_t new_length)
+  Class* CopyOf(Thread* self, int32_t new_length, StackHandleScope<kImtSize>* imt_handle_scope)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // For proxy class only.
@@ -1032,6 +1025,13 @@
   bool GetSlowPathEnabled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SetSlowPath(bool enabled) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static MemberOffset DexCacheStringsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_strings_);
+  }
+
   // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
   // fence.
   class InitializeClassVisitor {
@@ -1048,6 +1048,11 @@
     DISALLOW_COPY_AND_ASSIGN(InitializeClassVisitor);
   };
 
+  // Returns true if the class loader is null, ie the class loader is the boot strap class loader.
+  bool IsBootStrapClassLoaded() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetClassLoader() == nullptr;
+  }
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -1066,8 +1071,6 @@
 
   void CheckObjectAlloc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ObjectArray<ArtMethod>* GetImTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // defining class loader, or NULL for the "bootstrap" system loader
   HeapReference<ClassLoader> class_loader_;
 
@@ -1079,6 +1082,9 @@
   // runtime such as arrays and primitive classes).
   HeapReference<DexCache> dex_cache_;
 
+  // Short cuts to dex_cache_ member for fast compiled code access.
+  HeapReference<ObjectArray<String>> dex_cache_strings_;
+
   // static, private, and <init> methods
   HeapReference<ObjectArray<ArtMethod>> direct_methods_;
 
@@ -1107,9 +1113,6 @@
   // methods for the methods in the interface.
   HeapReference<IfTable> iftable_;
 
-  // Interface method table (imt), for quick "invoke-interface".
-  HeapReference<ObjectArray<ArtMethod>> imtable_;
-
   // Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
   HeapReference<String> name_;
 
@@ -1178,11 +1181,11 @@
 
   // The following data exist in real class objects.
   // Embedded Imtable, for class object that's not an interface, fixed size.
-  ImTableEntry embedded_imtable_[0];
+  // ImTableEntry embedded_imtable_[0];
   // Embedded Vtable, for class object that's not an interface, variable size.
-  VTableEntry embedded_vtable_[0];
+  // VTableEntry embedded_vtable_[0];
   // Static fields, variable size.
-  uint32_t fields_[0];
+  // uint32_t fields_[0];
 
   // java.lang.Class
   static GcRoot<Class> java_lang_Class_;
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index ff2ad89..b10a296 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_MIRROR_CLASS_LOADER_H_
 #define ART_RUNTIME_MIRROR_CLASS_LOADER_H_
 
-#include "mirror/object.h"
+#include "object.h"
 
 namespace art {
 
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index ef6fc67..53e5534 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -34,6 +34,7 @@
 TEST_F(DexCacheTest, Open) {
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
+  ASSERT_TRUE(java_lang_dex_file_ != NULL);
   Handle<DexCache> dex_cache(
       hs.NewHandle(class_linker_->AllocDexCache(soa.Self(), *java_lang_dex_file_)));
   ASSERT_TRUE(dex_cache.Get() != NULL);
diff --git a/runtime/mirror/iftable-inl.h b/runtime/mirror/iftable-inl.h
index 3f20bf4..d1309d2 100644
--- a/runtime/mirror/iftable-inl.h
+++ b/runtime/mirror/iftable-inl.h
@@ -27,7 +27,7 @@
   DCHECK(interface->IsInterface());
   const size_t idx = i * kMax + kInterface;
   DCHECK_EQ(Get(idx), static_cast<Object*>(nullptr));
-  Set<false>(idx, interface);
+  SetWithoutChecks<false>(idx, interface);
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h
index 5feb602..4d899d2 100644
--- a/runtime/mirror/iftable.h
+++ b/runtime/mirror/iftable.h
@@ -25,13 +25,14 @@
 
 class MANAGED IfTable FINAL : public ObjectArray<Object> {
  public:
-  Class* GetInterface(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Class* interface = Get((i * kMax) + kInterface)->AsClass();
+  ALWAYS_INLINE Class* GetInterface(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Class* interface = GetWithoutChecks((i * kMax) + kInterface)->AsClass();
     DCHECK(interface != NULL);
     return interface;
   }
 
-  void SetInterface(int32_t i, Class* interface) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE void SetInterface(int32_t i, Class* interface)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ObjectArray<ArtMethod>* GetMethodArray(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ObjectArray<ArtMethod>* method_array =
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 166ea9c..121947d 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -121,7 +121,7 @@
       OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_));
 #else
   LOG(FATAL) << "Unreachable";
-  return nullptr;
+  UNREACHABLE();
 #endif
 }
 
@@ -134,6 +134,8 @@
       OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr);
 #else
   LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
+  UNUSED(rb_ptr);
 #endif
 }
 
@@ -141,7 +143,7 @@
 #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
   DCHECK(kUseBakerOrBrooksReadBarrier);
   MemberOffset offset = OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_);
-  byte* raw_addr = reinterpret_cast<byte*>(this) + offset.SizeValue();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + offset.SizeValue();
   Atomic<uint32_t>* atomic_rb_ptr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
   HeapReference<Object> expected_ref(HeapReference<Object>::FromMirrorPtr(expected_rb_ptr));
   HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(rb_ptr));
@@ -155,8 +157,9 @@
   DCHECK_EQ(new_ref.reference_, atomic_rb_ptr->LoadRelaxed());
   return true;
 #else
+  UNUSED(expected_rb_ptr, rb_ptr);
   LOG(FATAL) << "Unreachable";
-  return false;
+  UNREACHABLE();
 #endif
 }
 
@@ -166,13 +169,12 @@
     DCHECK(obj->GetReadBarrierPointer() == nullptr)
         << "Bad Baker pointer: obj=" << reinterpret_cast<void*>(obj)
         << " ptr=" << reinterpret_cast<void*>(obj->GetReadBarrierPointer());
-  } else if (kUseBrooksReadBarrier) {
+  } else {
+    CHECK(kUseBrooksReadBarrier);
     Object* obj = const_cast<Object*>(this);
     DCHECK_EQ(obj, obj->GetReadBarrierPointer())
         << "Bad Brooks pointer: obj=" << reinterpret_cast<void*>(obj)
         << " ptr=" << reinterpret_cast<void*>(obj->GetReadBarrierPointer());
-  } else {
-    LOG(FATAL) << "Unreachable";
   }
 }
 
@@ -402,8 +404,7 @@
   }
   DCHECK_GE(result, sizeof(Object))
       << " class=" << PrettyTypeOf(GetClass<kNewFlags, kReadBarrierOption>());
-  DCHECK(!(IsArtField<kNewFlags, kReadBarrierOption>())  || result == sizeof(ArtField));
-  DCHECK(!(IsArtMethod<kNewFlags, kReadBarrierOption>()) || result == sizeof(ArtMethod));
+  DCHECK(!(IsArtField<kNewFlags, kReadBarrierOption>()) || result == sizeof(ArtField));
   return result;
 }
 
@@ -602,7 +603,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
 
   return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
@@ -620,7 +621,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
 
   return atomic_addr->CompareExchangeWeakRelaxed(old_value, new_value);
@@ -638,7 +639,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
 
   return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
@@ -682,7 +683,7 @@
 
 template<typename kSize, bool kIsVolatile>
 inline void Object::SetField(MemberOffset field_offset, kSize new_value) {
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   kSize* addr = reinterpret_cast<kSize*>(raw_addr);
   if (kIsVolatile) {
     reinterpret_cast<Atomic<kSize>*>(addr)->StoreSequentiallyConsistent(new_value);
@@ -693,7 +694,7 @@
 
 template<typename kSize, bool kIsVolatile>
 inline kSize Object::GetField(MemberOffset field_offset) {
-  const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value();
+  const uint8_t* raw_addr = reinterpret_cast<const uint8_t*>(this) + field_offset.Int32Value();
   const kSize* addr = reinterpret_cast<const kSize*>(raw_addr);
   if (kIsVolatile) {
     return reinterpret_cast<const Atomic<kSize>*>(addr)->LoadSequentiallyConsistent();
@@ -714,7 +715,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
   return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
 }
@@ -731,7 +732,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
   return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
 }
@@ -742,7 +743,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   HeapReference<T>* objref_addr = reinterpret_cast<HeapReference<T>*>(raw_addr);
   T* result = ReadBarrier::Barrier<T, kReadBarrierOption>(this, field_offset, objref_addr);
   if (kIsVolatile) {
@@ -782,7 +783,7 @@
   if (kVerifyFlags & kVerifyWrites) {
     VerifyObject(new_value);
   }
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   HeapReference<Object>* objref_addr = reinterpret_cast<HeapReference<Object>*>(raw_addr);
   if (kIsVolatile) {
     // TODO: Refactor to use a SequentiallyConsistent store instead.
@@ -818,7 +819,7 @@
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
-  return reinterpret_cast<HeapReference<Object>*>(reinterpret_cast<byte*>(this) +
+  return reinterpret_cast<HeapReference<Object>*>(reinterpret_cast<uint8_t*>(this) +
       field_offset.Int32Value());
 }
 
@@ -842,7 +843,7 @@
   }
   HeapReference<Object> old_ref(HeapReference<Object>::FromMirrorPtr(old_value));
   HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(new_value));
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
 
   bool success = atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_ref.reference_,
@@ -874,7 +875,7 @@
   }
   HeapReference<Object> old_ref(HeapReference<Object>::FromMirrorPtr(old_value));
   HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(new_value));
-  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
   Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
 
   bool success = atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_ref.reference_,
@@ -888,18 +889,18 @@
 
 template<bool kVisitClass, bool kIsStatic, typename Visitor>
 inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor) {
-  if (!kIsStatic && LIKELY(ref_offsets != CLASS_WALK_SUPER)) {
-    if (!kVisitClass) {
-      // Mask out the class from the reference offsets.
-      ref_offsets ^= kWordHighBitMask;
+  if (!kIsStatic && (ref_offsets != mirror::Class::kClassWalkSuper)) {
+    // Instance fields and not the slow-path.
+    if (kVisitClass) {
+      visitor(this, ClassOffset(), kIsStatic);
     }
-    DCHECK_EQ(ClassOffset().Uint32Value(), 0U);
-    // Found a reference offset bitmap. Visit the specified offsets.
+    uint32_t field_offset = mirror::kObjectHeaderSize;
     while (ref_offsets != 0) {
-      size_t right_shift = CLZ(ref_offsets);
-      MemberOffset field_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
-      visitor(this, field_offset, kIsStatic);
-      ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
+      if ((ref_offsets & 1) != 0) {
+        visitor(this, MemberOffset(field_offset), kIsStatic);
+      }
+      ref_offsets >>= 1;
+      field_offset += sizeof(mirror::HeapReference<mirror::Object>);
     }
   } else {
     // There is no reference offset bitmap. In the non-static case, walk up the class
@@ -909,13 +910,19 @@
         klass = kIsStatic ? nullptr : klass->GetSuperClass()) {
       size_t num_reference_fields =
           kIsStatic ? klass->NumReferenceStaticFields() : klass->NumReferenceInstanceFields();
+      if (num_reference_fields == 0u) {
+        continue;
+      }
+      MemberOffset field_offset = kIsStatic
+          ? klass->GetFirstReferenceStaticFieldOffset()
+          : klass->GetFirstReferenceInstanceFieldOffset();
       for (size_t i = 0; i < num_reference_fields; ++i) {
-        mirror::ArtField* field = kIsStatic ? klass->GetStaticField(i) : klass->GetInstanceField(i);
-        MemberOffset field_offset = field->GetOffset();
         // TODO: Do a simpler check?
         if (kVisitClass || field_offset.Uint32Value() != ClassOffset().Uint32Value()) {
           visitor(this, field_offset, kIsStatic);
         }
+        field_offset = MemberOffset(field_offset.Uint32Value() +
+                                    sizeof(mirror::HeapReference<mirror::Object>));
       }
     }
   }
@@ -954,7 +961,6 @@
     }
   }
 }
-
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 57069ab..6914f38 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -24,7 +24,7 @@
 #include "class.h"
 #include "class-inl.h"
 #include "class_linker-inl.h"
-#include "field_helper.h"
+#include "dex_file-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
 #include "iftable-inl.h"
@@ -39,6 +39,8 @@
 namespace art {
 namespace mirror {
 
+Atomic<uint32_t> Object::hash_code_seed(987654321U + std::time(nullptr));
+
 class CopyReferenceFieldsWithReadBarrierVisitor {
  public:
   explicit CopyReferenceFieldsWithReadBarrierVisitor(Object* dest_obj)
@@ -69,8 +71,8 @@
                            size_t num_bytes) {
   // Copy instance data.  We assume memcpy copies by words.
   // TODO: expose and use move32.
-  byte* src_bytes = reinterpret_cast<byte*>(src);
-  byte* dst_bytes = reinterpret_cast<byte*>(dest);
+  uint8_t* src_bytes = reinterpret_cast<uint8_t*>(src);
+  uint8_t* dst_bytes = reinterpret_cast<uint8_t*>(dest);
   size_t offset = sizeof(Object);
   memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset);
   if (kUseBakerOrBrooksReadBarrier) {
@@ -135,17 +137,20 @@
   return copy;
 }
 
-int32_t Object::GenerateIdentityHashCode() {
-  static AtomicInteger seed(987654321 + std::time(nullptr));
-  int32_t expected_value, new_value;
+uint32_t Object::GenerateIdentityHashCode() {
+  uint32_t expected_value, new_value;
   do {
-    expected_value = static_cast<uint32_t>(seed.LoadRelaxed());
+    expected_value = hash_code_seed.LoadRelaxed();
     new_value = expected_value * 1103515245 + 12345;
-  } while ((expected_value & LockWord::kHashMask) == 0 ||
-      !seed.CompareExchangeWeakRelaxed(expected_value, new_value));
+  } while (!hash_code_seed.CompareExchangeWeakRelaxed(expected_value, new_value) ||
+      (expected_value & LockWord::kHashMask) == 0);
   return expected_value & LockWord::kHashMask;
 }
 
+void Object::SetHashCodeSeed(uint32_t new_seed) {
+  hash_code_seed.StoreRelaxed(new_seed);
+}
+
 int32_t Object::IdentityHashCode() const {
   mirror::Object* current_this = const_cast<mirror::Object*>(this);
   while (true) {
@@ -200,13 +205,18 @@
   for (Class* cur = c; cur != NULL; cur = cur->GetSuperClass()) {
     ObjectArray<ArtField>* fields = cur->GetIFields();
     if (fields != NULL) {
-      size_t num_ref_ifields = cur->NumReferenceInstanceFields();
-      for (size_t i = 0; i < num_ref_ifields; ++i) {
+      size_t num_ifields = fields->GetLength();
+      for (size_t i = 0; i < num_ifields; ++i) {
+        StackHandleScope<1> hs(Thread::Current());
+        Handle<Object> h_object(hs.NewHandle(new_value));
         ArtField* field = fields->Get(i);
         if (field->GetOffset().Int32Value() == field_offset.Int32Value()) {
-          StackHandleScope<1> hs(Thread::Current());
-          FieldHelper fh(hs.NewHandle(field));
-          CHECK(fh.GetType()->IsAssignableFrom(new_value->GetClass()));
+          CHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot);
+          // TODO: resolve the field type for moving GC.
+          mirror::Class* field_type = field->GetType(!kMovingCollector);
+          if (field_type != nullptr) {
+            CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
+          }
           return;
         }
       }
@@ -219,13 +229,16 @@
   if (IsClass()) {
     ObjectArray<ArtField>* fields = AsClass()->GetSFields();
     if (fields != NULL) {
-      size_t num_ref_sfields = AsClass()->NumReferenceStaticFields();
-      for (size_t i = 0; i < num_ref_sfields; ++i) {
+      size_t num_sfields = fields->GetLength();
+      for (size_t i = 0; i < num_sfields; ++i) {
         ArtField* field = fields->Get(i);
         if (field->GetOffset().Int32Value() == field_offset.Int32Value()) {
-          StackHandleScope<1> hs(Thread::Current());
-          FieldHelper fh(hs.NewHandle(field));
-          CHECK(fh.GetType()->IsAssignableFrom(new_value->GetClass()));
+          CHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot);
+          // TODO: resolve the field type for moving GC.
+          mirror::Class* field_type = field->GetType(!kMovingCollector);
+          if (field_type != nullptr) {
+            CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
+          }
           return;
         }
       }
@@ -233,6 +246,7 @@
   }
   LOG(FATAL) << "Failed to find field for assignment to " << reinterpret_cast<void*>(this)
       << " of type " << PrettyDescriptor(c) << " at offset " << field_offset;
+  UNREACHABLE();
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 6cd230b..07d15b5 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -17,9 +17,9 @@
 #ifndef ART_RUNTIME_MIRROR_OBJECT_H_
 #define ART_RUNTIME_MIRROR_OBJECT_H_
 
+#include "globals.h"
 #include "object_reference.h"
 #include "offsets.h"
-#include "runtime.h"
 #include "verify_object.h"
 
 namespace art {
@@ -61,6 +61,9 @@
 // Checks that we don't do field assignments which violate the typing system.
 static constexpr bool kCheckFieldAssignments = false;
 
+// Size of Object.
+static constexpr uint32_t kObjectHeaderSize = kUseBakerOrBrooksReadBarrier ? 16 : 8;
+
 // C++ mirror of java.lang.Object
 class MANAGED LOCKABLE Object {
  public:
@@ -389,15 +392,26 @@
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T>
   void SetFieldPtr(MemberOffset field_offset, T new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#ifndef __LP64__
-    SetField32<kTransactionActive, kCheckTransaction, kVerifyFlags>(
-        field_offset, reinterpret_cast<int32_t>(new_value));
-#else
-    SetField64<kTransactionActive, kCheckTransaction, kVerifyFlags>(
-        field_offset, reinterpret_cast<int64_t>(new_value));
-#endif
+    SetFieldPtrWithSize<kTransactionActive, kCheckTransaction, kVerifyFlags>(
+        field_offset, new_value, sizeof(void*));
   }
 
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T>
+  ALWAYS_INLINE void SetFieldPtrWithSize(MemberOffset field_offset, T new_value,
+                                         size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(pointer_size == 4 || pointer_size == 8) << pointer_size;
+    if (pointer_size == 4) {
+      intptr_t ptr  = reinterpret_cast<intptr_t>(new_value);
+      DCHECK_EQ(static_cast<int32_t>(ptr), ptr);  // Check that we dont lose any non 0 bits.
+      SetField32<kTransactionActive, kCheckTransaction, kVerifyFlags>(
+          field_offset, static_cast<int32_t>(ptr));
+    } else {
+      SetField64<kTransactionActive, kCheckTransaction, kVerifyFlags>(
+          field_offset, static_cast<int64_t>(reinterpret_cast<intptr_t>(new_value)));
+    }
+  }
   // TODO fix thread safety analysis broken by the use of template. This should be
   // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
   template <const bool kVisitClass, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
@@ -405,16 +419,31 @@
   void VisitReferences(const Visitor& visitor, const JavaLangRefVisitor& ref_visitor)
       NO_THREAD_SAFETY_ANALYSIS;
 
+  // Used by object_test.
+  static void SetHashCodeSeed(uint32_t new_seed);
+  // Generate an identity hash code. Public for object test.
+  static uint32_t GenerateIdentityHashCode();
+
  protected:
   // Accessors for non-Java type fields
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
   T GetFieldPtr(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#ifndef __LP64__
-    return reinterpret_cast<T>(GetField32<kVerifyFlags, kIsVolatile>(field_offset));
-#else
-    return reinterpret_cast<T>(GetField64<kVerifyFlags, kIsVolatile>(field_offset));
-#endif
+    return GetFieldPtrWithSize<T, kVerifyFlags, kIsVolatile>(field_offset, sizeof(void*));
+  }
+
+  template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
+  ALWAYS_INLINE T GetFieldPtrWithSize(MemberOffset field_offset, size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(pointer_size == 4 || pointer_size == 8) << pointer_size;
+    if (pointer_size == 4) {
+      return reinterpret_cast<T>(GetField32<kVerifyFlags, kIsVolatile>(field_offset));
+    } else {
+      int64_t v = GetField64<kVerifyFlags, kIsVolatile>(field_offset);
+      // Check that we dont lose any non 0 bits.
+      DCHECK_EQ(reinterpret_cast<int64_t>(reinterpret_cast<T>(v)), v);
+      return reinterpret_cast<T>(v);
+    }
   }
 
   // TODO: Fixme when anotatalysis works with visitors.
@@ -447,9 +476,6 @@
     }
   }
 
-  // Generate an identity hash code.
-  static int32_t GenerateIdentityHashCode();
-
   // A utility function that copies an object in a read barrier and
   // write barrier-aware way. This is internally used by Clone() and
   // Class::CopyOf().
@@ -457,6 +483,8 @@
                             size_t num_bytes)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  static Atomic<uint32_t> hash_code_seed;
+
   // The Class representing the type of the object.
   HeapReference<Class> klass_;
   // Monitor and hash code information.
@@ -475,6 +503,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_array-inl.h b/runtime/mirror/object_array-inl.h
index 0ca44f8..fbc4f4a 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -19,6 +19,7 @@
 
 #include "object_array.h"
 
+#include "array-inl.h"
 #include "base/stringprintf.h"
 #include "gc/heap.h"
 #include "mirror/art_field.h"
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 7012b19..6404faf 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -45,11 +45,11 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool CheckAssignable(T* object) NO_THREAD_SAFETY_ANALYSIS;
 
-  void Set(int32_t i, T* object) ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE void Set(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // TODO fix thread safety analysis: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void Set(int32_t i, T* object) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS;
+  ALWAYS_INLINE void Set(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
 
   // Set element without bound and element type checks, to be used in limited
   // circumstances, such as during boot image writing.
@@ -57,15 +57,15 @@
   // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetWithoutChecks(int32_t i, T* object) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS;
+  ALWAYS_INLINE void SetWithoutChecks(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
   // TODO fix thread safety analysis broken by the use of template. This should be
   // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetWithoutChecksAndWriteBarrier(int32_t i, T* object) ALWAYS_INLINE
+  ALWAYS_INLINE void SetWithoutChecksAndWriteBarrier(int32_t i, T* object)
       NO_THREAD_SAFETY_ANALYSIS;
 
-  T* GetWithoutChecks(int32_t i) ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE T* GetWithoutChecks(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Copy src into this array (dealing with overlaps as memmove does) without assignability checks.
   void AssignableMemmove(int32_t dst_pos, ObjectArray<T>* src, int32_t src_pos,
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 7fa664d..fb42d28 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -34,7 +34,6 @@
 #include "gc/heap.h"
 #include "handle_scope-inl.h"
 #include "iftable-inl.h"
-#include "method_helper-inl.h"
 #include "object-inl.h"
 #include "object_array-inl.h"
 #include "scoped_thread_state_change.h"
@@ -76,27 +75,12 @@
 
 // Keep constants in sync.
 TEST_F(ObjectTest, Constants) {
-  EXPECT_EQ(kObjectReferenceSize, sizeof(mirror::HeapReference<mirror::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());
+  EXPECT_EQ(kObjectReferenceSize, sizeof(HeapReference<Object>));
+  EXPECT_EQ(kObjectHeaderSize, sizeof(Object));
+  EXPECT_EQ(MIRROR_ART_METHOD_QUICK_CODE_OFFSET_32,
+            ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value());
+  EXPECT_EQ(MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64,
+            ArtMethod::EntryPointFromQuickCompiledCodeOffset(8).Int32Value());
 }
 
 TEST_F(ObjectTest, IsInSamePackage) {
@@ -247,12 +231,6 @@
 TEST_F(ObjectTest, PrimitiveArray_Char_Alloc) {
   TestPrimitiveArray<CharArray>(class_linker_);
 }
-TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) {
-  TestPrimitiveArray<DoubleArray>(class_linker_);
-}
-TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) {
-  TestPrimitiveArray<FloatArray>(class_linker_);
-}
 TEST_F(ObjectTest, PrimitiveArray_Int_Alloc) {
   TestPrimitiveArray<IntArray>(class_linker_);
 }
@@ -263,6 +241,67 @@
   TestPrimitiveArray<ShortArray>(class_linker_);
 }
 
+TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) {
+  typedef DoubleArray ArrayT;
+  ScopedObjectAccess soa(Thread::Current());
+  typedef typename ArrayT::ElementType T;
+
+  ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+  EXPECT_EQ(2, a->GetLength());
+  EXPECT_DOUBLE_EQ(0, a->Get(0));
+  EXPECT_DOUBLE_EQ(0, a->Get(1));
+  a->Set(0, T(123));
+  EXPECT_DOUBLE_EQ(T(123), a->Get(0));
+  EXPECT_DOUBLE_EQ(0, a->Get(1));
+  a->Set(1, T(321));
+  EXPECT_DOUBLE_EQ(T(123), a->Get(0));
+  EXPECT_DOUBLE_EQ(T(321), a->Get(1));
+
+  Class* aioobe = class_linker_->FindSystemClass(soa.Self(),
+                                                 "Ljava/lang/ArrayIndexOutOfBoundsException;");
+
+  EXPECT_DOUBLE_EQ(0, a->Get(-1));
+  EXPECT_TRUE(soa.Self()->IsExceptionPending());
+  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  soa.Self()->ClearException();
+
+  EXPECT_DOUBLE_EQ(0, a->Get(2));
+  EXPECT_TRUE(soa.Self()->IsExceptionPending());
+  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  soa.Self()->ClearException();
+}
+
+TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) {
+  typedef FloatArray ArrayT;
+  ScopedObjectAccess soa(Thread::Current());
+  typedef typename ArrayT::ElementType T;
+
+  ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+  EXPECT_FLOAT_EQ(2, a->GetLength());
+  EXPECT_FLOAT_EQ(0, a->Get(0));
+  EXPECT_FLOAT_EQ(0, a->Get(1));
+  a->Set(0, T(123));
+  EXPECT_FLOAT_EQ(T(123), a->Get(0));
+  EXPECT_FLOAT_EQ(0, a->Get(1));
+  a->Set(1, T(321));
+  EXPECT_FLOAT_EQ(T(123), a->Get(0));
+  EXPECT_FLOAT_EQ(T(321), a->Get(1));
+
+  Class* aioobe = class_linker_->FindSystemClass(soa.Self(),
+                                                 "Ljava/lang/ArrayIndexOutOfBoundsException;");
+
+  EXPECT_FLOAT_EQ(0, a->Get(-1));
+  EXPECT_TRUE(soa.Self()->IsExceptionPending());
+  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  soa.Self()->ClearException();
+
+  EXPECT_FLOAT_EQ(0, a->Get(2));
+  EXPECT_TRUE(soa.Self()->IsExceptionPending());
+  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  soa.Self()->ClearException();
+}
+
+
 TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
   // pretend we are trying to call 'new char[3]' from String.toCharArray
   ScopedObjectAccess soa(Thread::Current());
@@ -274,7 +313,7 @@
       java_lang_dex_file_->GetIndexForStringId(*string_id));
   ASSERT_TRUE(type_id != NULL);
   uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
-  Object* array = CheckAndAllocArrayFromCodeInstrumented(type_idx, sort, 3, Thread::Current(), false,
+  Object* array = CheckAndAllocArrayFromCodeInstrumented(type_idx, 3, sort, Thread::Current(), false,
                                                          Runtime::Current()->GetHeap()->GetCurrentAllocator());
   EXPECT_TRUE(array->IsArrayInstance());
   EXPECT_EQ(3, array->AsArray()->GetLength());
@@ -484,26 +523,6 @@
   EXPECT_STREQ(m3_2->GetName(), "m3");
   ArtMethod* m4_2 = klass2->GetVirtualMethod(3);
   EXPECT_STREQ(m4_2->GetName(), "m4");
-
-  MutableMethodHelper mh(hs.NewHandle(m1_1));
-  MutableMethodHelper mh2(hs.NewHandle(m1_2));
-  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
-  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
-
-  mh.ChangeMethod(m2_1);
-  mh2.ChangeMethod(m2_2);
-  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
-  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
-
-  mh.ChangeMethod(m3_1);
-  mh2.ChangeMethod(m3_2);
-  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
-  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
-
-  mh.ChangeMethod(m4_1);
-  mh2.ChangeMethod(m4_2);
-  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
-  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 }
 
 TEST_F(ObjectTest, StringHashCode) {
@@ -712,5 +731,14 @@
   // TODO: test that interfaces trump superclasses.
 }
 
+TEST_F(ObjectTest, IdentityHashCode) {
+  // Regression test for b/19046417 which had an infinite loop if the
+  // (seed & LockWord::kHashMask) == 0. seed 0 triggered the infinite loop since we did the check
+  // before the CAS which resulted in the same seed the next loop iteration.
+  mirror::Object::SetHashCodeSeed(0);
+  int32_t hash_code = mirror::Object::GenerateIdentityHashCode();
+  EXPECT_NE(hash_code, 0);
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/reference.cc b/runtime/mirror/reference.cc
index c36bd98..35130e8 100644
--- a/runtime/mirror/reference.cc
+++ b/runtime/mirror/reference.cc
@@ -33,9 +33,7 @@
 }
 
 void Reference::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_ref_Reference_.IsNull()) {
-    java_lang_ref_Reference_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_ref_Reference_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index 1eb20f7..c2a67e8 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -68,9 +68,7 @@
 }
 
 void StackTraceElement::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_StackTraceElement_.IsNull()) {
-    java_lang_StackTraceElement_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_StackTraceElement_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index 01599ae..e199d0e 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -224,9 +224,7 @@
 }
 
 void String::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_String_.IsNull()) {
-    java_lang_String_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_String_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 1320ab7..30b8aa3 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"
@@ -111,6 +109,14 @@
 
   int32_t CompareTo(String* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void SetOffset(int32_t new_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // Offset is only used during testing so use non-transactional mode.
+    DCHECK_LE(0, new_offset);
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset);
+  }
+
+  void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static Class* GetJavaLangString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(!java_lang_String_.IsNull());
     return java_lang_String_.Read();
@@ -136,21 +142,12 @@
     SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count);
   }
 
-  void SetOffset(int32_t new_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Offset is only used during testing so use non-transactional mode.
-    DCHECK_LE(0, new_offset);
-    DCHECK_GE(GetLength(), new_offset);
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset);
-  }
-
   static String* Alloc(Thread* self, int32_t utf16_length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static String* Alloc(Thread* self, Handle<CharArray> array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   HeapReference<CharArray> array_;
 
@@ -163,7 +160,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/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 93ed4d4..61d85e2 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -138,9 +138,7 @@
 }
 
 void Throwable::VisitRoots(RootCallback* callback, void* arg) {
-  if (!java_lang_Throwable_.IsNull()) {
-    java_lang_Throwable_.VisitRoot(callback, arg, 0, kRootStickyClass);
-  }
+  java_lang_Throwable_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
 }
 
 }  // namespace mirror
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 23c18f8..09dc78a 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -46,7 +46,6 @@
 static constexpr uint32_t kAccPreverified =          0x00080000;  // class (runtime),
                                                                   // method (dex only)
 static constexpr uint32_t kAccFastNative =           0x00080000;  // method (dex only)
-static constexpr uint32_t kAccPortableCompiled =     0x00100000;  // method (dex only)
 static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
 
 // Special runtime-only flags.
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 6123934..ef63080 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -16,6 +16,9 @@
 
 #include "monitor.h"
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
+#include <cutils/trace.h>
 #include <vector>
 
 #include "base/mutex.h"
@@ -36,6 +39,8 @@
 
 namespace art {
 
+static constexpr uint64_t kLongWaitMs = 100;
+
 /*
  * Every Object has a monitor associated with it, but not every Object is actually locked.  Even
  * the ones that are locked do not need a full-fledged monitor until a) there is actual contention
@@ -242,13 +247,19 @@
     mirror::ArtMethod* owners_method = locking_method_;
     uint32_t owners_dex_pc = locking_dex_pc_;
     // Do this before releasing the lock so that we don't get deflated.
+    size_t num_waiters = num_waiters_;
     ++num_waiters_;
     monitor_lock_.Unlock(self);  // Let go of locks in order.
     self->SetMonitorEnterObject(GetObject());
     {
       ScopedThreadStateChange tsc(self, kBlocked);  // Change to blocked and give up mutator_lock_.
       MutexLock mu2(self, monitor_lock_);  // Reacquire monitor_lock_ without mutator_lock_ for Wait.
-      if (owner_ != NULL) {  // Did the owner_ give the lock up?
+      if (owner_ != nullptr) {  // Did the owner_ give the lock up?
+        if (ATRACE_ENABLED()) {
+          std::string name;
+          owner_->GetThreadName(name);
+          ATRACE_BEGIN(("Contended on monitor with owner " + name).c_str());
+        }
         monitor_contenders_.Wait(self);  // Still contended so wait.
         // Woken from contention.
         if (log_contention) {
@@ -263,9 +274,16 @@
             const char* owners_filename;
             uint32_t owners_line_number;
             TranslateLocation(owners_method, owners_dex_pc, &owners_filename, &owners_line_number);
+            if (wait_ms > kLongWaitMs && owners_method != nullptr) {
+              LOG(WARNING) << "Long monitor contention event with owner method="
+                  << PrettyMethod(owners_method) << " from " << owners_filename << ":"
+                  << owners_line_number << " waiters=" << num_waiters << " for "
+                  << PrettyDuration(MsToNs(wait_ms));
+            }
             LogContentionEvent(self, wait_ms, sample_percent, owners_filename, owners_line_number);
           }
         }
+        ATRACE_END();
       }
     }
     self->SetMonitorEnterObject(nullptr);
@@ -543,7 +561,7 @@
     thread->SetWaitNext(nullptr);
 
     // Check to see if the thread is still waiting.
-    MutexLock mu(self, *thread->GetWaitMutex());
+    MutexLock wait_mu(self, *thread->GetWaitMutex());
     if (thread->GetWaitMonitor() != nullptr) {
       thread->GetWaitConditionVariable()->Signal(self);
       return;
@@ -646,8 +664,6 @@
     Thread* owner;
     {
       ScopedThreadStateChange tsc(self, kBlocked);
-      // Take suspend thread lock to avoid races with threads trying to suspend this one.
-      MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_);
       owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
     }
     if (owner != nullptr) {
@@ -877,7 +893,7 @@
     }
     default: {
       LOG(FATAL) << "Unreachable";
-      return ThreadList::kInvalidThreadId;
+      UNREACHABLE();
     }
   }
 }
@@ -985,25 +1001,20 @@
   // the locks held in this stack frame.
   std::vector<uint32_t> monitor_enter_dex_pcs;
   verifier::MethodVerifier::FindLocksAtDexPc(m, dex_pc, &monitor_enter_dex_pcs);
-  if (monitor_enter_dex_pcs.empty()) {
-    return;
-  }
-
-  for (size_t i = 0; i < monitor_enter_dex_pcs.size(); ++i) {
+  for (uint32_t monitor_dex_pc : monitor_enter_dex_pcs) {
     // The verifier works in terms of the dex pcs of the monitor-enter instructions.
     // We want the registers used by those instructions (so we can read the values out of them).
-    uint32_t dex_pc = monitor_enter_dex_pcs[i];
-    uint16_t monitor_enter_instruction = code_item->insns_[dex_pc];
+    uint16_t monitor_enter_instruction = code_item->insns_[monitor_dex_pc];
 
     // Quick sanity check.
     if ((monitor_enter_instruction & 0xff) != Instruction::MONITOR_ENTER) {
-      LOG(FATAL) << "expected monitor-enter @" << dex_pc << "; was "
+      LOG(FATAL) << "expected monitor-enter @" << monitor_dex_pc << "; was "
                  << reinterpret_cast<void*>(monitor_enter_instruction);
     }
 
     uint16_t monitor_register = ((monitor_enter_instruction >> 8) & 0xff);
-    mirror::Object* o = reinterpret_cast<mirror::Object*>(stack_visitor->GetVReg(m, monitor_register,
-                                                                                 kReferenceVReg));
+    mirror::Object* o = reinterpret_cast<mirror::Object*>(
+        stack_visitor->GetVReg(m, monitor_register, kReferenceVReg));
     callback(o, callback_context);
   }
 }
@@ -1032,7 +1043,7 @@
       return true;
     default:
       LOG(FATAL) << "Unreachable";
-      return false;
+      UNREACHABLE();
   }
 }
 
diff --git a/runtime/monitor_pool.h b/runtime/monitor_pool.h
index cb45162..27678dc 100644
--- a/runtime/monitor_pool.h
+++ b/runtime/monitor_pool.h
@@ -53,6 +53,7 @@
 
   static void ReleaseMonitor(Thread* self, Monitor* monitor) {
 #ifndef __LP64__
+    UNUSED(self);
     delete monitor;
 #else
     GetMonitorPool()->ReleaseMonitorToPool(self, monitor);
@@ -61,6 +62,7 @@
 
   static void ReleaseMonitors(Thread* self, MonitorList::Monitors* monitors) {
 #ifndef __LP64__
+    UNUSED(self);
     STLDeleteElements(monitors);
 #else
     GetMonitorPool()->ReleaseMonitorsToPool(self, monitors);
@@ -85,6 +87,7 @@
 
   static MonitorId ComputeMonitorId(Monitor* mon, Thread* self) {
 #ifndef __LP64__
+    UNUSED(self);
     return MonitorIdFromMonitor(mon);
 #else
     return GetMonitorPool()->ComputeMonitorIdInPool(mon, self);
@@ -172,7 +175,7 @@
   // To avoid race issues when resizing, we keep all the previous arrays.
   std::vector<uintptr_t*> old_chunk_arrays_ GUARDED_BY(Locks::allocated_monitor_ids_lock_);
 
-  typedef TrackingAllocator<byte, kAllocatorTagMonitorPool> Allocator;
+  typedef TrackingAllocator<uint8_t, kAllocatorTagMonitorPool> Allocator;
   Allocator allocator_;
 
   // Start of free list of monitors.
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index 704e041..6d1e721 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -341,8 +341,7 @@
 
   // Wake the watchdog.
   {
-    Thread* self = Thread::Current();
-    ScopedObjectAccess soa(self);
+    ScopedObjectAccess soa(Thread::Current());
 
     test->watchdog_object_.Get()->MonitorEnter(self);     // Lock the object.
     test->watchdog_object_.Get()->NotifyAll(self);        // Wake up waiting parties.
@@ -357,6 +356,8 @@
 TEST_F(MonitorTest, CheckExceptionsWait1) {
   // Make the CreateTask wait 10ms, the UseTask wait 10ms.
   // => The use task will get the lock first and get to self == owner check.
+  // This will lead to OOM and monitor error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
   CommonWaitSetup(this, class_linker_, 10, 50, false, false, 2, 50, true,
                   "Monitor test thread pool 1");
 }
@@ -365,6 +366,8 @@
 TEST_F(MonitorTest, CheckExceptionsWait2) {
   // Make the CreateTask wait 0ms, the UseTask wait 10ms.
   // => The create task will get the lock first and get to ms >= 0
+  // This will lead to OOM and monitor error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
   CommonWaitSetup(this, class_linker_, 0, -1, true, false, 10, 50, true,
                   "Monitor test thread pool 2");
 }
@@ -374,6 +377,8 @@
   // Make the CreateTask wait 0ms, then Wait for a long time. Make the InterruptTask wait 10ms,
   // after which it will interrupt the create task and then wait another 10ms.
   // => The create task will get to the interrupted-exception throw.
+  // This will lead to OOM and monitor error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
   CommonWaitSetup(this, class_linker_, 0, 500, true, true, 10, 50, true,
                   "Monitor test thread pool 3");
 }
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 65a7919..037072d 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "dalvik_system_DexFile.h"
+
 #include <algorithm>
 #include <set>
 #include <fcntl.h>
@@ -43,13 +45,17 @@
 #include "profiler.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
-#include "ScopedFd.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "utils.h"
 #include "well_known_classes.h"
 #include "zip_archive.h"
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "ScopedFd.h"
+#pragma GCC diagnostic pop
+
 namespace art {
 
 // A smart pointer that provides read-only access to a Java string's UTF chars.
@@ -109,7 +115,8 @@
   }
 
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
+  std::unique_ptr<std::vector<std::unique_ptr<const DexFile>>> dex_files(
+      new std::vector<std::unique_ptr<const DexFile>>());
   std::vector<std::string> error_msgs;
 
   bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,
@@ -137,9 +144,11 @@
   }
 }
 
-static std::vector<const DexFile*>* toDexFiles(jlong dex_file_address, JNIEnv* env) {
-  std::vector<const DexFile*>* dex_files = reinterpret_cast<std::vector<const DexFile*>*>(
-      static_cast<uintptr_t>(dex_file_address));
+static std::vector<std::unique_ptr<const DexFile>>*
+toDexFiles(jlong dex_file_address, JNIEnv* env) {
+  std::vector<std::unique_ptr<const DexFile>>* dex_files
+    = reinterpret_cast<std::vector<std::unique_ptr<const DexFile>>*>(
+        static_cast<uintptr_t>(dex_file_address));
   if (UNLIKELY(dex_files == nullptr)) {
     ScopedObjectAccess soa(env);
     ThrowNullPointerException(NULL, "dex_file == null");
@@ -148,27 +157,29 @@
 }
 
 static void DexFile_closeDexFile(JNIEnv* env, jclass, jlong cookie) {
-  std::unique_ptr<std::vector<const DexFile*>> dex_files(toDexFiles(cookie, env));
+  std::unique_ptr<std::vector<std::unique_ptr<const DexFile>>> dex_files(toDexFiles(cookie, env));
   if (dex_files.get() == nullptr) {
     return;
   }
   ScopedObjectAccess soa(env);
 
-  size_t index = 0;
-  for (const DexFile* dex_file : *dex_files) {
+  // The Runtime currently never unloads classes, which means any registered
+  // dex files must be kept around forever in case they are used. We
+  // accomplish this here by explicitly leaking those dex files that are
+  // registered.
+  //
+  // TODO: The Runtime should support unloading of classes and freeing of the
+  // dex files for those unloaded classes rather than leaking dex files here.
+  for (auto& dex_file : *dex_files) {
     if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
-      (*dex_files)[index] = nullptr;
+      dex_file.release();
     }
-    index++;
   }
-
-  STLDeleteElements(dex_files.get());
-  // Unique_ptr will delete the vector itself.
 }
 
 static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
                                         jlong cookie) {
-  std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env);
+  std::vector<std::unique_ptr<const DexFile>>* dex_files = toDexFiles(cookie, env);
   if (dex_files == NULL) {
     VLOG(class_linker) << "Failed to find dex_file";
     return NULL;
@@ -179,9 +190,9 @@
     return NULL;
   }
   const std::string descriptor(DotToDescriptor(class_name.c_str()));
-
-  for (const DexFile* dex_file : *dex_files) {
-    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str());
+  const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
+  for (auto& dex_file : *dex_files) {
+    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str(), hash);
     if (dex_class_def != nullptr) {
       ScopedObjectAccess soa(env);
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -189,15 +200,16 @@
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> class_loader(
           hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
-      mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(),
+      mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash,
                                                         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;
 }
 
@@ -211,13 +223,13 @@
 // Note: this can be an expensive call, as we sort out duplicates in MultiDex files.
 static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jlong cookie) {
   jobjectArray result = nullptr;
-  std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env);
+  std::vector<std::unique_ptr<const DexFile>>* dex_files = toDexFiles(cookie, env);
 
   if (dex_files != nullptr) {
     // Push all class descriptors into a set. Use set instead of unordered_set as we want to
     // retrieve all in the end.
     std::set<const char*, CharPointerComparator> descriptors;
-    for (const DexFile* dex_file : *dex_files) {
+    for (auto& dex_file : *dex_files) {
       for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
         const char* descriptor = dex_file->GetClassDescriptor(class_def);
@@ -287,18 +299,28 @@
 
 template <const bool kVerboseLogging, const bool kReasonLogging>
 static jbyte IsDexOptNeededForFile(const std::string& oat_filename, const char* filename,
-                                   InstructionSet target_instruction_set) {
+                                   InstructionSet target_instruction_set,
+                                   bool* oat_is_pic) {
   std::string error_msg;
   std::unique_ptr<const OatFile> oat_file(OatFile::Open(oat_filename, oat_filename, nullptr,
+                                                        nullptr,
                                                         false, &error_msg));
   if (oat_file.get() == nullptr) {
-    if (kReasonLogging) {
+    // Note that even though this is kDexoptNeeded, we use
+    // kVerboseLogging instead of the usual kReasonLogging since it is
+    // the common case on first boot and very spammy.
+    if (kVerboseLogging) {
       LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << oat_filename
           << "' for file location '" << filename << "': " << error_msg;
     }
     error_msg.clear();
     return kDexoptNeeded;
   }
+
+  // Pass-up the information about if this is PIC.
+  // TODO: Refactor this function to be less complicated.
+  *oat_is_pic = oat_file->IsPic();
+
   bool should_relocate_if_possible = Runtime::Current()->ShouldRelocate();
   uint32_t location_checksum = 0;
   const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename, nullptr,
@@ -526,10 +548,16 @@
   // Lets try the cache first (since we want to load from there since thats where the relocated
   // versions will be).
   if (have_cache_filename && !force_system_only) {
+    bool oat_is_pic;
     // We can use the dalvik-cache if we find a good file.
     dalvik_cache_decision =
         IsDexOptNeededForFile<kVerboseLogging, kReasonLogging>(cache_filename, filename,
-                                                               target_instruction_set);
+                                                               target_instruction_set, &oat_is_pic);
+
+    // Apps that are compiled with --compile-pic never need to be patchoat-d
+    if (oat_is_pic && dalvik_cache_decision == kPatchoatNeeded) {
+      dalvik_cache_decision = kUpToDate;
+    }
     // We will only return DexOptNeeded if both the cache and system return it.
     if (dalvik_cache_decision != kDexoptNeeded && !require_system_version) {
       CHECK(!(dalvik_cache_decision == kPatchoatNeeded && !should_relocate_if_possible))
@@ -539,12 +567,18 @@
     // We couldn't find one thats easy. We should now try the system.
   }
 
+  bool oat_is_pic;
   jbyte system_decision =
       IsDexOptNeededForFile<kVerboseLogging, kReasonLogging>(odex_filename, filename,
-                                                             target_instruction_set);
+                                                             target_instruction_set, &oat_is_pic);
   CHECK(!(system_decision == kPatchoatNeeded && !should_relocate_if_possible))
       << "May not return PatchoatNeeded when patching is disabled.";
 
+  // Apps that are compiled with --compile-pic never need to be patchoat-d
+  if (oat_is_pic && system_decision == kPatchoatNeeded) {
+    system_decision = kUpToDate;
+  }
+
   if (require_system_version && system_decision == kPatchoatNeeded
                              && dalvik_cache_decision == kUpToDate) {
     // We have a version from system relocated to the cache. Return it.
diff --git a/runtime/native/dalvik_system_DexFile.h b/runtime/native/dalvik_system_DexFile.h
new file mode 100644
index 0000000..487df05
--- /dev/null
+++ b/runtime/native/dalvik_system_DexFile.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_DALVIK_SYSTEM_DEXFILE_H_
+#define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_DEXFILE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_dalvik_system_DexFile(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_DALVIK_SYSTEM_DEXFILE_H_
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index ceff206..6c82eb2 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "dalvik_system_VMDebug.h"
+
 #include <string.h>
 #include <unistd.h>
 
diff --git a/runtime/native/dalvik_system_VMDebug.h b/runtime/native/dalvik_system_VMDebug.h
new file mode 100644
index 0000000..b7eb8a8
--- /dev/null
+++ b/runtime/native/dalvik_system_VMDebug.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_DALVIK_SYSTEM_VMDEBUG_H_
+#define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_VMDEBUG_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_dalvik_system_VMDebug(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_DALVIK_SYSTEM_VMDEBUG_H_
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 23f46f4..599d97f 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -14,9 +14,17 @@
  * limitations under the License.
  */
 
-#include <limits.h>
+#include "dalvik_system_VMRuntime.h"
 
-#include "ScopedUtfChars.h"
+#include <limits.h>
+#include <ScopedUtfChars.h>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "toStringArray.h"
+#pragma GCC diagnostic pop
+
+#include "arch/instruction_set.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "debugger.h"
@@ -26,7 +34,7 @@
 #include "gc/heap.h"
 #include "gc/space/dlmalloc_space.h"
 #include "gc/space/image_space.h"
-#include "instruction_set.h"
+#include "gc/task_processor.h"
 #include "intern_table.h"
 #include "jni_internal.h"
 #include "mirror/art_method-inl.h"
@@ -38,7 +46,6 @@
 #include "scoped_thread_state_change.h"
 #include "thread.h"
 #include "thread_list.h"
-#include "toStringArray.h"
 
 namespace art {
 
@@ -127,6 +134,10 @@
   Runtime::Current()->GetHeap()->ClearGrowthLimit();
 }
 
+static void VMRuntime_clampGrowthLimit(JNIEnv*, jobject) {
+  Runtime::Current()->GetHeap()->ClampGrowthLimit();
+}
+
 static jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) {
   return Dbg::IsDebuggerActive();
 }
@@ -166,13 +177,13 @@
   return env->NewStringUTF(isa_string);
 }
 
-static jboolean VMRuntime_is64Bit(JNIEnv* env, jobject) {
+static jboolean VMRuntime_is64Bit(JNIEnv*, jobject) {
   bool is64BitMode = (sizeof(void*) == sizeof(uint64_t));
   return is64BitMode ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean VMRuntime_isCheckJniEnabled(JNIEnv* env, jobject) {
-  return Runtime::Current()->GetJavaVM()->IsCheckJniEnabled() ? JNI_TRUE : JNI_FALSE;
+  return down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled() ? JNI_TRUE : JNI_FALSE;
 }
 
 static void VMRuntime_setTargetSdkVersionNative(JNIEnv*, jobject, jint target_sdk_version) {
@@ -201,23 +212,44 @@
   Runtime::Current()->GetHeap()->RegisterNativeFree(env, static_cast<size_t>(bytes));
 }
 
-static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) {
-  Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
-  Runtime::Current()->UpdateProfilerState(process_state);
+static void VMRuntime_updateProcessState(JNIEnv*, jobject, jint process_state) {
+  Runtime* runtime = Runtime::Current();
+  runtime->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
+  runtime->UpdateProfilerState(process_state);
 }
 
-static void VMRuntime_trimHeap(JNIEnv*, jobject) {
-  Runtime::Current()->GetHeap()->DoPendingTransitionOrTrim();
+static void VMRuntime_trimHeap(JNIEnv* env, jobject) {
+  Runtime::Current()->GetHeap()->Trim(ThreadForEnv(env));
 }
 
 static void VMRuntime_concurrentGC(JNIEnv* env, jobject) {
   Runtime::Current()->GetHeap()->ConcurrentGC(ThreadForEnv(env));
 }
 
+static void VMRuntime_requestHeapTrim(JNIEnv* env, jobject) {
+  Runtime::Current()->GetHeap()->RequestTrim(ThreadForEnv(env));
+}
+
+static void VMRuntime_requestConcurrentGC(JNIEnv* env, jobject) {
+  Runtime::Current()->GetHeap()->RequestConcurrentGC(ThreadForEnv(env));
+}
+
+static void VMRuntime_startHeapTaskProcessor(JNIEnv* env, jobject) {
+  Runtime::Current()->GetHeap()->GetTaskProcessor()->Start(ThreadForEnv(env));
+}
+
+static void VMRuntime_stopHeapTaskProcessor(JNIEnv* env, jobject) {
+  Runtime::Current()->GetHeap()->GetTaskProcessor()->Stop(ThreadForEnv(env));
+}
+
+static void VMRuntime_runHeapTasks(JNIEnv* env, jobject) {
+  Runtime::Current()->GetHeap()->GetTaskProcessor()->RunAllTasks(ThreadForEnv(env));
+}
+
 typedef std::map<std::string, mirror::String*> StringTable;
 
 static void PreloadDexCachesStringsCallback(mirror::Object** root, void* arg,
-                                            uint32_t /*thread_id*/, RootType /*root_type*/)
+                                            const RootInfo& /*root_info*/)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   StringTable& table = *reinterpret_cast<StringTable*>(arg);
   mirror::String* string = const_cast<mirror::Object*>(*root)->AsString();
@@ -255,7 +287,7 @@
   if (class_name[1] == '\0') {
     klass = linker->FindPrimitiveClass(class_name[0]);
   } else {
-    klass = linker->LookupClass(self, class_name, NULL);
+    klass = linker->LookupClass(self, class_name, ComputeModifiedUtf8Hash(class_name), NULL);
   }
   if (klass == NULL) {
     return;
@@ -326,6 +358,7 @@
       break;
     default:
       LOG(FATAL) << "Unreachable - invocation type: " << invoke_type;
+      UNREACHABLE();
   }
   if (method == NULL) {
     return;
@@ -384,26 +417,26 @@
     const DexFile* dex_file = boot_class_path[i];
     CHECK(dex_file != NULL);
     mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
-    for (size_t i = 0; i < dex_cache->NumStrings(); i++) {
-      mirror::String* string = dex_cache->GetResolvedString(i);
+    for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
+      mirror::String* string = dex_cache->GetResolvedString(j);
       if (string != NULL) {
         filled->num_strings++;
       }
     }
-    for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
-      mirror::Class* klass = dex_cache->GetResolvedType(i);
+    for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
+      mirror::Class* klass = dex_cache->GetResolvedType(j);
       if (klass != NULL) {
         filled->num_types++;
       }
     }
-    for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
-      mirror::ArtField* field = dex_cache->GetResolvedField(i);
+    for (size_t j = 0; j < dex_cache->NumResolvedFields(); j++) {
+      mirror::ArtField* field = dex_cache->GetResolvedField(j);
       if (field != NULL) {
         filled->num_fields++;
       }
     }
-    for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
-      mirror::ArtMethod* method = dex_cache->GetResolvedMethod(i);
+    for (size_t j = 0; j < dex_cache->NumResolvedMethods(); j++) {
+      mirror::ArtMethod* method = dex_cache->GetResolvedMethod(j);
       if (method != NULL) {
         filled->num_methods++;
       }
@@ -448,14 +481,14 @@
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file)));
 
     if (kPreloadDexCachesStrings) {
-      for (size_t i = 0; i < dex_cache->NumStrings(); i++) {
-        PreloadDexCachesResolveString(dex_cache, i, strings);
+      for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
+        PreloadDexCachesResolveString(dex_cache, j, strings);
       }
     }
 
     if (kPreloadDexCachesTypes) {
-      for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
-        PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), i);
+      for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
+        PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), j);
       }
     }
 
@@ -464,7 +497,7 @@
            class_def_index < dex_file->NumClassDefs();
            class_def_index++) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-        const byte* class_data = dex_file->GetClassData(class_def);
+        const uint8_t* class_data = dex_file->GetClassData(class_def);
         if (class_data == NULL) {
           continue;
         }
@@ -513,8 +546,9 @@
  * for ART.
  */
 static void VMRuntime_registerAppInfo(JNIEnv* env, jclass, jstring pkgName,
-                                      jstring appDir, jstring procName) {
-  const char *pkgNameChars = env->GetStringUTFChars(pkgName, NULL);
+                                      jstring appDir ATTRIBUTE_UNUSED,
+                                      jstring procName ATTRIBUTE_UNUSED) {
+  const char *pkgNameChars = env->GetStringUTFChars(pkgName, nullptr);
   std::string profileFile = StringPrintf("/data/dalvik-cache/profiles/%s", pkgNameChars);
 
   Runtime::Current()->StartProfiler(profileFile.c_str());
@@ -547,6 +581,7 @@
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"),
   NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
+  NATIVE_METHOD(VMRuntime, clampGrowthLimit, "()V"),
   NATIVE_METHOD(VMRuntime, classPath, "()Ljava/lang/String;"),
   NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"),
   NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
@@ -560,8 +595,13 @@
   NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"),
+  NATIVE_METHOD(VMRuntime, requestConcurrentGC, "()V"),
+  NATIVE_METHOD(VMRuntime, requestHeapTrim, "()V"),
+  NATIVE_METHOD(VMRuntime, runHeapTasks, "()V"),
   NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"),
+  NATIVE_METHOD(VMRuntime, startHeapTaskProcessor, "()V"),
   NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
+  NATIVE_METHOD(VMRuntime, stopHeapTaskProcessor, "()V"),
   NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
   NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
   NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"),
diff --git a/runtime/native/dalvik_system_VMRuntime.h b/runtime/native/dalvik_system_VMRuntime.h
new file mode 100644
index 0000000..795caa5
--- /dev/null
+++ b/runtime/native/dalvik_system_VMRuntime.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_DALVIK_SYSTEM_VMRUNTIME_H_
+#define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_VMRUNTIME_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_dalvik_system_VMRuntime(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_DALVIK_SYSTEM_VMRUNTIME_H_
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index eef1c46..2cdc68f 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "dalvik_system_VMStack.h"
+
 #include "jni_internal.h"
 #include "nth_caller_visitor.h"
 #include "mirror/art_method-inl.h"
@@ -36,12 +38,7 @@
     soa.Self()->TransitionFromRunnableToSuspended(kNative);
     ThreadList* thread_list = Runtime::Current()->GetThreadList();
     bool timed_out;
-    Thread* thread;
-    {
-      // Take suspend thread lock to avoid races with threads trying to suspend this one.
-      MutexLock mu(soa.Self(), *Locks::thread_list_suspend_thread_lock_);
-      thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
-    }
+    Thread* thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
     if (thread != nullptr) {
       // Must be runnable to create returned array.
       CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kNative);
@@ -87,8 +84,10 @@
 static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap,
                                                  jobject javaSystem) {
   struct ClosestUserClassLoaderVisitor : public StackVisitor {
-    ClosestUserClassLoaderVisitor(Thread* thread, mirror::Object* bootstrap, mirror::Object* system)
-      : StackVisitor(thread, NULL), bootstrap(bootstrap), system(system), class_loader(NULL) {}
+    ClosestUserClassLoaderVisitor(Thread* thread, mirror::Object* bootstrap_in,
+                                  mirror::Object* system_in)
+      : StackVisitor(thread, NULL), bootstrap(bootstrap_in), system(system_in),
+        class_loader(NULL) {}
 
     bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       DCHECK(class_loader == NULL);
diff --git a/runtime/native/dalvik_system_VMStack.h b/runtime/native/dalvik_system_VMStack.h
new file mode 100644
index 0000000..5638f99
--- /dev/null
+++ b/runtime/native/dalvik_system_VMStack.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_DALVIK_SYSTEM_VMSTACK_H_
+#define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_VMSTACK_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_dalvik_system_VMStack(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_DALVIK_SYSTEM_VMSTACK_H_
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index e469126..c056adc 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -14,17 +14,19 @@
  * limitations under the License.
  */
 
+#include "dalvik_system_ZygoteHooks.h"
+
 #include <stdlib.h>
 
+#include "arch/instruction_set.h"
 #include "debugger.h"
-#include "instruction_set.h"
 #include "java_vm_ext.h"
 #include "jni_internal.h"
 #include "JNIHelp.h"
 #include "ScopedUtfChars.h"
 #include "thread-inl.h"
 
-#if defined(HAVE_PRCTL)
+#if defined(__linux__)
 #include <sys/prctl.h>
 #endif
 
@@ -33,9 +35,9 @@
 namespace art {
 
 static void EnableDebugger() {
+#if defined(__linux__)
   // To let a non-privileged gdbserver attach to this
   // process, we must set our dumpable flag.
-#if defined(HAVE_PRCTL)
   if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
     PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid();
   }
@@ -84,9 +86,15 @@
   }
   debug_flags &= ~DEBUG_ENABLE_DEBUGGER;
 
-  // These two are for backwards compatibility with Dalvik.
+  if ((debug_flags & DEBUG_ENABLE_SAFEMODE) != 0) {
+    // Ensure that any (secondary) oat files will be interpreted.
+    Runtime* runtime = Runtime::Current();
+    runtime->AddCompilerOption("--compiler-filter=interpret-only");
+    debug_flags &= ~DEBUG_ENABLE_SAFEMODE;
+  }
+
+  // This is for backwards compatibility with Dalvik.
   debug_flags &= ~DEBUG_ENABLE_ASSERT;
-  debug_flags &= ~DEBUG_ENABLE_SAFEMODE;
 
   if (debug_flags != 0) {
     LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
@@ -100,8 +108,7 @@
   runtime->PreZygoteFork();
 
   // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
-  Thread* self = Thread::Current();
-  return reinterpret_cast<jlong>(self);
+  return reinterpret_cast<jlong>(ThreadForEnv(env));
 }
 
 static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
diff --git a/runtime/native/dalvik_system_ZygoteHooks.h b/runtime/native/dalvik_system_ZygoteHooks.h
new file mode 100644
index 0000000..ca0658d
--- /dev/null
+++ b/runtime/native/dalvik_system_ZygoteHooks.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_DALVIK_SYSTEM_ZYGOTEHOOKS_H_
+#define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_ZYGOTEHOOKS_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_dalvik_system_ZygoteHooks(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_DALVIK_SYSTEM_ZYGOTEHOOKS_H_
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index b11cbdf..1ea75f3 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_Class.h"
+
 #include "class_linker.h"
 #include "dex_file-inl.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_Class.h b/runtime/native/java_lang_Class.h
new file mode 100644
index 0000000..8f769c3
--- /dev/null
+++ b/runtime/native/java_lang_Class.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_CLASS_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_CLASS_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_Class(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_CLASS_H_
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index c1c6c26..27eae46 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_DexCache.h"
+
 #include "dex_file.h"
 #include "jni_internal.h"
 #include "mirror/dex_cache.h"
diff --git a/runtime/native/java_lang_DexCache.h b/runtime/native/java_lang_DexCache.h
new file mode 100644
index 0000000..b1c1f5e
--- /dev/null
+++ b/runtime/native/java_lang_DexCache.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_DEXCACHE_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_DEXCACHE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_DexCache(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_DEXCACHE_H_
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index 4768f48..49cacdf 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_Object.h"
+
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "scoped_fast_native_object_access.h"
diff --git a/runtime/native/java_lang_Object.h b/runtime/native/java_lang_Object.h
new file mode 100644
index 0000000..c860571
--- /dev/null
+++ b/runtime/native/java_lang_Object.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_OBJECT_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_OBJECT_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_Object(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_OBJECT_H_
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index a85eec7..dc0cb7b 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_Runtime.h"
+
 #include <dlfcn.h>
 #include <limits.h>
 #include <unistd.h>
@@ -37,7 +39,7 @@
   Runtime::Current()->GetHeap()->CollectGarbage(false);
 }
 
-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/java_lang_Runtime.h b/runtime/native/java_lang_Runtime.h
new file mode 100644
index 0000000..ceda06b
--- /dev/null
+++ b/runtime/native/java_lang_Runtime.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_Runtime(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_RUNTIME_H_
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index d6b47eb..4ea2546 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_String.h"
+
 #include "common_throws.h"
 #include "jni_internal.h"
 #include "mirror/string-inl.h"
diff --git a/runtime/native/java_lang_String.h b/runtime/native/java_lang_String.h
new file mode 100644
index 0000000..357eb3d
--- /dev/null
+++ b/runtime/native/java_lang_String.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_STRING_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_STRING_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_String(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_STRING_H_
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index ee99e78..f79be56 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_System.h"
+
 #include "common_throws.h"
 #include "gc/accounting/card_table-inl.h"
 #include "jni_internal.h"
@@ -93,7 +95,7 @@
     switch (dstComponentPrimitiveType) {
       case Primitive::kPrimVoid:
         LOG(FATAL) << "Unreachable, cannot have arrays of type void";
-        return;
+        UNREACHABLE();
       case Primitive::kPrimBoolean:
       case Primitive::kPrimByte:
         DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U);
@@ -122,7 +124,7 @@
       }
       default:
         LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray);
-        return;
+        UNREACHABLE();
     }
   }
   // If one of the arrays holds a primitive type the other array must hold the exact same type.
diff --git a/runtime/native/java_lang_System.h b/runtime/native/java_lang_System.h
new file mode 100644
index 0000000..e371fa5
--- /dev/null
+++ b/runtime/native/java_lang_System.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_SYSTEM_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_SYSTEM_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_System(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_SYSTEM_H_
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index c0c7265..e4b8db1 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_Thread.h"
+
 #include "common_throws.h"
 #include "debugger.h"
 #include "jni_internal.h"
@@ -86,6 +88,7 @@
     case kWaitingForSignalCatcherOutput:  return kJavaWaiting;
     case kWaitingInMainSignalCatcherLoop: return kJavaWaiting;
     case kWaitingForMethodTracingStart:   return kJavaWaiting;
+    case kWaitingForVisitObjects:         return kJavaWaiting;
     case kSuspended:                      return kJavaRunnable;
     // Don't add a 'default' here so the compiler can spot incompatible enum changes.
   }
@@ -116,14 +119,12 @@
 
 static void Thread_nativeSetName(JNIEnv* env, jobject peer, jstring java_name) {
   ScopedUtfChars name(env, java_name);
-  Thread* self;
   {
     ScopedObjectAccess soa(env);
     if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
       soa.Self()->SetThreadName(name.c_str());
       return;
     }
-    self = soa.Self();
   }
   // Suspend thread to avoid it from killing itself while we set its name. We don't just hold the
   // thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock
@@ -131,11 +132,7 @@
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   bool timed_out;
   // Take suspend thread lock to avoid races with threads trying to suspend this one.
-  Thread* thread;
-  {
-    MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_);
-    thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
-  }
+  Thread* thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
   if (thread != NULL) {
     {
       ScopedObjectAccess soa(env);
diff --git a/runtime/native/java_lang_Thread.h b/runtime/native/java_lang_Thread.h
new file mode 100644
index 0000000..7700ce2
--- /dev/null
+++ b/runtime/native/java_lang_Thread.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_THREAD_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_THREAD_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_Thread(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_THREAD_H_
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index 3ed4cfe..cb8a869 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_Throwable.h"
+
 #include "jni_internal.h"
 #include "scoped_fast_native_object_access.h"
 #include "thread.h"
diff --git a/runtime/native/java_lang_Throwable.h b/runtime/native/java_lang_Throwable.h
new file mode 100644
index 0000000..f9aea84
--- /dev/null
+++ b/runtime/native/java_lang_Throwable.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_THROWABLE_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_THROWABLE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_Throwable(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_THROWABLE_H_
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index f6a46bd..35932e0 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_VMClassLoader.h"
+
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
@@ -34,14 +36,16 @@
   }
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
   std::string descriptor(DotToDescriptor(name.c_str()));
-  mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), loader);
+  const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
+  mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
   if (c != nullptr && c->IsResolved()) {
     return soa.AddLocalReference<jclass>(c);
   }
   if (loader != nullptr) {
     // Try the common case.
     StackHandleScope<1> hs(soa.Self());
-    c = cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), hs.NewHandle(loader));
+    c = cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), descriptor_hash,
+                                       hs.NewHandle(loader));
     if (c != nullptr) {
       return soa.AddLocalReference<jclass>(c);
     }
diff --git a/runtime/native/java_lang_VMClassLoader.h b/runtime/native/java_lang_VMClassLoader.h
new file mode 100644
index 0000000..bf8d94f
--- /dev/null
+++ b/runtime/native/java_lang_VMClassLoader.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_VMCLASSLOADER_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_VMCLASSLOADER_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_VMClassLoader(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_VMCLASSLOADER_H_
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index ad48ec0..0532c35 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_ref_FinalizerReference.h"
+
 #include "gc/heap.h"
 #include "gc/reference_processor.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_ref_FinalizerReference.h b/runtime/native/java_lang_ref_FinalizerReference.h
new file mode 100644
index 0000000..848a7ad
--- /dev/null
+++ b/runtime/native/java_lang_ref_FinalizerReference.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REF_FINALIZERREFERENCE_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REF_FINALIZERREFERENCE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_ref_FinalizerReference(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REF_FINALIZERREFERENCE_H_
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index 4f04d60..d232059 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_ref_Reference.h"
+
 #include "gc/heap.h"
 #include "gc/reference_processor.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_ref_Reference.h b/runtime/native/java_lang_ref_Reference.h
new file mode 100644
index 0000000..0cbf116
--- /dev/null
+++ b/runtime/native/java_lang_ref_Reference.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REF_REFERENCE_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REF_REFERENCE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_ref_Reference(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REF_REFERENCE_H_
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index 763a664..1ffcbdf 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_reflect_Array.h"
+
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
diff --git a/runtime/native/java_lang_reflect_Array.h b/runtime/native/java_lang_reflect_Array.h
new file mode 100644
index 0000000..805bf79
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Array.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ARRAY_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ARRAY_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_reflect_Array(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ARRAY_H_
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 0542aeb..3121a90 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_reflect_Constructor.h"
+
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "mirror/art_method.h"
diff --git a/runtime/native/java_lang_reflect_Constructor.h b/runtime/native/java_lang_reflect_Constructor.h
new file mode 100644
index 0000000..7baae97
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Constructor.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REFLECT_CONSTRUCTOR_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_CONSTRUCTOR_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_reflect_Constructor(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_CONSTRUCTOR_H_
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index d166be0..2cebf02 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
+#include "java_lang_reflect_Field.h"
+
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
-#include "field_helper.h"
 #include "jni_internal.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
@@ -57,9 +58,8 @@
 }
 
 template<bool kAllowReferences>
-ALWAYS_INLINE inline static bool GetFieldValue(
-    const ScopedFastNativeObjectAccess& soa, mirror::Object* o, mirror::ArtField* f,
-    Primitive::Type field_type, JValue* value)
+ALWAYS_INLINE inline static bool GetFieldValue(mirror::Object* o, mirror::ArtField* f,
+                                               Primitive::Type field_type, JValue* value)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK_EQ(value->GetJ(), INT64_C(0));
   switch (field_type) {
@@ -148,7 +148,7 @@
   // Get the field's value, boxing if necessary.
   Primitive::Type field_type = f->GetTypeAsPrimitiveType();
   JValue value;
-  if (!GetFieldValue<true>(soa, o, f, field_type, &value)) {
+  if (!GetFieldValue<true>(o, f, field_type, &value)) {
     DCHECK(soa.Self()->IsExceptionPending());
     return nullptr;
   }
@@ -178,13 +178,13 @@
   JValue field_value;
   if (field_type == kPrimitiveType) {
     // This if statement should get optimized out since we only pass in valid primitive types.
-    if (UNLIKELY(!GetFieldValue<false>(soa, o, f, kPrimitiveType, &field_value))) {
+    if (UNLIKELY(!GetFieldValue<false>(o, f, kPrimitiveType, &field_value))) {
       DCHECK(soa.Self()->IsExceptionPending());
       return JValue();
     }
     return field_value;
   }
-  if (!GetFieldValue<false>(soa, o, f, field_type, &field_value)) {
+  if (!GetFieldValue<false>(o, f, field_type, &field_value)) {
     DCHECK(soa.Self()->IsExceptionPending());
     return JValue();
   }
@@ -232,9 +232,8 @@
   return GetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj, accessible).GetS();
 }
 
-static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o,
-                          mirror::ArtField* f, Primitive::Type field_type, bool allow_references,
-                          const JValue& new_value)
+static void SetFieldValue(mirror::Object* o, mirror::ArtField* f, Primitive::Type field_type,
+                          bool allow_references, const JValue& new_value)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(f->GetDeclaringClass()->IsInitialized());
   switch (field_type) {
@@ -268,6 +267,7 @@
       break;
     }
     // Else fall through to report an error.
+    FALLTHROUGH_INTENDED;
   case Primitive::kPrimVoid:
     // Never okay.
     ThrowIllegalArgumentException(nullptr, StringPrintf("Not a primitive field: %s",
@@ -293,9 +293,8 @@
     StackHandleScope<2> hs(soa.Self());
     HandleWrapper<mirror::Object> h_o(hs.NewHandleWrapper(&o));
     HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f));
-    FieldHelper fh(h_f);
     // May cause resolution.
-    field_type = fh.GetType(true);
+    field_type = h_f->GetType(true);
     if (field_type == nullptr) {
       DCHECK(soa.Self()->IsExceptionPending());
       return;
@@ -316,7 +315,7 @@
     DCHECK(soa.Self()->IsExceptionPending());
     return;
   }
-  SetFieldValue(soa, o, f, field_prim_type, true, unboxed_value);
+  SetFieldValue(o, f, field_prim_type, true, unboxed_value);
 }
 
 template<Primitive::Type kPrimitiveType>
@@ -349,7 +348,7 @@
   }
 
   // Write the value.
-  SetFieldValue(soa, o, f, field_type, false, wide_value);
+  SetFieldValue(o, f, field_type, false, wide_value);
 }
 
 static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z,
diff --git a/runtime/native/java_lang_reflect_Field.h b/runtime/native/java_lang_reflect_Field.h
new file mode 100644
index 0000000..1739711
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Field.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REFLECT_FIELD_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_FIELD_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_reflect_Field(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_FIELD_H_
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index f029b16..9859746 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_reflect_Method.h"
+
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "mirror/art_method.h"
diff --git a/runtime/native/java_lang_reflect_Method.h b/runtime/native/java_lang_reflect_Method.h
new file mode 100644
index 0000000..3a93cd0
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Method.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REFLECT_METHOD_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_METHOD_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_reflect_Method(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_METHOD_H_
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 07d670d..baf8b24 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_lang_reflect_Proxy.h"
+
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
diff --git a/runtime/native/java_lang_reflect_Proxy.h b/runtime/native/java_lang_reflect_Proxy.h
new file mode 100644
index 0000000..e25f0f7
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Proxy.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_LANG_REFLECT_PROXY_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_PROXY_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_reflect_Proxy(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_PROXY_H_
diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
index bf92e12..04f0ba0 100644
--- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
+++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "java_util_concurrent_atomic_AtomicLong.h"
+
 #include "atomic.h"
 #include "jni_internal.h"
 
diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.h b/runtime/native/java_util_concurrent_atomic_AtomicLong.h
new file mode 100644
index 0000000..990dc86
--- /dev/null
+++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMICLONG_H_
+#define ART_RUNTIME_NATIVE_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMICLONG_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_util_concurrent_atomic_AtomicLong(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMICLONG_H_
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index 8b2aecb..0ab2979 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "org_apache_harmony_dalvik_ddmc_DdmServer.h"
+
 #include "base/logging.h"
 #include "debugger.h"
 #include "jni_internal.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h
new file mode 100644
index 0000000..9a4645c
--- /dev/null
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_ORG_APACHE_HARMONY_DALVIK_DDMC_DDMSERVER_H_
+#define ART_RUNTIME_NATIVE_ORG_APACHE_HARMONY_DALVIK_DDMC_DDMSERVER_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_org_apache_harmony_dalvik_ddmc_DdmServer(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_ORG_APACHE_HARMONY_DALVIK_DDMC_DDMSERVER_H_
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 45ef9ae..987427e 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "org_apache_harmony_dalvik_ddmc_DdmVmInternal.h"
+
 #include "base/logging.h"
 #include "base/mutex.h"
 #include "debugger.h"
@@ -61,12 +63,7 @@
     }
 
     // Suspend thread to build stack trace.
-    Thread* thread;
-    {
-      // Take suspend thread lock to avoid races with threads trying to suspend this one.
-      MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_);
-      thread = thread_list->SuspendThreadByThreadId(thin_lock_id, false, &timed_out);
-    }
+    Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id, false, &timed_out);
     if (thread != nullptr) {
       {
         ScopedObjectAccess soa(env);
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h
new file mode 100644
index 0000000..736e4c8
--- /dev/null
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_ORG_APACHE_HARMONY_DALVIK_DDMC_DDMVMINTERNAL_H_
+#define ART_RUNTIME_NATIVE_ORG_APACHE_HARMONY_DALVIK_DDMC_DDMVMINTERNAL_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_ORG_APACHE_HARMONY_DALVIK_DDMC_DDMVMINTERNAL_H_
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/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 65dece0..17ebdff 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "sun_misc_Unsafe.h"
+
 #include "gc/accounting/card_table-inl.h"
 #include "jni_internal.h"
 #include "mirror/array.h"
diff --git a/runtime/native/sun_misc_Unsafe.h b/runtime/native/sun_misc_Unsafe.h
new file mode 100644
index 0000000..93194f4
--- /dev/null
+++ b/runtime/native/sun_misc_Unsafe.h
@@ -0,0 +1,28 @@
+/*
+ * 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_RUNTIME_NATIVE_SUN_MISC_UNSAFE_H_
+#define ART_RUNTIME_NATIVE_SUN_MISC_UNSAFE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_sun_misc_Unsafe(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_SUN_MISC_UNSAFE_H_
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index bc191b4..b7f31f2 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -19,21 +19,21 @@
 #include "nativebridge/native_bridge.h"
 
 #include "base/logging.h"
+#include "base/macros.h"
+#include "dex_file-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "scoped_thread_state_change.h"
 
 namespace art {
 
-const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
+static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
   ScopedObjectAccess soa(env);
-  StackHandleScope<1> scope(soa.Self());
   mirror::ArtMethod* m = soa.DecodeMethod(mid);
-  MethodHelper mh(scope.NewHandle(m));
-  return mh.GetShorty();
+  return m->GetShorty();
 }
 
-uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
+static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
   if (clazz == nullptr)
     return 0;
 
@@ -56,8 +56,8 @@
   return native_method_count;
 }
 
-uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
-                          uint32_t method_count) {
+static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+                                 uint32_t method_count) {
   if ((clazz == nullptr) || (methods == nullptr)) {
     return 0;
   }
@@ -71,7 +71,7 @@
       if (count < method_count) {
         methods[count].name = m->GetName();
         methods[count].signature = m->GetShorty();
-        methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
+        methods[count].fnPtr = m->GetEntryPointFromJni();
         count++;
       } else {
         LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
@@ -84,7 +84,7 @@
       if (count < method_count) {
         methods[count].name = m->GetName();
         methods[count].signature = m->GetShorty();
-        methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
+        methods[count].fnPtr = m->GetEntryPointFromJni();
         count++;
       } else {
         LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
@@ -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) {
@@ -118,9 +119,10 @@
 #ifndef __APPLE__  // Mac OS does not support CLONE_NEWNS.
   if (unshare(CLONE_NEWNS) == -1) {
     LOG(WARNING) << "Could not create mount namespace.";
-    return;
   }
   android::PreInitializeNativeBridge(dir.c_str(), GetInstructionSetString(kRuntimeISA));
+#else
+  UNUSED(dir);
 #endif
 }
 
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/noop_compiler_callbacks.h b/runtime/noop_compiler_callbacks.h
index e9ad353..300abc9 100644
--- a/runtime/noop_compiler_callbacks.h
+++ b/runtime/noop_compiler_callbacks.h
@@ -26,11 +26,11 @@
   NoopCompilerCallbacks() {}
   ~NoopCompilerCallbacks() {}
 
-  bool MethodVerified(verifier::MethodVerifier* verifier) OVERRIDE {
+  bool MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) OVERRIDE {
     return true;
   }
 
-  void ClassRejected(ClassReference ref) OVERRIDE {}
+  void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) OVERRIDE {}
 
   // This is only used by compilers which need to be able to run without relocation even when it
   // would normally be enabled. For example the patchoat executable, and dex2oat --image, both need
diff --git a/runtime/nth_caller_visitor.h b/runtime/nth_caller_visitor.h
index 374a80e..a851f21 100644
--- a/runtime/nth_caller_visitor.h
+++ b/runtime/nth_caller_visitor.h
@@ -26,9 +26,9 @@
 
 // Walks up the stack 'n' callers, when used with Thread::WalkStack.
 struct NthCallerVisitor : public StackVisitor {
-  NthCallerVisitor(Thread* thread, size_t n, bool include_runtime_and_upcalls = false)
-      : StackVisitor(thread, NULL), n(n), include_runtime_and_upcalls_(include_runtime_and_upcalls),
-        count(0), caller(NULL) {}
+  NthCallerVisitor(Thread* thread, size_t n_in, bool include_runtime_and_upcalls = false)
+      : StackVisitor(thread, NULL), n(n_in),
+        include_runtime_and_upcalls_(include_runtime_and_upcalls), count(0), caller(NULL) {}
 
   bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::ArtMethod* m = GetMethod();
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 6810d73..c223e2e 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -15,15 +15,18 @@
  */
 
 #include "oat.h"
-#include "utils.h"
 
 #include <string.h>
 #include <zlib.h>
 
+#include "arch/instruction_set_features.h"
+#include "base/stringprintf.h"
+#include "utils.h"
+
 namespace art {
 
-const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '4', '2', '\0' };
+constexpr uint8_t OatHeader::kOatMagic[4];
+constexpr uint8_t OatHeader::kOatVersion[4];
 
 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
   size_t estimate = 0U;
@@ -39,7 +42,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,11 +63,18 @@
 }
 
 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,
                      const SafeMap<std::string, std::string>* variable_data) {
+  // Don't want asserts in header as they would be checked in each file that includes it. But the
+  // fields are private, so we check inside a method.
+  static_assert(sizeof(magic_) == sizeof(kOatMagic),
+                "Oat magic and magic_ have different lengths.");
+  static_assert(sizeof(version_) == sizeof(kOatVersion),
+                "Oat version and version_ have different lengths.");
+
   memcpy(magic_, kOatMagic, sizeof(kOatMagic));
   memcpy(version_, kOatVersion, sizeof(kOatVersion));
   executable_offset_ = 0;
@@ -76,8 +86,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_));
@@ -103,9 +113,6 @@
   interpreter_to_interpreter_bridge_offset_ = 0;
   interpreter_to_compiled_code_bridge_offset_ = 0;
   jni_dlsym_lookup_offset_ = 0;
-  portable_imt_conflict_trampoline_offset_ = 0;
-  portable_resolution_trampoline_offset_ = 0;
-  portable_to_interpreter_bridge_offset_ = 0;
   quick_generic_jni_trampoline_offset_ = 0;
   quick_imt_conflict_trampoline_offset_ = 0;
   quick_resolution_trampoline_offset_ = 0;
@@ -128,6 +135,28 @@
   return true;
 }
 
+std::string OatHeader::GetValidationErrorMessage() const {
+  if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) {
+    static_assert(sizeof(kOatMagic) == 4, "kOatMagic has unexpected length");
+    return StringPrintf("Invalid oat magic, expected 0x%x%x%x%x, got 0x%x%x%x%x.",
+                        kOatMagic[0], kOatMagic[1], kOatMagic[2], kOatMagic[3],
+                        magic_[0], magic_[1], magic_[2], magic_[3]);
+  }
+  if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) {
+    static_assert(sizeof(kOatVersion) == 4, "kOatVersion has unexpected length");
+    return StringPrintf("Invalid oat version, expected 0x%x%x%x%x, got 0x%x%x%x%x.",
+                        kOatVersion[0], kOatVersion[1], kOatVersion[2], kOatVersion[3],
+                        version_[0], version_[1], version_[2], version_[3]);
+  }
+  if (!IsAligned<kPageSize>(executable_offset_)) {
+    return "Executable offset not page-aligned.";
+  }
+  if (!IsAligned<kPageSize>(image_patch_delta_)) {
+    return "Image patch delta not page-aligned.";
+  }
+  return "";
+}
+
 const char* OatHeader::GetMagic() const {
   CHECK(IsValid());
   return reinterpret_cast<const char*>(magic_);
@@ -149,9 +178,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 {
@@ -229,75 +258,18 @@
   UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset));
 }
 
-const void* OatHeader::GetPortableImtConflictTrampoline() const {
-  return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset();
-}
-
-uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const {
-  DCHECK(IsValid());
-  CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_);
-  return portable_imt_conflict_trampoline_offset_;
-}
-
-void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) {
-  CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
-  DCHECK(IsValid());
-  DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset;
-
-  portable_imt_conflict_trampoline_offset_ = offset;
-  UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset));
-}
-
-const void* OatHeader::GetPortableResolutionTrampoline() const {
-  return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
-}
-
-uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
-  DCHECK(IsValid());
-  CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_);
-  return portable_resolution_trampoline_offset_;
-}
-
-void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
-  CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_);
-  DCHECK(IsValid());
-  DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;
-
-  portable_resolution_trampoline_offset_ = offset;
-  UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
-}
-
-const void* OatHeader::GetPortableToInterpreterBridge() const {
-  return reinterpret_cast<const uint8_t*>(this) + GetPortableToInterpreterBridgeOffset();
-}
-
-uint32_t OatHeader::GetPortableToInterpreterBridgeOffset() const {
-  DCHECK(IsValid());
-  CHECK_GE(portable_to_interpreter_bridge_offset_, portable_resolution_trampoline_offset_);
-  return portable_to_interpreter_bridge_offset_;
-}
-
-void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) {
-  CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
-  DCHECK(IsValid());
-  DCHECK_EQ(portable_to_interpreter_bridge_offset_, 0U) << offset;
-
-  portable_to_interpreter_bridge_offset_ = offset;
-  UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset));
-}
-
 const void* OatHeader::GetQuickGenericJniTrampoline() const {
   return reinterpret_cast<const uint8_t*>(this) + GetQuickGenericJniTrampolineOffset();
 }
 
 uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const {
   DCHECK(IsValid());
-  CHECK_GE(quick_generic_jni_trampoline_offset_, portable_to_interpreter_bridge_offset_);
+  CHECK_GE(quick_generic_jni_trampoline_offset_, jni_dlsym_lookup_offset_);
   return quick_generic_jni_trampoline_offset_;
 }
 
 void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) {
-  CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
+  CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
   DCHECK(IsValid());
   DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset;
 
@@ -470,6 +442,12 @@
   return sizeof(OatHeader) + key_value_store_size_;
 }
 
+bool OatHeader::IsPic() const {
+  const char* pic_string = GetStoreValueByKey(OatHeader::kPicKey);
+  static const char kTrue[] = "true";
+  return (pic_string != nullptr && strncmp(pic_string, kTrue, sizeof(kTrue)) == 0);
+}
+
 void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
   char* data_ptr = reinterpret_cast<char*>(&key_value_store_);
   if (key_value_store != nullptr) {
@@ -485,35 +463,19 @@
   key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_);
 }
 
-OatMethodOffsets::OatMethodOffsets()
-  : code_offset_(0),
-    gc_map_offset_(0)
-{}
-
-OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
-                                   uint32_t gc_map_offset
-                                   )
-  : code_offset_(code_offset),
-    gc_map_offset_(gc_map_offset)
-{}
+OatMethodOffsets::OatMethodOffsets(uint32_t code_offset) : code_offset_(code_offset) {
+}
 
 OatMethodOffsets::~OatMethodOffsets() {}
 
-OatQuickMethodHeader::OatQuickMethodHeader()
-  : mapping_table_offset_(0),
-    vmap_table_offset_(0),
-    frame_info_(0, 0, 0),
-    code_size_(0)
-{}
-
 OatQuickMethodHeader::OatQuickMethodHeader(
-    uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t frame_size_in_bytes,
-    uint32_t core_spill_mask, uint32_t fp_spill_mask, uint32_t code_size)
-  : mapping_table_offset_(mapping_table_offset),
-    vmap_table_offset_(vmap_table_offset),
-    frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask),
-    code_size_(code_size)
-{}
+    uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t gc_map_offset,
+    uint32_t frame_size_in_bytes, uint32_t core_spill_mask, uint32_t fp_spill_mask,
+    uint32_t code_size)
+    : mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset),
+      gc_map_offset_(gc_map_offset),
+      frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask), code_size_(code_size) {
+}
 
 OatQuickMethodHeader::~OatQuickMethodHeader() {}
 
diff --git a/runtime/oat.h b/runtime/oat.h
index 6a32e3e..8e63d3a 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -19,31 +19,35 @@
 
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "dex_file.h"
-#include "instruction_set.h"
 #include "quick/quick_method_frame_info.h"
 #include "safe_map.h"
 
 namespace art {
 
+class InstructionSetFeatures;
+
 class PACKED(4) OatHeader {
  public:
-  static const uint8_t kOatMagic[4];
-  static const uint8_t kOatVersion[4];
+  static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
+  static constexpr uint8_t kOatVersion[] = { '0', '5', '3', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
   static constexpr const char* kDex2OatHostKey = "dex2oat-host";
+  static constexpr const char* kPicKey = "pic";
 
   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,
                            const SafeMap<std::string, std::string>* variable_data);
 
   bool IsValid() const;
+  std::string GetValidationErrorMessage() const;
   const char* GetMagic() const;
   uint32_t GetChecksum() const;
   void UpdateChecksum(const void* data, size_t length);
@@ -65,16 +69,6 @@
   uint32_t GetJniDlsymLookupOffset() const;
   void SetJniDlsymLookupOffset(uint32_t offset);
 
-  const void* GetPortableResolutionTrampoline() const;
-  uint32_t GetPortableResolutionTrampolineOffset() const;
-  void SetPortableResolutionTrampolineOffset(uint32_t offset);
-  const void* GetPortableImtConflictTrampoline() const;
-  uint32_t GetPortableImtConflictTrampolineOffset() const;
-  void SetPortableImtConflictTrampolineOffset(uint32_t offset);
-  const void* GetPortableToInterpreterBridge() const;
-  uint32_t GetPortableToInterpreterBridgeOffset() const;
-  void SetPortableToInterpreterBridgeOffset(uint32_t offset);
-
   const void* GetQuickGenericJniTrampoline() const;
   uint32_t GetQuickGenericJniTrampolineOffset() const;
   void SetQuickGenericJniTrampolineOffset(uint32_t offset);
@@ -93,7 +87,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;
 
@@ -103,10 +97,11 @@
   bool GetStoreKeyValuePairByIndex(size_t index, const char** key, const char** value) const;
 
   size_t GetHeaderSize() const;
+  bool IsPic() const;
 
  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,15 +114,12 @@
   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_;
   uint32_t interpreter_to_compiled_code_bridge_offset_;
   uint32_t jni_dlsym_lookup_offset_;
-  uint32_t portable_imt_conflict_trampoline_offset_;
-  uint32_t portable_resolution_trampoline_offset_;
-  uint32_t portable_to_interpreter_bridge_offset_;
   uint32_t quick_generic_jni_trampoline_offset_;
   uint32_t quick_imt_conflict_trampoline_offset_;
   uint32_t quick_resolution_trampoline_offset_;
@@ -160,25 +152,20 @@
 
 class PACKED(4) OatMethodOffsets {
  public:
-  OatMethodOffsets();
-
-  OatMethodOffsets(uint32_t code_offset,
-                   uint32_t gc_map_offset);
+  OatMethodOffsets(uint32_t code_offset = 0);
 
   ~OatMethodOffsets();
 
   uint32_t code_offset_;
-  uint32_t gc_map_offset_;
 };
 
 // OatQuickMethodHeader precedes the raw code chunk generated by the Quick compiler.
 class PACKED(4) OatQuickMethodHeader {
  public:
-  OatQuickMethodHeader();
-
-  explicit OatQuickMethodHeader(uint32_t mapping_table_offset, uint32_t vmap_table_offset,
-                                uint32_t frame_size_in_bytes, uint32_t core_spill_mask,
-                                uint32_t fp_spill_mask, uint32_t code_size);
+  OatQuickMethodHeader(uint32_t mapping_table_offset = 0U, uint32_t vmap_table_offset = 0U,
+                       uint32_t gc_map_offset = 0U, uint32_t frame_size_in_bytes = 0U,
+                       uint32_t core_spill_mask = 0U, uint32_t fp_spill_mask = 0U,
+                       uint32_t code_size = 0U);
 
   ~OatQuickMethodHeader();
 
@@ -186,6 +173,8 @@
   uint32_t mapping_table_offset_;
   // The offset in bytes from the start of the vmap table to the end of the header.
   uint32_t vmap_table_offset_;
+  // The offset in bytes from the start of the gc map to the end of the header.
+  uint32_t gc_map_offset_;
   // The stack frame information.
   QuickMethodFrameInfo frame_info_;
   // The code size in bytes.
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index 9570bb5..a429c87 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -35,7 +35,7 @@
   if (method_header == nullptr) {
     return 0u;
   }
-  return reinterpret_cast<const byte*>(method_header) - begin_;
+  return reinterpret_cast<const uint8_t*>(method_header) - begin_;
 }
 
 inline uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
@@ -51,7 +51,7 @@
   if (method_header == nullptr) {
     return 0u;
   }
-  return reinterpret_cast<const byte*>(&method_header->code_size_) - begin_;
+  return reinterpret_cast<const uint8_t*>(&method_header->code_size_) - begin_;
 }
 
 inline size_t OatFile::OatMethod::GetFrameSizeInBytes() const {
@@ -78,6 +78,31 @@
   return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.FpSpillMask();
 }
 
+const uint8_t* OatFile::OatMethod::GetGcMap() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return nullptr;
+  }
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].gc_map_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code) - offset;
+}
+
+uint32_t OatFile::OatMethod::GetGcMapOffset() const {
+  const uint8_t* gc_map = GetGcMap();
+  return static_cast<uint32_t>(gc_map != nullptr ? gc_map - begin_ : 0u);
+}
+
+uint32_t OatFile::OatMethod::GetGcMapOffsetOffset() const {
+  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
+  if (method_header == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const uint8_t*>(&method_header->gc_map_offset_) - begin_;
+}
+
 inline uint32_t OatFile::OatMethod::GetMappingTableOffset() const {
   const uint8_t* mapping_table = GetMappingTable();
   return static_cast<uint32_t>(mapping_table != nullptr ? mapping_table - begin_ : 0u);
@@ -88,7 +113,7 @@
   if (method_header == nullptr) {
     return 0u;
   }
-  return reinterpret_cast<const byte*>(&method_header->mapping_table_offset_) - begin_;
+  return reinterpret_cast<const uint8_t*>(&method_header->mapping_table_offset_) - begin_;
 }
 
 inline uint32_t OatFile::OatMethod::GetVmapTableOffset() const {
@@ -101,7 +126,7 @@
   if (method_header == nullptr) {
     return 0u;
   }
-  return reinterpret_cast<const byte*>(&method_header->vmap_table_offset_) - begin_;
+  return reinterpret_cast<const uint8_t*>(&method_header->vmap_table_offset_) - begin_;
 }
 
 inline const uint8_t* OatFile::OatMethod::GetMappingTable() const {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index a896f3e..9061bb3 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -47,9 +47,11 @@
                                   std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
   oat_file->elf_file_.reset(elf_file);
-  Elf32_Shdr* hdr = elf_file->FindSectionByName(".rodata");
-  oat_file->begin_ = elf_file->Begin() + hdr->sh_offset;
-  oat_file->end_ = elf_file->Begin() + hdr->sh_size + hdr->sh_offset;
+  uint64_t offset, size;
+  bool has_section = elf_file->GetSectionOffsetAndSize(".rodata", &offset, &size);
+  CHECK(has_section);
+  oat_file->begin_ = elf_file->Begin() + offset;
+  oat_file->end_ = elf_file->Begin() + size + offset;
   return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
 }
 
@@ -66,53 +68,49 @@
 
 OatFile* OatFile::Open(const std::string& filename,
                        const std::string& location,
-                       byte* requested_base,
+                       uint8_t* requested_base,
+                       uint8_t* oat_file_begin,
                        bool executable,
                        std::string* error_msg) {
   CHECK(!filename.empty()) << location;
-  CheckLocation(filename);
+  CheckLocation(location);
   std::unique_ptr<OatFile> ret;
-  if (kUsePortableCompiler && executable) {
-    // If we are using PORTABLE, use dlopen to deal with relocations.
-    //
-    // We use our own ELF loader for Quick to deal with legacy apps that
-    // open a generated dex file by name, remove the file, then open
-    // another generated dex file with the same name. http://b/10614658
-    ret.reset(OpenDlopen(filename, location, requested_base, error_msg));
-  } else {
-    // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
-    //
-    // On target, dlopen may fail when compiling due to selinux restrictions on installd.
-    //
-    // On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
-    // This won't work for portable runtime execution because it doesn't process relocations.
-    std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
-    if (file.get() == NULL) {
-      *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno));
-      return nullptr;
-    }
-    ret.reset(OpenElfFile(file.get(), location, requested_base, false, executable, error_msg));
-
-    // It would be nice to unlink here. But we might have opened the file created by the
-    // ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API
-    // to allow removal when we know the ELF must be borked.
+  // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
+  //
+  // On target, dlopen may fail when compiling due to selinux restrictions on installd.
+  //
+  // We use our own ELF loader for Quick to deal with legacy apps that
+  // open a generated dex file by name, remove the file, then open
+  // another generated dex file with the same name. http://b/10614658
+  //
+  // On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
+  std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
+  if (file.get() == NULL) {
+    *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno));
+    return nullptr;
   }
+  ret.reset(OpenElfFile(file.get(), location, requested_base, oat_file_begin, false, executable,
+                        error_msg));
+
+  // It would be nice to unlink here. But we might have opened the file created by the
+  // ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API
+  // to allow removal when we know the ELF must be borked.
   return ret.release();
 }
 
 OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) {
   CheckLocation(location);
-  return OpenElfFile(file, location, NULL, true, false, error_msg);
+  return OpenElfFile(file, location, nullptr, nullptr, true, false, error_msg);
 }
 
 OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::string* error_msg) {
   CheckLocation(location);
-  return OpenElfFile(file, location, NULL, false, false, error_msg);
+  return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg);
 }
 
 OatFile* OatFile::OpenDlopen(const std::string& elf_filename,
                              const std::string& location,
-                             byte* requested_base,
+                             uint8_t* requested_base,
                              std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(new OatFile(location, true));
   bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg);
@@ -124,12 +122,14 @@
 
 OatFile* OatFile::OpenElfFile(File* file,
                               const std::string& location,
-                              byte* requested_base,
+                              uint8_t* requested_base,
+                              uint8_t* oat_file_begin,
                               bool writable,
                               bool executable,
                               std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(new OatFile(location, executable));
-  bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg);
+  bool success = oat_file->ElfFileOpen(file, requested_base, oat_file_begin, writable, executable,
+                                       error_msg);
   if (!success) {
     CHECK(!error_msg->empty());
     return nullptr;
@@ -151,7 +151,7 @@
   }
 }
 
-bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base,
+bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base,
                      std::string* error_msg) {
   char* absolute_path = realpath(elf_filename.c_str(), NULL);
   if (absolute_path == NULL) {
@@ -164,7 +164,7 @@
     *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror());
     return false;
   }
-  begin_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatdata"));
+  begin_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatdata"));
   if (begin_ == NULL) {
     *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(),
                               dlerror());
@@ -177,7 +177,7 @@
     ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
-  end_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatlastword"));
+  end_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatlastword"));
   if (end_ == NULL) {
     *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(),
                               dlerror());
@@ -188,9 +188,12 @@
   return Setup(error_msg);
 }
 
-bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable,
+bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin,
+                          bool writable, bool executable,
                           std::string* error_msg) {
-  elf_file_.reset(ElfFile::Open(file, writable, true, error_msg));
+  // TODO: rename requested_base to oat_data_begin
+  elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, error_msg,
+                                oat_file_begin));
   if (elf_file_.get() == nullptr) {
     DCHECK(!error_msg->empty());
     return false;
@@ -224,10 +227,12 @@
 
 bool OatFile::Setup(std::string* error_msg) {
   if (!GetOatHeader().IsValid()) {
-    *error_msg = StringPrintf("Invalid oat magic for '%s'", GetLocation().c_str());
+    std::string cause = GetOatHeader().GetValidationErrorMessage();
+    *error_msg = StringPrintf("Invalid oat header for '%s': %s", GetLocation().c_str(),
+                              cause.c_str());
     return false;
   }
-  const byte* oat = Begin();
+  const uint8_t* oat = Begin();
   oat += sizeof(OatHeader);
   if (oat > End()) {
     *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str());
@@ -293,7 +298,7 @@
     oat += sizeof(dex_file_offset);
     if (UNLIKELY(oat > End())) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
-                                " after dex file offsets", GetLocation().c_str(), i,
+                                "after dex file offsets", GetLocation().c_str(), i,
                                 dex_file_location.c_str());
       return false;
     }
@@ -301,13 +306,13 @@
     const uint8_t* dex_file_pointer = Begin() + dex_file_offset;
     if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
-                                " dex file magic '%s'", GetLocation().c_str(), i,
+                                "dex file magic '%s'", GetLocation().c_str(), i,
                                 dex_file_location.c_str(), dex_file_pointer);
       return false;
     }
     if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
-                                " dex file version '%s'", GetLocation().c_str(), i,
+                                "dex file version '%s'", GetLocation().c_str(), i,
                                 dex_file_location.c_str(), dex_file_pointer);
       return false;
     }
@@ -317,7 +322,7 @@
     oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_);
     if (UNLIKELY(oat > End())) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated "
-                                " method offsets", GetLocation().c_str(), i,
+                                "method offsets", GetLocation().c_str(), i,
                                 dex_file_location.c_str());
       return false;
     }
@@ -348,12 +353,12 @@
   return *reinterpret_cast<const OatHeader*>(Begin());
 }
 
-const byte* OatFile::Begin() const {
+const uint8_t* OatFile::Begin() const {
   CHECK(begin_ != NULL);
   return begin_;
 }
 
-const byte* OatFile::End() const {
+const uint8_t* OatFile::End() const {
   CHECK(end_ != NULL);
   return end_;
 }
@@ -434,7 +439,7 @@
                                 const std::string& dex_file_location,
                                 const std::string& canonical_dex_file_location,
                                 uint32_t dex_file_location_checksum,
-                                const byte* dex_file_pointer,
+                                const uint8_t* dex_file_pointer,
                                 const uint32_t* oat_class_offsets_pointer)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
@@ -449,9 +454,9 @@
   return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
 }
 
-const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
+std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
   return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
-                       dex_file_location_checksum_, error_msg);
+                       dex_file_location_checksum_, GetOatFile(), error_msg);
 }
 
 uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
@@ -461,26 +466,26 @@
 OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const {
   uint32_t oat_class_offset = GetOatClassOffset(class_def_index);
 
-  const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset;
+  const uint8_t* oat_class_pointer = oat_file_->Begin() + oat_class_offset;
   CHECK_LT(oat_class_pointer, oat_file_->End()) << oat_file_->GetLocation();
 
-  const byte* status_pointer = oat_class_pointer;
+  const uint8_t* status_pointer = oat_class_pointer;
   CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation();
   mirror::Class::Status status =
       static_cast<mirror::Class::Status>(*reinterpret_cast<const int16_t*>(status_pointer));
   CHECK_LT(status, mirror::Class::kStatusMax);
 
-  const byte* type_pointer = status_pointer + sizeof(uint16_t);
+  const uint8_t* type_pointer = status_pointer + sizeof(uint16_t);
   CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation();
   OatClassType type = static_cast<OatClassType>(*reinterpret_cast<const uint16_t*>(type_pointer));
   CHECK_LT(type, kOatClassMax);
 
-  const byte* after_type_pointer = type_pointer + sizeof(int16_t);
+  const uint8_t* after_type_pointer = type_pointer + sizeof(int16_t);
   CHECK_LE(after_type_pointer, oat_file_->End()) << oat_file_->GetLocation();
 
   uint32_t bitmap_size = 0;
-  const byte* bitmap_pointer = nullptr;
-  const byte* methods_pointer = nullptr;
+  const uint8_t* bitmap_pointer = nullptr;
+  const uint8_t* methods_pointer = nullptr;
   if (type != kOatClassNoneCompiled) {
     if (type == kOatClassSomeCompiled) {
       bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
@@ -568,26 +573,26 @@
 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
   const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
   if (oat_method_offsets == nullptr) {
-    return OatMethod(nullptr, 0, 0);
+    return OatMethod(nullptr, 0);
   }
   if (oat_file_->IsExecutable() ||
       Runtime::Current() == nullptr ||        // This case applies for oatdump.
       Runtime::Current()->IsCompiler()) {
-    return OatMethod(
-        oat_file_->Begin(),
-        oat_method_offsets->code_offset_,
-        oat_method_offsets->gc_map_offset_);
+    return OatMethod(oat_file_->Begin(), oat_method_offsets->code_offset_);
   } else {
     // We aren't allowed to use the compiled code. We just force it down the interpreted version.
-    return OatMethod(oat_file_->Begin(), 0, 0);
+    return OatMethod(oat_file_->Begin(), 0);
   }
 }
 
 void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const {
   CHECK(method != NULL);
-  method->SetEntryPointFromPortableCompiledCode(GetPortableCode());
   method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
-  method->SetNativeGcMap(GetNativeGcMap());  // Used by native methods in work around JNI mode.
+}
+
+bool OatFile::IsPic() const {
+  return GetOatHeader().IsPic();
+  // TODO: Check against oat_patches. b/18144996
 }
 
 }  // namespace art
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index b9d5702..6ae3c3e 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -48,7 +48,8 @@
   // optionally be used to request where the file should be loaded.
   static OatFile* Open(const std::string& filename,
                        const std::string& location,
-                       byte* requested_base,
+                       uint8_t* requested_base,
+                       uint8_t* oat_file_begin,
                        bool executable,
                        std::string* error_msg);
 
@@ -72,6 +73,8 @@
     return is_executable_;
   }
 
+  bool IsPic() const;
+
   ElfFile* GetElfFile() const {
     CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
         << "Cannot get an elf file from " << GetLocation();
@@ -93,33 +96,9 @@
     uint32_t GetCodeOffset() const {
       return code_offset_;
     }
-    uint32_t GetNativeGcMapOffset() const {
-      return native_gc_map_offset_;
-    }
-
-    const void* GetPortableCode() const {
-      // TODO: encode whether code is portable/quick in flags within OatMethod.
-      if (kUsePortableCompiler) {
-        return GetOatPointer<const void*>(code_offset_);
-      } else {
-        return nullptr;
-      }
-    }
 
     const void* GetQuickCode() const {
-      if (kUsePortableCompiler) {
-        return nullptr;
-      } else {
-        return GetOatPointer<const void*>(code_offset_);
-      }
-    }
-
-    // Returns 0.
-    uint32_t GetPortableCodeSize() const {
-      // TODO: With Quick, we store the size before the code. With Portable, the code is in a .o
-      // file we don't manage ourselves. ELF symbols do have a concept of size, so we could capture
-      // that and store it somewhere, such as the OatMethod.
-      return 0;
+      return GetOatPointer<const void*>(code_offset_);
     }
 
     // Returns size of quick code.
@@ -131,10 +110,6 @@
     const OatQuickMethodHeader* GetOatQuickMethodHeader() const;
     uint32_t GetOatQuickMethodHeaderOffset() const;
 
-    const uint8_t* GetNativeGcMap() const {
-      return GetOatPointer<const uint8_t*>(native_gc_map_offset_);
-    }
-
     size_t GetFrameSizeInBytes() const;
     uint32_t GetCoreSpillMask() const;
     uint32_t GetFpSpillMask() const;
@@ -147,18 +122,20 @@
     uint32_t GetVmapTableOffset() const;
     uint32_t GetVmapTableOffsetOffset() const;
 
+    const uint8_t* GetGcMap() const;
+    uint32_t GetGcMapOffset() const;
+    uint32_t GetGcMapOffsetOffset() const;
+
     // Create an OatMethod with offsets relative to the given base address
-    OatMethod(const byte* base, const uint32_t code_offset, const uint32_t gc_map_offset)
-      : begin_(base),
-        code_offset_(code_offset),
-        native_gc_map_offset_(gc_map_offset) {
+    OatMethod(const uint8_t* base, const uint32_t code_offset)
+        : begin_(base), code_offset_(code_offset) {
     }
     ~OatMethod() {}
 
     // A representation of an invalid OatMethod, used when an OatMethod or OatClass can't be found.
     // See ClassLinker::FindOatMethodFor.
     static const OatMethod Invalid() {
-      return OatMethod(nullptr, -1, -1);
+      return OatMethod(nullptr, -1);
     }
 
    private:
@@ -170,10 +147,8 @@
       return reinterpret_cast<T>(begin_ + offset);
     }
 
-    const byte* const begin_;
-
+    const uint8_t* const begin_;
     const uint32_t code_offset_;
-    const uint32_t native_gc_map_offset_;
 
     friend class OatClass;
   };
@@ -235,7 +210,7 @@
   class OatDexFile {
    public:
     // Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
-    const DexFile* OpenDexFile(std::string* error_msg) const;
+    std::unique_ptr<const DexFile> OpenDexFile(std::string* error_msg) const;
 
     const OatFile* GetOatFile() const {
       return oat_file_;
@@ -272,14 +247,14 @@
                const std::string& dex_file_location,
                const std::string& canonical_dex_file_location,
                uint32_t dex_file_checksum,
-               const byte* dex_file_pointer,
+               const uint8_t* dex_file_pointer,
                const uint32_t* oat_class_offsets_pointer);
 
     const OatFile* const oat_file_;
     const std::string dex_file_location_;
     const std::string canonical_dex_file_location_;
     const uint32_t dex_file_location_checksum_;
-    const byte* const dex_file_pointer_;
+    const uint8_t* const dex_file_pointer_;
     const uint32_t* const oat_class_offsets_pointer_;
 
     friend class OatFile;
@@ -299,27 +274,30 @@
     return End() - Begin();
   }
 
-  const byte* Begin() const;
-  const byte* End() const;
+  const uint8_t* Begin() const;
+  const uint8_t* End() const;
 
  private:
   static void CheckLocation(const std::string& location);
 
   static OatFile* OpenDlopen(const std::string& elf_filename,
                              const std::string& location,
-                             byte* requested_base,
+                             uint8_t* requested_base,
                              std::string* error_msg);
 
   static OatFile* OpenElfFile(File* file,
                               const std::string& location,
-                              byte* requested_base,
+                              uint8_t* requested_base,
+                              uint8_t* oat_file_begin,  // Override base if not null
                               bool writable,
                               bool executable,
                               std::string* error_msg);
 
   explicit OatFile(const std::string& filename, bool executable);
-  bool Dlopen(const std::string& elf_filename, byte* requested_base, std::string* error_msg);
-  bool ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable,
+  bool Dlopen(const std::string& elf_filename, uint8_t* requested_base, std::string* error_msg);
+  bool ElfFileOpen(File* file, uint8_t* requested_base,
+                   uint8_t* oat_file_begin,  // Override where the file is loaded to if not null
+                   bool writable, bool executable,
                    std::string* error_msg);
   bool Setup(std::string* error_msg);
 
@@ -329,10 +307,10 @@
   const std::string location_;
 
   // Pointer to OatHeader.
-  const byte* begin_;
+  const uint8_t* begin_;
 
   // Pointer to end of oat region for bounds checking.
-  const byte* end_;
+  const uint8_t* end_;
 
   // Was this oat_file loaded executable?
   const bool is_executable_;
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 592deed..cf81cc5 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -35,34 +35,10 @@
 }  // namespace mirror
 class StackVisitor;
 
-enum RootType {
-  kRootUnknown = 0,
-  kRootJNIGlobal,
-  kRootJNILocal,
-  kRootJavaFrame,
-  kRootNativeStack,
-  kRootStickyClass,
-  kRootThreadBlock,
-  kRootMonitorUsed,
-  kRootThreadObject,
-  kRootInternedString,
-  kRootDebugger,
-  kRootVMInternal,
-  kRootJNIMonitor,
-};
-std::ostream& operator<<(std::ostream& os, const RootType& root_type);
-
-// Returns the new address of the object, returns root if it has not moved. tid and root_type are
-// only used by hprof.
-typedef void (RootCallback)(mirror::Object** root, void* arg, uint32_t thread_id,
-    RootType root_type);
 // A callback for visiting an object in the heap.
 typedef void (ObjectCallback)(mirror::Object* obj, void* arg);
 // A callback used for marking an object, returns the new address of the object if the object moved.
 typedef mirror::Object* (MarkObjectCallback)(mirror::Object* obj, void* arg) WARN_UNUSED;
-// A callback for verifying roots.
-typedef void (VerifyRootCallback)(const mirror::Object* root, void* arg, size_t vreg,
-    const StackVisitor* visitor, RootType root_type);
 
 typedef void (MarkHeapReferenceCallback)(mirror::HeapReference<mirror::Object>* ref, void* arg);
 typedef void (DelayReferenceReferentCallback)(mirror::Class* klass, mirror::Reference* ref, void* arg);
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..efc4a71 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
@@ -32,7 +34,6 @@
 
 ParsedOptions::ParsedOptions()
     :
-    boot_class_path_(nullptr),
     check_jni_(kIsDebugBuild),                      // -Xcheck:jni is off by default for regular
                                                     // builds but on by default in debug builds.
     force_copy_(false),
@@ -103,11 +104,7 @@
     profile_clock_source_(kDefaultTraceClockSource),
     verify_(true),
     image_isa_(kRuntimeISA),
-    use_homogeneous_space_compaction_for_oom_(false),  // If we are using homogeneous space
-                                                       // compaction then default background
-                                                       // compaction to off since homogeneous
-                                                       // space compactions when we transition
-                                                       // to not jank perceptible.
+    use_homogeneous_space_compaction_for_oom_(true),  // Enable hspace compaction on OOM by default.
     min_interval_homogeneous_space_compaction_by_oom_(MsToNs(100 * 1000))  // 100s.
     {}
 
@@ -205,7 +202,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) {
@@ -290,6 +287,9 @@
     } else if (StartsWith(option, "-Xbootclasspath:")) {
       boot_class_path_string_ = option.substr(strlen("-Xbootclasspath:")).data();
       LOG(INFO) << "setting boot class path to " << boot_class_path_string_;
+    } else if (StartsWith(option, "-Xbootclasspath-locations:")) {
+      boot_class_path_locations_string_ = option.substr(
+          strlen("-Xbootclasspath-locations:")).data();
     } else if (option == "-classpath" || option == "-cp") {
       // TODO: support -Djava.class.path
       i++;
@@ -299,9 +299,6 @@
       }
       const StringPiece& value = options[i].first;
       class_path_string_ = value.data();
-    } else if (option == "bootclasspath") {
-      boot_class_path_
-          = reinterpret_cast<const std::vector<const DexFile*>*>(options[i].second);
     } else if (StartsWith(option, "-Ximage:")) {
       if (!ParseStringAfterChar(option, ':', &image_)) {
         return false;
@@ -416,6 +413,12 @@
       use_homogeneous_space_compaction_for_oom_ = true;
     } else if (option == "-XX:DisableHSpaceCompactForOOM") {
       use_homogeneous_space_compaction_for_oom_ = false;
+    } else if (StartsWith(option, "-XX:HspaceCompactForOOMMinIntervalMs=")) {
+      unsigned int value;
+      if (!ParseUnsignedInteger(option, '=', &value)) {
+        return false;
+      }
+      min_interval_homogeneous_space_compaction_by_oom_ = MsToNs(value);
     } else if (StartsWith(option, "-D")) {
       properties_.push_back(option.substr(strlen("-D")));
     } else if (StartsWith(option, "-Xjnitrace:")) {
@@ -501,42 +504,39 @@
       is_explicit_gc_disabled_ = true;
     } else if (StartsWith(option, "-verbose:")) {
       std::vector<std::string> verbose_options;
-      Split(option.substr(strlen("-verbose:")), ',', verbose_options);
-      for (size_t i = 0; i < verbose_options.size(); ++i) {
-        if (verbose_options[i] == "class") {
+      Split(option.substr(strlen("-verbose:")), ',', &verbose_options);
+      for (size_t j = 0; j < verbose_options.size(); ++j) {
+        if (verbose_options[j] == "class") {
           gLogVerbosity.class_linker = true;
-        } else if (verbose_options[i] == "compiler") {
+        } else if (verbose_options[j] == "compiler") {
           gLogVerbosity.compiler = true;
-        } else if (verbose_options[i] == "gc") {
+        } else if (verbose_options[j] == "gc") {
           gLogVerbosity.gc = true;
-        } else if (verbose_options[i] == "heap") {
+        } else if (verbose_options[j] == "heap") {
           gLogVerbosity.heap = true;
-        } else if (verbose_options[i] == "jdwp") {
+        } else if (verbose_options[j] == "jdwp") {
           gLogVerbosity.jdwp = true;
-        } else if (verbose_options[i] == "jni") {
+        } else if (verbose_options[j] == "jni") {
           gLogVerbosity.jni = true;
-        } else if (verbose_options[i] == "monitor") {
+        } else if (verbose_options[j] == "monitor") {
           gLogVerbosity.monitor = true;
-        } else if (verbose_options[i] == "profiler") {
+        } else if (verbose_options[j] == "profiler") {
           gLogVerbosity.profiler = true;
-        } else if (verbose_options[i] == "signals") {
+        } else if (verbose_options[j] == "signals") {
           gLogVerbosity.signals = true;
-        } else if (verbose_options[i] == "startup") {
+        } else if (verbose_options[j] == "startup") {
           gLogVerbosity.startup = true;
-        } else if (verbose_options[i] == "third-party-jni") {
+        } else if (verbose_options[j] == "third-party-jni") {
           gLogVerbosity.third_party_jni = true;
-        } else if (verbose_options[i] == "threads") {
+        } else if (verbose_options[j] == "threads") {
           gLogVerbosity.threads = true;
-        } else if (verbose_options[i] == "verifier") {
+        } else if (verbose_options[j] == "verifier") {
           gLogVerbosity.verifier = true;
         } else {
-          Usage("Unknown -verbose option %s\n", verbose_options[i].c_str());
+          Usage("Unknown -verbose option %s\n", verbose_options[j].c_str());
           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;
@@ -696,11 +696,16 @@
       return false;
     }
   }
-  // If not set, background collector type defaults to homogeneous compaction
-  // if not low memory mode, semispace otherwise.
+  // If not set, background collector type defaults to homogeneous compaction.
+  // If foreground is GSS, use GSS as background collector.
+  // If not low memory mode, semispace otherwise.
   if (background_collector_type_ == gc::kCollectorTypeNone) {
-    background_collector_type_ = low_memory_mode_ ?
-        gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact;
+    if (collector_type_ != gc::kCollectorTypeGSS) {
+      background_collector_type_ = low_memory_mode_ ?
+          gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact;
+    } else {
+      background_collector_type_ = collector_type_;
+    }
   }
 
   // If a reference to the dalvik core.jar snuck in, replace it with
@@ -720,6 +725,24 @@
     boot_class_path_string_.replace(core_jar_pos, core_jar.size(), core_libart_jar);
   }
 
+  if (!boot_class_path_locations_string_.empty()) {
+    std::vector<std::string> files;
+    Split(boot_class_path_string_, ':', &files);
+
+    std::vector<std::string> locations;
+    Split(boot_class_path_locations_string_, ':', &locations);
+
+    if (files.size() != locations.size()) {
+      Usage("The number of boot class path files does not match"
+          " the number of boot class path locations given\n"
+          "  boot class path files     (%zu): %s\n"
+          "  boot class path locations (%zu): %s\n",
+          files.size(), boot_class_path_string_.c_str(),
+          locations.size(), boot_class_path_locations_string_.c_str());
+      return false;
+    }
+  }
+
   if (compiler_callbacks_ == nullptr && image_.empty()) {
     image_ += GetAndroidRoot();
     image_ += "/framework/boot.art";
@@ -727,9 +750,6 @@
   if (heap_growth_limit_ == 0) {
     heap_growth_limit_ = heap_maximum_size_;
   }
-  if (background_collector_type_ == gc::kCollectorTypeNone) {
-    background_collector_type_ = collector_type_;
-  }
   return true;
 }  // NOLINT(readability/fn_size)
 
@@ -742,7 +762,7 @@
 }
 
 void ParsedOptions::UsageMessageV(FILE* stream, const char* fmt, va_list ap) {
-  hook_vfprintf_(stderr, fmt, ap);
+  hook_vfprintf_(stream, fmt, ap);
 }
 
 void ParsedOptions::UsageMessage(FILE* stream, const char* fmt, ...) {
@@ -807,6 +827,8 @@
   UsageMessage(stream, "  -Xgc:[no]postverify_rosalloc\n");
   UsageMessage(stream, "  -Xgc:[no]presweepingverify\n");
   UsageMessage(stream, "  -Ximage:filename\n");
+  UsageMessage(stream, "  -Xbootclasspath-locations:bootclasspath\n"
+      "     (override the dex locations of the -Xbootclasspath files)\n");
   UsageMessage(stream, "  -XX:+DisableExplicitGC\n");
   UsageMessage(stream, "  -XX:ParallelGCThreads=integervalue\n");
   UsageMessage(stream, "  -XX:ConcGCThreads=integervalue\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 26a2f31..c7162b8 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -25,7 +25,7 @@
 #include "globals.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
 #include "profiler_options.h"
 
 namespace art {
@@ -40,8 +40,8 @@
   // returns null if problem parsing and ignore_unrecognized is false
   static ParsedOptions* Create(const RuntimeOptions& options, bool ignore_unrecognized);
 
-  const std::vector<const DexFile*>* boot_class_path_;
   std::string boot_class_path_string_;
+  std::string boot_class_path_locations_string_;
   std::string class_path_string_;
   std::string image_;
   bool check_jni_;
diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc
index 5154d69..61481b1 100644
--- a/runtime/parsed_options_test.cc
+++ b/runtime/parsed_options_test.cc
@@ -64,7 +64,7 @@
   EXPECT_EQ(2048U, parsed->heap_initial_size_);
   EXPECT_EQ(4 * KB, parsed->heap_maximum_size_);
   EXPECT_EQ(1 * MB, parsed->stack_size_);
-  EXPECT_EQ(0.75, parsed->heap_target_utilization_);
+  EXPECT_DOUBLE_EQ(0.75, parsed->heap_target_utilization_);
   EXPECT_TRUE(test_vfprintf == parsed->hook_vfprintf_);
   EXPECT_TRUE(test_exit == parsed->hook_exit_);
   EXPECT_TRUE(test_abort == parsed->hook_abort_);
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index cde4177..b3da134 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"
@@ -42,9 +44,7 @@
 #include "cutils/properties.h"
 #endif
 
-#if !defined(ART_USE_PORTABLE_COMPILER)
 #include "entrypoints/quick/quick_entrypoints.h"
-#endif
 
 namespace art {
 
@@ -95,7 +95,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 +742,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 +757,7 @@
       break;
     }
     std::vector<std::string> info;
-    Split(line, '/', info);
+    Split(line, '/', &info);
     if (info.size() != 3 && info.size() != 4) {
       // Malformed.
       break;
@@ -770,10 +770,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 +819,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 +837,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/profiler_options.h b/runtime/profiler_options.h
index e3ef697..1db2f05 100644
--- a/runtime/profiler_options.h
+++ b/runtime/profiler_options.h
@@ -26,6 +26,7 @@
   kProfilerMethod,          // Method only
   kProfilerBoundedStack,    // Methods with Dex PC on top of the stack
 };
+std::ostream& operator<<(std::ostream& os, const ProfileDataType& rhs);
 
 class ProfilerOptions {
  public:
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 1eded62..3260992 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -18,7 +18,6 @@
 #include <vector>
 
 #include "common_compiler_test.h"
-#include "field_helper.h"
 #include "mirror/art_field-inl.h"
 #include "scoped_thread_state_change.h"
 
@@ -184,21 +183,20 @@
 
   // Test "Class[] interfaces" field.
   MutableHandle<mirror::ArtField> fhandle = hs.NewHandle(static_fields->Get(0));
-  FieldHelper fh(fhandle);
-  EXPECT_EQ("interfaces", std::string(fh.GetField()->GetName()));
-  EXPECT_EQ("[Ljava/lang/Class;", std::string(fh.GetField()->GetTypeDescriptor()));
-  EXPECT_EQ(interfacesFieldClass.Get(), fh.GetType());
-  EXPECT_EQ("L$Proxy1234;", std::string(fh.GetDeclaringClassDescriptor()));
-  EXPECT_FALSE(fh.GetField()->IsPrimitiveType());
+  EXPECT_EQ("interfaces", std::string(fhandle->GetName()));
+  EXPECT_EQ("[Ljava/lang/Class;", std::string(fhandle->GetTypeDescriptor()));
+  EXPECT_EQ(interfacesFieldClass.Get(), fhandle->GetType(true));
+  std::string temp;
+  EXPECT_EQ("L$Proxy1234;", std::string(fhandle->GetDeclaringClass()->GetDescriptor(&temp)));
+  EXPECT_FALSE(fhandle->IsPrimitiveType());
 
   // Test "Class[][] throws" field.
   fhandle.Assign(static_fields->Get(1));
-  FieldHelper fh2(fhandle);
-  EXPECT_EQ("throws", std::string(fh2.GetField()->GetName()));
-  EXPECT_EQ("[[Ljava/lang/Class;", std::string(fh2.GetField()->GetTypeDescriptor()));
-  EXPECT_EQ(throwsFieldClass.Get(), fh2.GetType());
-  EXPECT_EQ("L$Proxy1234;", std::string(fh2.GetDeclaringClassDescriptor()));
-  EXPECT_FALSE(fh2.GetField()->IsPrimitiveType());
+  EXPECT_EQ("throws", std::string(fhandle->GetName()));
+  EXPECT_EQ("[[Ljava/lang/Class;", std::string(fhandle->GetTypeDescriptor()));
+  EXPECT_EQ(throwsFieldClass.Get(), fhandle->GetType(true));
+  EXPECT_EQ("L$Proxy1234;", std::string(fhandle->GetDeclaringClass()->GetDescriptor(&temp)));
+  EXPECT_FALSE(fhandle->IsPrimitiveType());
 }
 
 }  // namespace art
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index d8fc277..d65b2d5 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -15,6 +15,7 @@
  */
 
 #include "inline_method_analyser.h"
+#include "dex_file-inl.h"
 #include "dex_instruction.h"
 #include "dex_instruction-inl.h"
 #include "mirror/art_field.h"
@@ -35,50 +36,38 @@
 
 namespace art {
 
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET),
-               check_iget_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE),
-               check_iget_wide_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT),
-               check_iget_object_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BOOLEAN),
-               check_iget_boolean_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BYTE),
-               check_iget_byte_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_CHAR),
-               check_iget_char_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_SHORT),
-               check_iget_short_type);
-
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT),
-               check_iput_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_WIDE),
-               check_iput_wide_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_OBJECT),
-               check_iput_object_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BOOLEAN),
-               check_iput_boolean_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BYTE),
-               check_iput_byte_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_CHAR),
-               check_iput_char_type);
-COMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_SHORT),
-               check_iput_short_type);
-
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT), check_iget_iput_variant);
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE), check_iget_iput_wide_variant);
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT), check_iget_iput_object_variant);
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN), check_iget_iput_boolean_variant);
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE), check_iget_iput_byte_variant);
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR), check_iget_iput_char_variant);
-COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) ==
-    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), check_iget_iput_short_variant);
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET), "iget type");
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE), "iget_wide type");
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT),
+              "iget_object type");
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BOOLEAN),
+              "iget_boolean type");
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BYTE), "iget_byte type");
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_CHAR), "iget_char type");
+static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_SHORT), "iget_short type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT), "iput type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_WIDE), "iput_wide type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_OBJECT),
+              "iput_object type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BOOLEAN),
+              "iput_boolean type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BYTE), "iput_byte type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_CHAR), "iput_char type");
+static_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_SHORT), "iput_short type");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT), "iget/iput variant");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE), "iget/iput_wide variant");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT), "iget/iput_object variant");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN), "iget/iput_boolean variant");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE), "iget/iput_byte variant");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR), "iget/iput_char variant");
+static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) ==
+    InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant");
 
 // This is used by compiler and debugger. We look into the dex cache for resolved methods and
 // fields. However, in the context of the debugger, not all methods and fields are resolved. Since
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index a2ae397..3463025 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -103,12 +103,13 @@
   kIntrinsicFlagIsObject   = 4,
   // kIntrinsicUnsafePut
   kIntrinsicFlagIsOrdered  = 8,
+
+  // kIntrinsicDoubleCvt, kIntrinsicFloatCvt.
+  kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin,
 };
 
 struct InlineIGetIPutData {
-  // The op_variant below is opcode-Instruction::IGET for IGETs and
-  // opcode-Instruction::IPUT for IPUTs. This is because the runtime
-  // doesn't know the OpSize enumeration.
+  // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
   uint16_t op_variant : 3;
   uint16_t method_is_static : 1;
   uint16_t object_arg : 4;
@@ -118,7 +119,7 @@
   uint32_t is_volatile : 1;
   uint32_t field_offset : 31;
 };
-COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
+static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
 
 struct InlineReturnArgData {
   uint16_t arg;
@@ -127,7 +128,8 @@
   uint16_t reserved : 14;
   uint32_t reserved2;
 };
-COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
+static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
+              "Invalid size of InlineReturnArgData");
 
 struct InlineMethod {
   InlineMethodOpcode opcode;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 2c158ba..3517848 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.
       }
@@ -213,7 +214,7 @@
     Handle<mirror::ArtMethod> h_method(hs.NewHandle(m));
     verifier::MethodVerifier verifier(self_, h_dex_cache->GetDexFile(), h_dex_cache, h_class_loader,
                                       &m->GetClassDef(), code_item, m->GetDexMethodIndex(),
-                                      h_method, m->GetAccessFlags(), false, true, true);
+                                      h_method, m->GetAccessFlags(), false, true, true, true);
     verifier.Verify();
     const std::vector<int32_t> kinds(verifier.DescribeVRegs(dex_pc));
     for (uint16_t reg = 0; reg < num_regs; ++reg) {
@@ -296,10 +297,10 @@
 // Unwinds all instrumentation stack frame prior to catch handler or upcall.
 class InstrumentationStackVisitor : public StackVisitor {
  public:
-  InstrumentationStackVisitor(Thread* self, bool is_deoptimization, size_t frame_depth)
+  InstrumentationStackVisitor(Thread* self, 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_;
 
@@ -332,7 +332,7 @@
 
 void QuickExceptionHandler::UpdateInstrumentationStack() {
   if (method_tracing_active_) {
-    InstrumentationStackVisitor visitor(self_, is_deoptimization_, handler_frame_depth_);
+    InstrumentationStackVisitor visitor(self_, handler_frame_depth_);
     visitor.WalkStack(true);
 
     size_t instrumentation_frames_to_pop = visitor.GetInstrumentationFramesToPop();
diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h
index b93769c..31622de 100644
--- a/runtime/quick_exception_handler.h
+++ b/runtime/quick_exception_handler.h
@@ -32,7 +32,7 @@
 class ThrowLocation;
 class ShadowFrame;
 
-// Manages exception delivery for Quick backend. Not used by Portable backend.
+// Manages exception delivery for Quick backend.
 class QuickExceptionHandler {
  public:
   QuickExceptionHandler(Thread* self, bool is_deoptimization)
@@ -40,6 +40,7 @@
 
   ~QuickExceptionHandler() {
     LOG(FATAL) << "UNREACHABLE";  // Expected to take long jump.
+    UNREACHABLE();
   }
 
   void FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception,
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index fd43d78..0dc31e7 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -27,9 +27,7 @@
 inline MirrorType* ReadBarrier::Barrier(
     mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr) {
   // Unused for now.
-  UNUSED(obj);
-  UNUSED(offset);
-  UNUSED(ref_addr);
+  UNUSED(obj, offset, ref_addr);
   const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
   if (with_read_barrier && kUseBakerReadBarrier) {
     // To be implemented.
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index 01c5070..e454b20 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -72,39 +72,29 @@
 }
 
 struct ObjectComparator {
-  bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2)
+  bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2) const
     // TODO: enable analysis when analysis can work with the STL.
       NO_THREAD_SAFETY_ANALYSIS {
     Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
     mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>();
     mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>();
-    // Ensure null references and cleared jweaks appear at the end.
-    if (obj1 == NULL) {
-      return true;
-    } else if (obj2 == NULL) {
-      return false;
-    }
+    DCHECK(obj1 != nullptr);
+    DCHECK(obj2 != nullptr);
     Runtime* runtime = Runtime::Current();
-    if (runtime->IsClearedJniWeakGlobal(obj1)) {
-      return true;
-    } else if (runtime->IsClearedJniWeakGlobal(obj2)) {
-      return false;
-    }
-
+    DCHECK(!runtime->IsClearedJniWeakGlobal(obj1));
+    DCHECK(!runtime->IsClearedJniWeakGlobal(obj2));
     // Sort by class...
     if (obj1->GetClass() != obj2->GetClass()) {
-      return obj1->GetClass()->IdentityHashCode() < obj2->IdentityHashCode();
-    } else {
-      // ...then by size...
-      size_t count1 = obj1->SizeOf();
-      size_t count2 = obj2->SizeOf();
-      if (count1 != count2) {
-        return count1 < count2;
-      } else {
-        // ...and finally by identity hash code.
-        return obj1->IdentityHashCode() < obj2->IdentityHashCode();
-      }
+      return obj1->GetClass()->IdentityHashCode() < obj2->GetClass()->IdentityHashCode();
     }
+    // ...then by size...
+    const size_t size1 = obj1->SizeOf();
+    const size_t size2 = obj2->SizeOf();
+    if (size1 != size2) {
+      return size1 < size2;
+    }
+    // ...and finally by identity hash code.
+    return obj1->IdentityHashCode() < obj2->IdentityHashCode();
   }
 };
 
@@ -166,16 +156,17 @@
     first = 0;
   }
   os << "  Last " << (count - first) << " entries (of " << count << "):\n";
+  Runtime* runtime = Runtime::Current();
   for (int idx = count - 1; idx >= first; --idx) {
     mirror::Object* ref = entries[idx].Read();
-    if (ref == NULL) {
+    if (ref == nullptr) {
       continue;
     }
-    if (Runtime::Current()->IsClearedJniWeakGlobal(ref)) {
+    if (runtime->IsClearedJniWeakGlobal(ref)) {
       os << StringPrintf("    %5d: cleared jweak\n", idx);
       continue;
     }
-    if (ref->GetClass() == NULL) {
+    if (ref->GetClass() == nullptr) {
       // should only be possible right after a plain dvmMalloc().
       size_t size = ref->SizeOf();
       os << StringPrintf("    %5d: %p (raw) (%zd bytes)\n", idx, ref, size);
@@ -189,7 +180,7 @@
     if (element_count != 0) {
       StringAppendF(&extras, " (%zd elements)", element_count);
     } else if (ref->GetClass()->IsStringClass()) {
-      mirror::String* s = const_cast<mirror::Object*>(ref)->AsString();
+      mirror::String* s = ref->AsString();
       std::string utf8(s->ToModifiedUtf8());
       if (s->GetLength() <= 16) {
         StringAppendF(&extras, " \"%s\"", utf8.c_str());
@@ -200,57 +191,50 @@
     os << StringPrintf("    %5d: ", idx) << ref << " " << className << extras << "\n";
   }
 
-  // Make a copy of the table and sort it.
+  // Make a copy of the table and sort it, only adding non null and not cleared elements.
   Table sorted_entries;
-  for (size_t i = 0; i < entries.size(); ++i) {
-    mirror::Object* entry = entries[i].Read();
-    sorted_entries.push_back(GcRoot<mirror::Object>(entry));
-  }
-  std::sort(sorted_entries.begin(), sorted_entries.end(), ObjectComparator());
-
-  // Remove any uninteresting stuff from the list. The sort moved them all to the end.
-  while (!sorted_entries.empty() && sorted_entries.back().IsNull()) {
-    sorted_entries.pop_back();
-  }
-  while (!sorted_entries.empty() &&
-         Runtime::Current()->IsClearedJniWeakGlobal(
-             sorted_entries.back().Read<kWithoutReadBarrier>())) {
-    sorted_entries.pop_back();
+  for (GcRoot<mirror::Object>& root : entries) {
+    if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) {
+      sorted_entries.push_back(root);
+    }
   }
   if (sorted_entries.empty()) {
     return;
   }
+  std::sort(sorted_entries.begin(), sorted_entries.end(), ObjectComparator());
 
   // Dump a summary of the whole table.
   os << "  Summary:\n";
   size_t equiv = 0;
   size_t identical = 0;
-  for (size_t idx = 1; idx < count; idx++) {
-    mirror::Object* prev = sorted_entries[idx-1].Read<kWithoutReadBarrier>();
-    mirror::Object* current = sorted_entries[idx].Read<kWithoutReadBarrier>();
-    size_t element_count = GetElementCount(prev);
-    if (current == prev) {
-      // Same reference, added more than once.
-      identical++;
-    } else if (current->GetClass() == prev->GetClass() && GetElementCount(current) == element_count) {
-      // Same class / element count, different object.
-      equiv++;
-    } else {
-      // Different class.
-      DumpSummaryLine(os, prev, element_count, identical, equiv);
-      equiv = identical = 0;
+  mirror::Object* prev = nullptr;
+  for (GcRoot<mirror::Object>& root : sorted_entries) {
+    mirror::Object* current = root.Read<kWithoutReadBarrier>();
+    if (prev != nullptr) {
+      const size_t element_count = GetElementCount(prev);
+      if (current == prev) {
+        // Same reference, added more than once.
+        ++identical;
+      } else if (current->GetClass() == prev->GetClass() &&
+          GetElementCount(current) == element_count) {
+        // Same class / element count, different object.
+        ++equiv;
+      } else {
+        // Different class.
+        DumpSummaryLine(os, prev, element_count, identical, equiv);
+        equiv = 0;
+        identical = 0;
+      }
     }
+    prev = current;
   }
   // Handle the last entry.
-  DumpSummaryLine(os, sorted_entries.back().Read<kWithoutReadBarrier>(),
-                  GetElementCount(sorted_entries.back().Read<kWithoutReadBarrier>()),
-                  identical, equiv);
+  DumpSummaryLine(os, prev, GetElementCount(prev), identical, equiv);
 }
 
-void ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, uint32_t tid,
-                                RootType root_type) {
+void ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, const RootInfo& root_info) {
   for (GcRoot<mirror::Object>& root : entries_) {
-    root.VisitRoot(visitor, arg, tid, root_type);
+    root.VisitRoot(visitor, arg, root_info);
   }
 }
 
diff --git a/runtime/reference_table.h b/runtime/reference_table.h
index 6cffa85..22cf1cd 100644
--- a/runtime/reference_table.h
+++ b/runtime/reference_table.h
@@ -49,7 +49,7 @@
 
   void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void VisitRoots(RootCallback* visitor, void* arg, uint32_t tid, RootType root_type);
+  void VisitRoots(RootCallback* visitor, void* arg, const RootInfo& root_info);
 
  private:
   typedef std::vector<GcRoot<mirror::Object>,
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 23f8076..2aeb92d 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -19,8 +19,8 @@
 #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"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -77,12 +77,6 @@
   }
 
   void AppendWide(uint64_t value) {
-    // For ARM and MIPS portable, align wide values to 8 bytes (ArgArray starts at offset of 4).
-#if defined(ART_USE_PORTABLE_COMPILER) && (defined(__arm__) || defined(__mips__))
-    if (num_bytes_ % 8 == 0) {
-      num_bytes_ += 4;
-    }
-#endif
     arg_array_[num_bytes_ / 4] = value;
     arg_array_[(num_bytes_ / 4) + 1] = value >> 32;
     num_bytes_ += 8;
@@ -218,11 +212,11 @@
                      PrettyDescriptor(found_descriptor).c_str()).c_str());
   }
 
-  bool BuildArgArrayFromObjectArray(const ScopedObjectAccessAlreadyRunnable& soa,
-                                    mirror::Object* receiver,
-                                    mirror::ObjectArray<mirror::Object>* args, MethodHelper& mh)
+  bool BuildArgArrayFromObjectArray(mirror::Object* receiver,
+                                    mirror::ObjectArray<mirror::Object>* args,
+                                    Handle<mirror::ArtMethod> h_m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile::TypeList* classes = mh.GetMethod()->GetParameterTypeList();
+    const DexFile::TypeList* classes = h_m->GetParameterTypeList();
     // Set receiver if non-null (method is not static)
     if (receiver != nullptr) {
       Append(receiver);
@@ -231,11 +225,11 @@
       mirror::Object* arg = args->Get(args_offset);
       if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
         mirror::Class* dst_class =
-            mh.GetClassFromTypeIdx(classes->GetTypeItem(args_offset).type_idx_);
+            h_m->GetClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_, true);
         if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
           ThrowIllegalArgumentException(nullptr,
               StringPrintf("method %s argument %zd has type %s, got %s",
-                  PrettyMethod(mh.GetMethod(), false).c_str(),
+                  PrettyMethod(h_m.Get(), false).c_str(),
                   args_offset + 1,  // Humans don't count from 0.
                   PrettyDescriptor(dst_class).c_str(),
                   PrettyTypeOf(arg).c_str()).c_str());
@@ -263,7 +257,7 @@
             } else { \
               ThrowIllegalArgumentException(nullptr, \
                   StringPrintf("method %s argument %zd has type %s, got %s", \
-                      PrettyMethod(mh.GetMethod(), false).c_str(), \
+                      PrettyMethod(h_m.Get(), false).c_str(), \
                       args_offset + 1, \
                       expected, \
                       PrettyTypeOf(arg).c_str()).c_str()); \
@@ -329,6 +323,7 @@
 #ifndef NDEBUG
         default:
           LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
+          UNREACHABLE();
 #endif
       }
 #undef DO_FIRST_ARG
@@ -360,14 +355,13 @@
   if (!m->IsStatic()) {
     offset = 1;
   }
-  // TODO: If args contain object references, it may cause problems
+  // TODO: If args contain object references, it may cause problems.
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
   Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
-  MethodHelper mh(h_m);
   for (uint32_t i = 0; i < num_params; i++) {
     uint16_t type_idx = params->GetTypeItem(i).type_idx_;
-    mirror::Class* param_type = mh.GetClassFromTypeIdx(type_idx);
+    mirror::Class* param_type = h_m->GetClassFromTypeIndex(type_idx, true);
     if (param_type == nullptr) {
       CHECK(self->IsExceptionPending());
       LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
@@ -528,7 +522,7 @@
 }
 
 void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
-                           MethodHelper& mh, JValue* result) {
+                           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.
@@ -536,11 +530,12 @@
     ThrowStackOverflowError(self);
     return;
   }
-
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  uint32_t shorty_len;
+  const char* shorty = shadow_frame->GetMethod()->GetShorty(&shorty_len);
+  ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
   shadow_frame->GetMethod()->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result,
-                                    mh.GetShorty());
+                                    shorty);
 }
 
 jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
@@ -571,7 +566,7 @@
     // Check that the receiver is non-null and an instance of the field's declaring class.
     receiver = soa.Decode<mirror::Object*>(javaReceiver);
     if (!VerifyObjectIsClass(receiver, declaring_class)) {
-      return NULL;
+      return nullptr;
     }
 
     // Find the actual implementation of the virtual method.
@@ -585,10 +580,10 @@
   uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
   uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0;
   if (arg_count != classes_size) {
-    ThrowIllegalArgumentException(NULL,
+    ThrowIllegalArgumentException(nullptr,
                                   StringPrintf("Wrong number of arguments; expected %d, got %d",
                                                classes_size, arg_count).c_str());
-    return NULL;
+    return nullptr;
   }
 
   // If method is not set to be accessible, verify it can be accessed by the caller.
@@ -611,8 +606,8 @@
   const char* shorty = m->GetShorty(&shorty_len);
   ArgArray arg_array(shorty, shorty_len);
   StackHandleScope<1> hs(soa.Self());
-  MethodHelper mh(hs.NewHandle(m));
-  if (!arg_array.BuildArgArrayFromObjectArray(soa, receiver, objects, mh)) {
+  Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
+  if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, h_m)) {
     CHECK(soa.Self()->IsExceptionPending());
     return nullptr;
   }
@@ -627,22 +622,21 @@
     jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
     jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th);
     soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance));
-    return NULL;
+    return nullptr;
   }
 
   // Box if necessary and return.
-  return soa.AddLocalReference<jobject>(BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(),
-                                                     result));
+  return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
 }
 
 bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
-  if (o == NULL) {
-    ThrowNullPointerException(NULL, "null receiver");
+  if (o == nullptr) {
+    ThrowNullPointerException(nullptr, "null receiver");
     return false;
   } else if (!o->InstanceOf(c)) {
     std::string expected_class_name(PrettyDescriptor(c));
     std::string actual_class_name(PrettyTypeOf(o));
-    ThrowIllegalArgumentException(NULL,
+    ThrowIllegalArgumentException(nullptr,
                                   StringPrintf("Expected receiver of type %s, but got %s",
                                                expected_class_name.c_str(),
                                                actual_class_name.c_str()).c_str());
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 23d8e05..1a64871 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -29,7 +29,6 @@
   class Object;
 }  // namespace mirror
 union JValue;
-class MethodHelper;
 class ScopedObjectAccessAlreadyRunnable;
 class ShadowFrame;
 class ThrowLocation;
@@ -65,7 +64,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
-                           MethodHelper& mh, JValue* result)
+                           JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 75211e0..7aefdaa 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -115,8 +115,8 @@
       *receiver = nullptr;
     } else {
       // Ensure class is initialized before allocating object
-      StackHandleScope<1> hs(self);
-      Handle<mirror::Class> h_class(hs.NewHandle(c));
+      StackHandleScope<1> hs2(self);
+      Handle<mirror::Class> h_class(hs2.NewHandle(c));
       bool initialized = class_linker_->EnsureInitialized(self, h_class, true, true);
       CHECK(initialized);
       *receiver = c->AllocObject(self);
@@ -193,19 +193,19 @@
 
     args[0].d = 0.0;
     JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(0.0, result.GetD());
+    EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = -1.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(-1.0, result.GetD());
+    EXPECT_DOUBLE_EQ(-1.0, result.GetD());
 
     args[0].d = DBL_MAX;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(DBL_MAX, result.GetD());
+    EXPECT_DOUBLE_EQ(DBL_MAX, result.GetD());
 
     args[0].d = DBL_MIN;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(DBL_MIN, result.GetD());
+    EXPECT_DOUBLE_EQ(DBL_MIN, result.GetD());
   }
 
   void InvokeSumIntIntMethod(bool is_static) {
@@ -375,27 +375,27 @@
     args[0].d = 0.0;
     args[1].d = 0.0;
     JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(0.0, result.GetD());
+    EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(3.0, result.GetD());
+    EXPECT_DOUBLE_EQ(3.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(-1.0, result.GetD());
+    EXPECT_DOUBLE_EQ(-1.0, result.GetD());
 
     args[0].d = DBL_MAX;
     args[1].d = DBL_MIN;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(1.7976931348623157e308, result.GetD());
+    EXPECT_DOUBLE_EQ(1.7976931348623157e308, result.GetD());
 
     args[0].d = DBL_MAX;
     args[1].d = DBL_MAX;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(INFINITY, result.GetD());
+    EXPECT_DOUBLE_EQ(INFINITY, result.GetD());
   }
 
   void InvokeSumDoubleDoubleDoubleMethod(bool is_static) {
@@ -409,19 +409,19 @@
     args[1].d = 0.0;
     args[2].d = 0.0;
     JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(0.0, result.GetD());
+    EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
     args[2].d = 3.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(6.0, result.GetD());
+    EXPECT_DOUBLE_EQ(6.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
     args[2].d = 3.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(2.0, result.GetD());
+    EXPECT_DOUBLE_EQ(2.0, result.GetD());
   }
 
   void InvokeSumDoubleDoubleDoubleDoubleMethod(bool is_static) {
@@ -436,21 +436,21 @@
     args[2].d = 0.0;
     args[3].d = 0.0;
     JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(0.0, result.GetD());
+    EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
     args[2].d = 3.0;
     args[3].d = 4.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(10.0, result.GetD());
+    EXPECT_DOUBLE_EQ(10.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
     args[2].d = 3.0;
     args[3].d = -4.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(-2.0, result.GetD());
+    EXPECT_DOUBLE_EQ(-2.0, result.GetD());
   }
 
   void InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(bool is_static) {
@@ -466,7 +466,7 @@
     args[3].d = 0.0;
     args[4].d = 0.0;
     JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(0.0, result.GetD());
+    EXPECT_DOUBLE_EQ(0.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = 2.0;
@@ -474,7 +474,7 @@
     args[3].d = 4.0;
     args[4].d = 5.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(15.0, result.GetD());
+    EXPECT_DOUBLE_EQ(15.0, result.GetD());
 
     args[0].d = 1.0;
     args[1].d = -2.0;
@@ -482,7 +482,7 @@
     args[3].d = -4.0;
     args[4].d = 5.0;
     result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
-    EXPECT_EQ(3.0, result.GetD());
+    EXPECT_DOUBLE_EQ(3.0, result.GetD());
   }
 
   JavaVMExt* vm_;
@@ -493,7 +493,6 @@
 };
 
 TEST_F(ReflectionTest, StaticMainMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Main");
   StackHandleScope<1> hs(soa.Self());
@@ -518,122 +517,98 @@
 }
 
 TEST_F(ReflectionTest, StaticNopMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeNopMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticNopMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeNopMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticIdentityByteMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeIdentityByteMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticIdentityByteMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeIdentityByteMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticIdentityIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeIdentityIntMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticIdentityIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeIdentityIntMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticIdentityDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeIdentityDoubleMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticIdentityDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeIdentityDoubleMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumIntIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntIntMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumIntIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntIntMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumIntIntIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntIntIntMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumIntIntIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntIntIntMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumIntIntIntIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntIntIntIntMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumIntIntIntIntIntMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumIntIntIntIntIntMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumDoubleDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleDoubleMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumDoubleDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleDoubleDoubleMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumDoubleDoubleDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(ReflectionTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(true);
 }
 
 TEST_F(ReflectionTest, NonStaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
-  TEST_DISABLED_FOR_PORTABLE();
   InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(false);
 }
 
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index fe05073..cdf8d54 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -59,6 +59,11 @@
   return imt_conflict_method_.Read();
 }
 
+inline mirror::ArtMethod* Runtime::GetImtUnimplementedMethod() {
+  CHECK(!imt_unimplemented_method_.IsNull());
+  return imt_unimplemented_method_.Read();
+}
+
 inline mirror::ObjectArray<mirror::ArtMethod>* Runtime::GetDefaultImt()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(HasDefaultImt());
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 48439b6..9dddf2f 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -37,16 +37,23 @@
 #include "arch/arm/registers_arm.h"
 #include "arch/arm64/quick_method_frame_info_arm64.h"
 #include "arch/arm64/registers_arm64.h"
+#include "arch/instruction_set_features.h"
 #include "arch/mips/quick_method_frame_info_mips.h"
 #include "arch/mips/registers_mips.h"
+#include "arch/mips64/quick_method_frame_info_mips64.h"
+#include "arch/mips64/registers_mips64.h"
 #include "arch/x86/quick_method_frame_info_x86.h"
 #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"
@@ -65,6 +72,31 @@
 #include "mirror/throwable.h"
 #include "monitor.h"
 #include "native_bridge_art_interface.h"
+#include "native/dalvik_system_DexFile.h"
+#include "native/dalvik_system_VMDebug.h"
+#include "native/dalvik_system_VMRuntime.h"
+#include "native/dalvik_system_VMStack.h"
+#include "native/dalvik_system_ZygoteHooks.h"
+#include "native/java_lang_Class.h"
+#include "native/java_lang_DexCache.h"
+#include "native/java_lang_Object.h"
+#include "native/java_lang_ref_FinalizerReference.h"
+#include "native/java_lang_reflect_Array.h"
+#include "native/java_lang_reflect_Constructor.h"
+#include "native/java_lang_reflect_Field.h"
+#include "native/java_lang_reflect_Method.h"
+#include "native/java_lang_reflect_Proxy.h"
+#include "native/java_lang_ref_Reference.h"
+#include "native/java_lang_Runtime.h"
+#include "native/java_lang_String.h"
+#include "native/java_lang_System.h"
+#include "native/java_lang_Thread.h"
+#include "native/java_lang_Throwable.h"
+#include "native/java_lang_VMClassLoader.h"
+#include "native/java_util_concurrent_atomic_AtomicLong.h"
+#include "native/org_apache_harmony_dalvik_ddmc_DdmServer.h"
+#include "native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h"
+#include "native/sun_misc_Unsafe.h"
 #include "parsed_options.h"
 #include "oat_file.h"
 #include "os.h"
@@ -92,10 +124,9 @@
 
 namespace art {
 
-static constexpr bool kEnableJavaStackTraceHandler = true;
-const char* Runtime::kDefaultInstructionSetFeatures =
-    STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES);
-Runtime* Runtime::instance_ = NULL;
+// If a signal isn't handled properly, enable a handler that attempts to dump the Java stack.
+static constexpr bool kEnableJavaStackTraceHandler = false;
+Runtime* Runtime::instance_ = nullptr;
 
 Runtime::Runtime()
     : instruction_set_(kNone),
@@ -144,10 +175,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
@@ -156,6 +192,13 @@
   }
 
   Thread* self = Thread::Current();
+  if (self == nullptr) {
+    CHECK(AttachCurrentThread("Shutdown thread", false, nullptr, false));
+    self = Thread::Current();
+  } else {
+    LOG(WARNING) << "Current thread not detached in Runtime shutdown";
+  }
+
   {
     MutexLock mu(self, *Locks::runtime_shutdown_lock_);
     shutting_down_started_ = true;
@@ -164,14 +207,21 @@
     }
     shutting_down_ = true;
   }
+  // Shutdown and wait for the daemons.
+  CHECK(self != nullptr);
+  if (IsFinishedStarting()) {
+    self->ClearException();
+    self->GetJniEnv()->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
+                                            WellKnownClasses::java_lang_Daemons_stop);
+  }
+  DetachCurrentThread();
+  self = nullptr;
+
   // Shut down background profiler before the runtime exits.
   if (profiler_started_) {
     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 +234,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 +247,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 +285,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 +297,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();
@@ -334,7 +389,7 @@
   return true;
 }
 
-jobject CreateSystemClassLoader() {
+static jobject CreateSystemClassLoader() {
   if (Runtime::Current()->UseCompileTimeClassPath()) {
     return NULL;
   }
@@ -378,9 +433,9 @@
   if (!patchoat_executable_.empty()) {
     return patchoat_executable_;
   }
-  std::string patchoat_executable_(GetAndroidRoot());
-  patchoat_executable_ += (kIsDebugBuild ? "/bin/patchoatd" : "/bin/patchoat");
-  return patchoat_executable_;
+  std::string patchoat_executable(GetAndroidRoot());
+  patchoat_executable += (kIsDebugBuild ? "/bin/patchoatd" : "/bin/patchoat");
+  return patchoat_executable;
 }
 
 std::string Runtime::GetCompilerExecutable() const {
@@ -402,8 +457,18 @@
 
   started_ = true;
 
+  // Use !IsCompiler so that we get test coverage, tests are never the zygote.
+  if (!IsCompiler()) {
+    ScopedObjectAccess soa(self);
+    gc::space::ImageSpace* image_space = heap_->GetImageSpace();
+    if (image_space != nullptr) {
+      Runtime::Current()->GetInternTable()->AddImageStringsToTable(image_space);
+      Runtime::Current()->GetClassLinker()->MoveImageClassesToClassTable();
+    }
+  }
+
   if (!IsImageDex2OatEnabled() || !Runtime::Current()->GetHeap()->HasImageSpace()) {
-    ScopedObjectAccess soa(Thread::Current());
+    ScopedObjectAccess soa(self);
     StackHandleScope<1> hs(soa.Self());
     auto klass(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
     class_linker_->EnsureInitialized(soa.Self(), klass, true, true);
@@ -425,12 +490,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 +573,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.
@@ -559,10 +626,10 @@
   VLOG(startup) << "Runtime::StartDaemonThreads exiting";
 }
 
-static bool OpenDexFilesFromImage(const std::vector<std::string>& dex_filenames,
-                                  const std::string& image_location,
-                                  std::vector<const DexFile*>& dex_files,
+static bool OpenDexFilesFromImage(const std::string& image_location,
+                                  std::vector<std::unique_ptr<const DexFile>>* dex_files,
                                   size_t* failures) {
+  DCHECK(dex_files != nullptr) << "OpenDexFilesFromImage: out-param is NULL";
   std::string system_filename;
   bool has_system = false;
   std::string cache_filename_unused;
@@ -606,11 +673,11 @@
       *failures += 1;
       continue;
     }
-    const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
-    if (dex_file == nullptr) {
+    std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
+    if (dex_file.get() == nullptr) {
       *failures += 1;
     } else {
-      dex_files.push_back(dex_file);
+      dex_files->push_back(std::move(dex_file));
     }
   }
   Runtime::Current()->GetClassLinker()->RegisterOatFile(oat_file.release());
@@ -619,22 +686,24 @@
 
 
 static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+                           const std::vector<std::string>& dex_locations,
                            const std::string& image_location,
-                           std::vector<const DexFile*>& dex_files) {
+                           std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+  DCHECK(dex_files != nullptr) << "OpenDexFiles: out-param is NULL";
   size_t failure_count = 0;
-  if (!image_location.empty() && OpenDexFilesFromImage(dex_filenames, image_location, dex_files,
-                                                       &failure_count)) {
+  if (!image_location.empty() && OpenDexFilesFromImage(image_location, dex_files, &failure_count)) {
     return failure_count;
   }
   failure_count = 0;
   for (size_t i = 0; i < dex_filenames.size(); i++) {
     const char* dex_filename = dex_filenames[i].c_str();
+    const char* dex_location = dex_locations[i].c_str();
     std::string error_msg;
     if (!OS::FileExists(dex_filename)) {
       LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
       continue;
     }
-    if (!DexFile::Open(dex_filename, dex_filename, &error_msg, &dex_files)) {
+    if (!DexFile::Open(dex_filename, dex_location, &error_msg, dex_files)) {
       LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
     }
@@ -645,6 +714,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";
@@ -798,25 +869,41 @@
     if (kIsDebugBuild) {
       GetHeap()->GetImageSpace()->VerifyImageAllocations();
     }
-  } else if (!IsCompiler() || !image_dex2oat_enabled_) {
+    if (boot_class_path_string_.empty()) {
+      // The bootclasspath is not explicitly specified: construct it from the loaded dex files.
+      const std::vector<const DexFile*>& boot_class_path = GetClassLinker()->GetBootClassPath();
+      std::vector<std::string> dex_locations;
+      dex_locations.reserve(boot_class_path.size());
+      for (const DexFile* dex_file : boot_class_path) {
+        dex_locations.push_back(dex_file->GetLocation());
+      }
+      boot_class_path_string_ = Join(dex_locations, ':');
+    }
+  } else {
     std::vector<std::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);
+    Split(boot_class_path_string_, ':', &dex_filenames);
+
+    std::vector<std::string> dex_locations;
+    if (options->boot_class_path_locations_string_.empty()) {
+      dex_locations = dex_filenames;
+    } else {
+      Split(options->boot_class_path_locations_string_, ':', &dex_locations);
+      CHECK_EQ(dex_filenames.size(), dex_locations.size());
+    }
+
+    std::vector<std::unique_ptr<const DexFile>> boot_class_path;
+    OpenDexFiles(dex_filenames, dex_locations, options->image_, &boot_class_path);
+    class_linker_->InitWithoutImage(std::move(boot_class_path));
     // TODO: Should we move the following to InitWithoutImage?
     SetInstructionSet(kRuntimeISA);
     for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
       Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
       if (!HasCalleeSaveMethod(type)) {
-        SetCalleeSaveMethod(CreateCalleeSaveMethod(type), type);
+        SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
       }
     }
-  } else {
-    CHECK(options->boot_class_path_ != nullptr);
-    CHECK_NE(options->boot_class_path_->size(), 0U);
-    class_linker_->InitWithoutImage(*options->boot_class_path_);
   }
+
   CHECK(class_linker_ != nullptr);
 
   // Initialize the special sentinel_ value early.
@@ -844,14 +931,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 +969,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;
@@ -909,10 +995,9 @@
   // Most JNI libraries can just use System.loadLibrary, but libcore can't because it's
   // the library that implements System.loadLibrary!
   {
-    std::string mapped_name(StringPrintf(OS_SHARED_LIB_FORMAT_STR, "javacore"));
     std::string reason;
-    if (!instance_->java_vm_->LoadNativeLibrary(env, mapped_name, nullptr, &reason)) {
-      LOG(FATAL) << "LoadNativeLibrary failed for \"" << mapped_name << "\": " << reason;
+    if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, &reason)) {
+      LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << reason;
     }
   }
 
@@ -953,34 +1038,31 @@
 }
 
 void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
-#define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
-  // Register Throwable first so that registration of other native methods can throw exceptions
-  REGISTER(register_java_lang_Throwable);
-  REGISTER(register_dalvik_system_DexFile);
-  REGISTER(register_dalvik_system_VMDebug);
-  REGISTER(register_dalvik_system_VMRuntime);
-  REGISTER(register_dalvik_system_VMStack);
-  REGISTER(register_dalvik_system_ZygoteHooks);
-  REGISTER(register_java_lang_Class);
-  REGISTER(register_java_lang_DexCache);
-  REGISTER(register_java_lang_Object);
-  REGISTER(register_java_lang_Runtime);
-  REGISTER(register_java_lang_String);
-  REGISTER(register_java_lang_System);
-  REGISTER(register_java_lang_Thread);
-  REGISTER(register_java_lang_VMClassLoader);
-  REGISTER(register_java_lang_ref_FinalizerReference);
-  REGISTER(register_java_lang_ref_Reference);
-  REGISTER(register_java_lang_reflect_Array);
-  REGISTER(register_java_lang_reflect_Constructor);
-  REGISTER(register_java_lang_reflect_Field);
-  REGISTER(register_java_lang_reflect_Method);
-  REGISTER(register_java_lang_reflect_Proxy);
-  REGISTER(register_java_util_concurrent_atomic_AtomicLong);
-  REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmServer);
-  REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmVmInternal);
-  REGISTER(register_sun_misc_Unsafe);
-#undef REGISTER
+  register_dalvik_system_DexFile(env);
+  register_dalvik_system_VMDebug(env);
+  register_dalvik_system_VMRuntime(env);
+  register_dalvik_system_VMStack(env);
+  register_dalvik_system_ZygoteHooks(env);
+  register_java_lang_Class(env);
+  register_java_lang_DexCache(env);
+  register_java_lang_Object(env);
+  register_java_lang_ref_FinalizerReference(env);
+  register_java_lang_reflect_Array(env);
+  register_java_lang_reflect_Constructor(env);
+  register_java_lang_reflect_Field(env);
+  register_java_lang_reflect_Method(env);
+  register_java_lang_reflect_Proxy(env);
+  register_java_lang_ref_Reference(env);
+  register_java_lang_Runtime(env);
+  register_java_lang_String(env);
+  register_java_lang_System(env);
+  register_java_lang_Thread(env);
+  register_java_lang_Throwable(env);
+  register_java_lang_VMClassLoader(env);
+  register_java_util_concurrent_atomic_AtomicLong(env);
+  register_org_apache_harmony_dalvik_ddmc_DdmServer(env);
+  register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(env);
+  register_sun_misc_Unsafe(env);
 }
 
 void Runtime::DumpForSigQuit(std::ostream& os) {
@@ -1139,30 +1221,15 @@
 
 void Runtime::VisitNonThreadRoots(RootCallback* callback, void* arg) {
   java_vm_->VisitRoots(callback, arg);
-  if (!sentinel_.IsNull()) {
-    sentinel_.VisitRoot(callback, arg, 0, kRootVMInternal);
-    DCHECK(!sentinel_.IsNull());
-  }
-  if (!pre_allocated_OutOfMemoryError_.IsNull()) {
-    pre_allocated_OutOfMemoryError_.VisitRoot(callback, arg, 0, kRootVMInternal);
-    DCHECK(!pre_allocated_OutOfMemoryError_.IsNull());
-  }
-  resolution_method_.VisitRoot(callback, arg, 0, kRootVMInternal);
-  DCHECK(!resolution_method_.IsNull());
-  if (!pre_allocated_NoClassDefFoundError_.IsNull()) {
-    pre_allocated_NoClassDefFoundError_.VisitRoot(callback, arg, 0, kRootVMInternal);
-    DCHECK(!pre_allocated_NoClassDefFoundError_.IsNull());
-  }
-  if (HasImtConflictMethod()) {
-    imt_conflict_method_.VisitRoot(callback, arg, 0, kRootVMInternal);
-  }
-  if (HasDefaultImt()) {
-    default_imt_.VisitRoot(callback, arg, 0, kRootVMInternal);
-  }
+  sentinel_.VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
+  pre_allocated_OutOfMemoryError_.VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
+  resolution_method_.VisitRoot(callback, arg, RootInfo(kRootVMInternal));
+  pre_allocated_NoClassDefFoundError_.VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
+  imt_conflict_method_.VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
+  imt_unimplemented_method_.VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
+  default_imt_.VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-    if (!callee_save_methods_[i].IsNull()) {
-      callee_save_methods_[i].VisitRoot(callback, arg, 0, kRootVMInternal);
-    }
+    callee_save_methods_[i].VisitRootIfNonNull(callback, arg, RootInfo(kRootVMInternal));
   }
   verifier::MethodVerifier::VisitStaticRoots(callback, arg);
   {
@@ -1210,11 +1277,9 @@
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
   // When compiling, the code pointer will get set later when the image is loaded.
   if (runtime->IsCompiler()) {
-    method->SetEntryPointFromPortableCompiledCode(nullptr);
     method->SetEntryPointFromQuickCompiledCode(nullptr);
   } else {
-    method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableImtConflictTrampoline());
-    method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickImtConflictTrampoline());
+    method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictStub());
   }
   return method.Get();
 }
@@ -1230,16 +1295,14 @@
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
   // When compiling, the code pointer will get set later when the image is loaded.
   if (runtime->IsCompiler()) {
-    method->SetEntryPointFromPortableCompiledCode(nullptr);
     method->SetEntryPointFromQuickCompiledCode(nullptr);
   } else {
-    method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableResolutionTrampoline());
-    method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickResolutionTrampoline());
+    method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
   }
   return method.Get();
 }
 
-mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(CalleeSaveType type) {
+mirror::ArtMethod* Runtime::CreateCalleeSaveMethod() {
   Thread* self = Thread::Current();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
@@ -1248,7 +1311,6 @@
   method->SetDeclaringClass(mirror::ArtMethod::GetJavaLangReflectArtMethod());
   // TODO: use a special method for callee saves
   method->SetDexMethodIndex(DexFile::kDexNoIndex);
-  method->SetEntryPointFromPortableCompiledCode(nullptr);
   method->SetEntryPointFromQuickCompiledCode(nullptr);
   DCHECK_NE(instruction_set_, kNone);
   return method.Get();
@@ -1278,6 +1340,11 @@
       CalleeSaveType type = static_cast<CalleeSaveType>(i);
       callee_save_method_frame_infos_[i] = mips::MipsCalleeSaveMethodFrameInfo(type);
     }
+  } else if (instruction_set_ == kMips64) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = mips64::Mips64CalleeSaveMethodFrameInfo(type);
+    }
   } else if (instruction_set_ == kX86) {
     for (int i = 0; i != kLastCalleeSaveType; ++i) {
       CalleeSaveType type = static_cast<CalleeSaveType>(i);
@@ -1322,12 +1389,18 @@
 
 void Runtime::AddMethodVerifier(verifier::MethodVerifier* verifier) {
   DCHECK(verifier != nullptr);
+  if (gAborting) {
+    return;
+  }
   MutexLock mu(Thread::Current(), method_verifier_lock_);
   method_verifiers_.insert(verifier);
 }
 
 void Runtime::RemoveMethodVerifier(verifier::MethodVerifier* verifier) {
   DCHECK(verifier != nullptr);
+  if (gAborting) {
+    return;
+  }
   MutexLock mu(Thread::Current(), method_verifier_lock_);
   auto it = method_verifiers_.find(verifier);
   CHECK(it != method_verifiers_.end());
@@ -1451,9 +1524,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 1a6c6e0..d58fe3c 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -26,11 +26,11 @@
 #include <utility>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/allocator.h"
 #include "compiler_callbacks.h"
 #include "gc_root.h"
 #include "instrumentation.h"
-#include "instruction_set.h"
 #include "jobject_comparator.h"
 #include "object_callbacks.h"
 #include "offsets.h"
@@ -55,8 +55,8 @@
   class Throwable;
 }  // namespace mirror
 namespace verifier {
-class MethodVerifier;
-}
+  class MethodVerifier;
+}  // namespace verifier
 class ClassLinker;
 class DexFile;
 class InternTable;
@@ -133,6 +133,10 @@
     return compiler_options_;
   }
 
+  void AddCompilerOption(std::string option) {
+    compiler_options_.push_back(option);
+  }
+
   const std::vector<std::string>& GetImageCompilerOptions() const {
     return image_compiler_options_;
   }
@@ -177,10 +181,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() 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;
@@ -315,6 +316,7 @@
 
   // Returns a special method that calls into a trampoline for runtime imt conflicts.
   mirror::ArtMethod* GetImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::ArtMethod* GetImtUnimplementedMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool HasImtConflictMethod() const {
     return !imt_conflict_method_.IsNull();
@@ -323,6 +325,9 @@
   void SetImtConflictMethod(mirror::ArtMethod* method) {
     imt_conflict_method_ = GcRoot<mirror::ArtMethod>(method);
   }
+  void SetImtUnimplementedMethod(mirror::ArtMethod* method) {
+    imt_unimplemented_method_ = GcRoot<mirror::ArtMethod>(method);
+  }
 
   mirror::ArtMethod* CreateImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -378,8 +383,7 @@
 
   void SetCalleeSaveMethod(mirror::ArtMethod* method, CalleeSaveType type);
 
-  mirror::ArtMethod* CreateCalleeSaveMethod(CalleeSaveType type)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::ArtMethod* CreateCalleeSaveMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   int32_t GetStat(int kind);
 
@@ -421,6 +425,9 @@
       LOCKS_EXCLUDED(method_verifier_lock_);
 
   const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader);
+
+  // The caller is responsible for ensuring the class_path DexFiles remain
+  // valid as long as the Runtime object remains valid.
   void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path);
 
   void StartProfiler(const char* profile_output_filename);
@@ -486,10 +493,6 @@
     return target_sdk_version_;
   }
 
-  static const char* GetDefaultInstructionSetFeatures() {
-    return kDefaultInstructionSetFeatures;
-  }
-
  private:
   static void InitPlatformSignalHandlers();
 
@@ -509,8 +512,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;
@@ -520,6 +521,9 @@
   GcRoot<mirror::Throwable> pre_allocated_NoClassDefFoundError_;
   GcRoot<mirror::ArtMethod> resolution_method_;
   GcRoot<mirror::ArtMethod> imt_conflict_method_;
+  // Unresolved method has the same behavior as the conflict method, it is used by the class linker
+  // for differentiating between unfilled imt slots vs conflict slots in superclasses.
+  GcRoot<mirror::ArtMethod> imt_unimplemented_method_;
   GcRoot<mirror::ObjectArray<mirror::ArtMethod>> default_imt_;
 
   // Special sentinel object used to invalid conditions in JNI (cleared weak references) and
@@ -644,17 +648,20 @@
   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);
 };
+std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
 
 }  // namespace art
 
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..35d944f 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -21,24 +21,37 @@
 #include <sys/utsname.h>
 #include <inttypes.h>
 
+#include <sstream>
+
+#include "base/dumpable.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/mutex.h"
 #include "base/stringprintf.h"
 #include "thread-inl.h"
+#include "thread_list.h"
 #include "utils.h"
 
 namespace art {
 
 static constexpr bool kDumpHeapObjectOnSigsevg = false;
+static constexpr bool kUseSigRTTimeout = true;
 
 struct Backtrace {
-  void Dump(std::ostream& os) {
-    DumpNativeStack(os, GetTid(), "\t");
+ public:
+  explicit Backtrace(void* raw_context) : raw_context_(raw_context) {}
+  void Dump(std::ostream& os) const {
+    DumpNativeStack(os, GetTid(), "\t", nullptr, raw_context_);
   }
+ private:
+  // Stores the context of the signal that was unexpected and will terminate the runtime. The
+  // DumpNativeStack code will take care of casting it to the expected type. This is required
+  // as our signal handler runs on an alternate stack.
+  void* raw_context_;
 };
 
 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 +145,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 +243,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";
@@ -271,11 +286,29 @@
   mcontext_t& context;
 };
 
+// Return the signal number we recognize as timeout. -1 means not active/supported.
+static int GetTimeoutSignal() {
+#if defined(__APPLE__)
+  // Mac does not support realtime signals.
+  UNUSED(kUseSigRTTimeout);
+  return -1;
+#else
+  return kUseSigRTTimeout ? (SIGRTMIN + 2) : -1;
+#endif
+}
+
+static bool IsTimeoutSignal(int signal_number) {
+  return signal_number == GetTimeoutSignal();
+}
+
 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");
+    if (IsTimeoutSignal(signal_number)) {
+      // Ignore a recursive timeout.
+      return;
+    }
     _exit(1);
   }
   handlingUnexpectedSignal = true;
@@ -294,7 +327,7 @@
   pid_t tid = GetTid();
   std::string thread_name(GetThreadName(tid));
   UContext thread_context(raw_context);
-  Backtrace thread_backtrace;
+  Backtrace thread_backtrace(raw_context);
 
   LOG(INTERNAL_FATAL) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
                       << StringPrintf("Fatal signal %d (%s), code %d (%s)",
@@ -309,6 +342,10 @@
                       << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
   Runtime* runtime = Runtime::Current();
   if (runtime != nullptr) {
+    if (IsTimeoutSignal(signal_number)) {
+      // Special timeout signal. Try to dump all threads.
+      runtime->GetThreadList()->DumpForSigQuit(LOG(INTERNAL_FATAL));
+    }
     gc::Heap* heap = runtime->GetHeap();
     LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
     if (kDumpHeapObjectOnSigsevg && heap != nullptr && info != nullptr) {
@@ -363,6 +400,10 @@
   rc += sigaction(SIGSTKFLT, &action, NULL);
 #endif
   rc += sigaction(SIGTRAP, &action, NULL);
+  // Special dump-all timeout.
+  if (GetTimeoutSignal() != -1) {
+    rc += sigaction(GetTimeoutSignal(), &action, NULL);
+  }
   CHECK_EQ(rc, 0);
 }
 
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 336340e..e377542 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -25,10 +25,12 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <sstream>
+
+#include "arch/instruction_set.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "gc/heap.h"
-#include "instruction_set.h"
 #include "os.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
@@ -108,11 +110,17 @@
     PLOG(ERROR) << "Unable to open stack trace file '" << stack_trace_file_ << "'";
     return;
   }
-  std::unique_ptr<File> file(new File(fd, stack_trace_file_));
-  if (!file->WriteFully(s.data(), s.size())) {
-    PLOG(ERROR) << "Failed to write stack traces to '" << stack_trace_file_ << "'";
+  std::unique_ptr<File> file(new File(fd, stack_trace_file_, true));
+  bool success = file->WriteFully(s.data(), s.size());
+  if (success) {
+    success = file->FlushCloseOrErase() == 0;
   } else {
+    file->Erase();
+  }
+  if (success) {
     LOG(INFO) << "Wrote stack traces to '" << stack_trace_file_ << "'";
+  } else {
+    PLOG(ERROR) << "Failed to write stack traces to '" << stack_trace_file_ << "'";
   }
 }
 
@@ -131,7 +139,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 b8b10d2..3165898 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"
@@ -112,6 +113,9 @@
   }
 }
 
+extern "C" mirror::Object* artQuickGetProxyThisObject(StackReference<mirror::ArtMethod>* sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 mirror::Object* StackVisitor::GetThisObject() const {
   mirror::ArtMethod* m = GetMethod();
   if (m->IsStatic()) {
@@ -119,14 +123,21 @@
   } 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);
     }
-  } else if (m->IsOptimized()) {
+  } else if (m->IsProxyMethod()) {
+    if (cur_quick_frame_ != nullptr) {
+      return artQuickGetProxyThisObject(cur_quick_frame_);
+    } else {
+      return cur_shadow_frame_->GetVRegReference(0);
+    }
+  } else if (m->IsOptimized(sizeof(void*))) {
     // TODO: Implement, currently only used for exceptions when jdwp is enabled.
-    LOG(WARNING) << "StackVisitor::GetThisObject is unimplemented with the optimizing compiler";
+    UNIMPLEMENTED(WARNING)
+        << "StackVisitor::GetThisObject is unimplemented with the optimizing compiler";
     return nullptr;
   } else {
     const DexFile::CodeItem* code_item = m->GetCodeItem();
@@ -143,7 +154,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,
@@ -151,9 +162,9 @@
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer();
+    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
     DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
     uint32_t vmap_offset;
     // TODO: IsInContext stops before spotting floating point registers.
@@ -205,9 +216,9 @@
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer();
+    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
     DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
     uint32_t vmap_offset_lo, vmap_offset_hi;
     // TODO: IsInContext stops before spotting floating point registers.
@@ -252,9 +263,9 @@
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer();
+    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
     DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
     uint32_t vmap_offset;
     // TODO: IsInContext stops before spotting floating point registers.
@@ -316,9 +327,9 @@
   if (cur_quick_frame_ != nullptr) {
     DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
     DCHECK(m == GetMethod());
-    const void* code_pointer = m->GetQuickOatCodePointer();
+    const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
     DCHECK(code_pointer != nullptr);
-    const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+    const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
     uint32_t vmap_offset_lo, vmap_offset_hi;
     // TODO: IsInContext stops before spotting floating point registers.
@@ -392,23 +403,23 @@
 }
 
 uintptr_t StackVisitor::GetReturnPc() const {
-  byte* sp = reinterpret_cast<byte*>(GetCurrentQuickFrame());
+  uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
   DCHECK(sp != NULL);
-  byte* 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) {
-  byte* sp = reinterpret_cast<byte*>(GetCurrentQuickFrame());
+  uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
   CHECK(sp != NULL);
-  byte* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
+  uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffset().SizeValue();
   *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
 }
 
 size_t StackVisitor::ComputeNumFrames(Thread* thread) {
   struct NumFramesVisitor : public StackVisitor {
-    explicit NumFramesVisitor(Thread* thread)
-        : StackVisitor(thread, NULL), frames(0) {}
+    explicit NumFramesVisitor(Thread* thread_in)
+        : StackVisitor(thread_in, NULL), frames(0) {}
 
     bool VisitFrame() OVERRIDE {
       frames++;
@@ -459,8 +470,8 @@
 
 void StackVisitor::DescribeStack(Thread* thread) {
   struct DescribeStackVisitor : public StackVisitor {
-    explicit DescribeStackVisitor(Thread* thread)
-        : StackVisitor(thread, NULL) {}
+    explicit DescribeStackVisitor(Thread* thread_in)
+        : StackVisitor(thread_in, NULL) {}
 
     bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation();
@@ -509,7 +520,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 +536,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 +554,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);
-        byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
+        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++;
@@ -574,7 +585,7 @@
           }
         }
         cur_quick_frame_pc_ = return_pc;
-        byte* next_frame = reinterpret_cast<byte*>(cur_quick_frame_) + frame_size;
+        uint8_t* next_frame = reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size;
         cur_quick_frame_ = reinterpret_cast<StackReference<mirror::ArtMethod>*>(next_frame);
         cur_depth_++;
         method = cur_quick_frame_->AsMirrorPtr();
@@ -603,4 +614,11 @@
   }
 }
 
+void JavaFrameRootInfo::Describe(std::ostream& os) const {
+  const StackVisitor* visitor = stack_visitor_;
+  CHECK(visitor != nullptr);
+  os << "Type=" << GetType() << " thread_id=" << GetThreadId() << " location=" <<
+      visitor->DescribeLocation() << " vreg=" << vreg_;
+}
+
 }  // namespace art
diff --git a/runtime/stack.h b/runtime/stack.h
index 44e36c4..233e1c3 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -20,8 +20,9 @@
 #include <stdint.h>
 #include <string>
 
+#include "arch/instruction_set.h"
 #include "dex_file.h"
-#include "instruction_set.h"
+#include "gc_root.h"
 #include "mirror/object_reference.h"
 #include "throw_location.h"
 #include "utils.h"
@@ -53,6 +54,7 @@
   kImpreciseConstant,
   kUndefined,
 };
+std::ostream& operator<<(std::ostream& os, const VRegKind& rhs);
 
 // A reference from the shadow stack to a MirrorType object within the Java heap.
 template<class MirrorType>
@@ -71,8 +73,7 @@
       : mirror::ObjectReference<false, MirrorType>(p) {}
 };
 
-// ShadowFrame has 3 possible layouts:
-//  - portable - a unified array of VRegs and references. Precise references need GC maps.
+// ShadowFrame has 2 possible layouts:
 //  - interpreter - separate VRegs and reference arrays. References are in the reference array.
 //  - JNI - just VRegs, but where every VReg holds a reference.
 class ShadowFrame {
@@ -99,28 +100,11 @@
   ~ShadowFrame() {}
 
   bool HasReferenceArray() const {
-#if defined(ART_USE_PORTABLE_COMPILER)
-    return (number_of_vregs_ & kHasReferenceArray) != 0;
-#else
     return true;
-#endif
   }
 
   uint32_t NumberOfVRegs() const {
-#if defined(ART_USE_PORTABLE_COMPILER)
-    return number_of_vregs_ & ~kHasReferenceArray;
-#else
     return number_of_vregs_;
-#endif
-  }
-
-  void SetNumberOfVRegs(uint32_t number_of_vregs) {
-#if defined(ART_USE_PORTABLE_COMPILER)
-    number_of_vregs_ = number_of_vregs | (number_of_vregs_ & kHasReferenceArray);
-#else
-    UNUSED(number_of_vregs);
-    UNIMPLEMENTED(FATAL) << "Should only be called when portable is enabled";
-#endif
   }
 
   uint32_t GetDexPC() const {
@@ -269,16 +253,6 @@
 
   ThrowLocation GetCurrentLocationForThrow() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetMethod(mirror::ArtMethod* method) {
-#if defined(ART_USE_PORTABLE_COMPILER)
-    DCHECK(method != nullptr);
-    method_ = method;
-#else
-    UNUSED(method);
-    UNIMPLEMENTED(FATAL) << "Should only be called when portable is enabled";
-#endif
-  }
-
   bool Contains(StackReference<mirror::Object>* shadow_frame_entry_obj) const {
     if (HasReferenceArray()) {
       return ((&References()[0] <= shadow_frame_entry_obj) &&
@@ -315,10 +289,6 @@
               uint32_t dex_pc, bool has_reference_array)
       : number_of_vregs_(num_vregs), link_(link), method_(method), dex_pc_(dex_pc) {
     if (has_reference_array) {
-#if defined(ART_USE_PORTABLE_COMPILER)
-      CHECK_LT(num_vregs, static_cast<uint32_t>(kHasReferenceArray));
-      number_of_vregs_ |= kHasReferenceArray;
-#endif
       memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(StackReference<mirror::Object>)));
     } else {
       memset(vregs_, 0, num_vregs * sizeof(uint32_t));
@@ -335,15 +305,7 @@
     return const_cast<StackReference<mirror::Object>*>(const_cast<const ShadowFrame*>(this)->References());
   }
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-  enum ShadowFrameFlag {
-    kHasReferenceArray = 1ul << 31
-  };
-  // TODO: make const in the portable case.
-  uint32_t number_of_vregs_;
-#else
   const uint32_t number_of_vregs_;
-#endif
   // Link to previous shadow frame or NULL.
   ShadowFrame* link_;
   mirror::ArtMethod* method_;
@@ -353,6 +315,19 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(ShadowFrame);
 };
 
+class JavaFrameRootInfo : public RootInfo {
+ public:
+  JavaFrameRootInfo(uint32_t thread_id, const StackVisitor* stack_visitor, size_t vreg)
+     : RootInfo(kRootJavaFrame, thread_id), stack_visitor_(stack_visitor), vreg_(vreg) {
+  }
+  virtual void Describe(std::ostream& os) const OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  const StackVisitor* const stack_visitor_;
+  const size_t vreg_;
+};
+
 // The managed stack is used to record fragments of managed code stacks. Managed code stacks
 // may either be shadow frames or lists of frames using fixed frame sizes. Transition records are
 // necessary for transitions between code using different frame layouts and transitions into native
@@ -360,7 +335,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 +361,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 +378,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 +390,7 @@
   }
 
   void SetTopShadowFrame(ShadowFrame* top) {
-    DCHECK(top_quick_frame_ == NULL);
+    DCHECK(top_quick_frame_ == nullptr);
     top_shadow_frame_ = top;
   }
 
@@ -441,10 +403,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 {
@@ -484,10 +445,10 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Callee saves are held at the top of the frame
     DCHECK(GetMethod() != nullptr);
-    byte* save_addr =
-        reinterpret_cast<byte*>(cur_quick_frame_) + frame_size - ((num + 1) * kPointerSize);
+    uint8_t* save_addr =
+        reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size - ((num + 1) * sizeof(void*));
 #if defined(__i386__) || defined(__x86_64__)
-    save_addr -= kPointerSize;  // account for return address
+    save_addr -= sizeof(void*);  // account for return address
 #endif
     return reinterpret_cast<uintptr_t*>(save_addr);
   }
@@ -557,7 +518,7 @@
                         uint16_t vreg) const {
     int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg, kRuntimeISA);
     DCHECK_EQ(cur_quick_frame, GetCurrentQuickFrame());
-    byte* vreg_addr = reinterpret_cast<byte*>(cur_quick_frame) + offset;
+    uint8_t* vreg_addr = reinterpret_cast<uint8_t*>(cur_quick_frame) + offset;
     return reinterpret_cast<uint32_t*>(vreg_addr);
   }
 
@@ -647,6 +608,7 @@
   }
 
   static int GetOutVROffset(uint16_t out_num, InstructionSet isa) {
+    UNUSED(isa);
     // According to stack model, the first out is above the Method referernce.
     return sizeof(StackReference<mirror::ArtMethod>) + (out_num * sizeof(uint32_t));
   }
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 9b49d31..7cc3e57 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -19,6 +19,7 @@
 
 #include "base/bit_vector.h"
 #include "memory_region.h"
+#include "utils.h"
 
 namespace art {
 
@@ -88,6 +89,7 @@
     kNone,
     kInStack,
     kInRegister,
+    kInFpuRegister,
     kConstant
   };
 
@@ -198,6 +200,11 @@
        && region_.size() == other.region_.size();
   }
 
+  static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) {
+    // On ARM, the stack maps must be 4-byte aligned.
+    return RoundUp(StackMap::kFixedSize + stack_mask_size, 4);
+  }
+
  private:
   static constexpr int kDexPcOffset = 0;
   static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
@@ -261,7 +268,7 @@
   }
 
   size_t StackMapSize() const {
-    return StackMap::kFixedSize + GetStackMaskSize();
+    return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
   }
 
   DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
@@ -285,7 +292,7 @@
       }
     }
     LOG(FATAL) << "Unreachable";
-    return StackMap(MemoryRegion());
+    UNREACHABLE();
   }
 
   StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
@@ -297,7 +304,7 @@
       }
     }
     LOG(FATAL) << "Unreachable";
-    return StackMap(MemoryRegion());
+    UNREACHABLE();
   }
 
  private:
diff --git a/runtime/strutil.h b/runtime/strutil.h
deleted file mode 100644
index c8d39e2..0000000
--- a/runtime/strutil.h
+++ /dev/null
@@ -1,40 +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.
- */
-
-#ifndef ART_RUNTIME_STRUTIL_H_
-#define ART_RUNTIME_STRUTIL_H_
-
-#include <string.h>
-
-namespace art {
-
-// Key comparison function for C strings.
-struct CStringLt {
-  bool operator()(const char* s1, const char* s2) const {
-    return strcmp(s1, s2) < 0;
-  }
-};
-
-// Key equality function for C strings.
-struct CStringEq {
-  bool operator()(const char* s1, const char* s2) const {
-    return strcmp(s1, s2) == 0;
-  }
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_STRUTIL_H_
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 170cec6..7aed8b0 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -69,7 +69,12 @@
   // Cannot use this code to change into Runnable as changing to Runnable should fail if
   // old_state_and_flags.suspend_request is true.
   DCHECK_NE(new_state, kRunnable);
-  DCHECK_EQ(this, Thread::Current());
+  if (kIsDebugBuild && this != Thread::Current()) {
+    std::string name;
+    GetThreadName(name);
+    LOG(FATAL) << "Thread \"" << name << "\"(" << this << " != Thread::Current()="
+               << Thread::Current() << ") changing state to " << new_state;
+  }
   union StateAndFlags old_state_and_flags;
   old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
   tls32_.state_and_flags.as_struct.state = new_state;
@@ -78,12 +83,14 @@
 
 inline void Thread::AssertThreadSuspensionIsAllowable(bool check_locks) const {
   if (kIsDebugBuild) {
-    CHECK_EQ(0u, tls32_.no_thread_suspension) << tlsPtr_.last_no_thread_suspension_cause;
+    if (gAborting == 0) {
+      CHECK_EQ(0u, tls32_.no_thread_suspension) << tlsPtr_.last_no_thread_suspension_cause;
+    }
     if (check_locks) {
       bool bad_mutexes_held = false;
       for (int i = kLockLevelCount - 1; i >= 0; --i) {
         // We expect no locks except the mutator_lock_ or thread list suspend thread lock.
-        if (i != kMutatorLock && i != kThreadListSuspendThreadLock) {
+        if (i != kMutatorLock) {
           BaseMutex* held_mutex = GetHeldMutex(static_cast<LockLevel>(i));
           if (held_mutex != NULL) {
             LOG(ERROR) << "holding \"" << held_mutex->GetName()
@@ -92,7 +99,9 @@
           }
         }
       }
-      CHECK(!bad_mutexes_held);
+      if (gAborting == 0) {
+        CHECK(!bad_mutexes_held);
+      }
     }
   }
 }
@@ -198,9 +207,9 @@
   DCHECK_LE(tlsPtr_.thread_local_alloc_stack_top, tlsPtr_.thread_local_alloc_stack_end);
   if (tlsPtr_.thread_local_alloc_stack_top < tlsPtr_.thread_local_alloc_stack_end) {
     // There's room.
-    DCHECK_LE(reinterpret_cast<byte*>(tlsPtr_.thread_local_alloc_stack_top) +
+    DCHECK_LE(reinterpret_cast<uint8_t*>(tlsPtr_.thread_local_alloc_stack_top) +
                   sizeof(mirror::Object*),
-              reinterpret_cast<byte*>(tlsPtr_.thread_local_alloc_stack_end));
+              reinterpret_cast<uint8_t*>(tlsPtr_.thread_local_alloc_stack_end));
     DCHECK(*tlsPtr_.thread_local_alloc_stack_top == nullptr);
     *tlsPtr_.thread_local_alloc_stack_top = obj;
     ++tlsPtr_.thread_local_alloc_stack_top;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 07657d1..78a8bf8 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"
@@ -89,18 +91,18 @@
 }
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
-                     PortableEntryPoints* ppoints, QuickEntryPoints* qpoints);
+                     QuickEntryPoints* qpoints);
 
 void Thread::InitTlsEntryPoints() {
   // Insert a placeholder so we can easily tell if we call an unimplemented entry point.
   uintptr_t* begin = reinterpret_cast<uintptr_t*>(&tlsPtr_.interpreter_entrypoints);
-  uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(begin) +
-                                                sizeof(tlsPtr_.quick_entrypoints));
+  uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(&tlsPtr_.quick_entrypoints) +
+      sizeof(tlsPtr_.quick_entrypoints));
   for (uintptr_t* it = begin; it != end; ++it) {
     *it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint);
   }
   InitEntryPoints(&tlsPtr_.interpreter_entrypoints, &tlsPtr_.jni_entrypoints,
-                  &tlsPtr_.portable_entrypoints, &tlsPtr_.quick_entrypoints);
+                  &tlsPtr_.quick_entrypoints);
 }
 
 void Thread::ResetQuickAllocEntryPointsForThread() {
@@ -156,7 +158,7 @@
     // Check that if we got here we cannot be shutting down (as shutdown should never have started
     // while threads are being born).
     CHECK(!runtime->IsShuttingDownLocked());
-    self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
+    CHECK(self->Init(runtime->GetThreadList(), runtime->GetJavaVM()));
     Runtime::Current()->EndThreadBirth();
   }
   {
@@ -168,6 +170,9 @@
     self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
     self->tlsPtr_.jpeer = nullptr;
     self->SetThreadName(self->GetThreadName(soa)->ToModifiedUtf8().c_str());
+
+    mirror::ArtField* priorityField = soa.DecodeField(WellKnownClasses::java_lang_Thread_priority);
+    self->SetNativePriority(priorityField->GetInt(self->tlsPtr_.opeer));
     Dbg::PostThreadStart(self);
 
     // Invoke the 'run' method of our java.lang.Thread.
@@ -235,7 +240,7 @@
 }
 
 // Global variable to prevent the compiler optimizing away the page reads for the stack.
-byte dont_optimize_this;
+uint8_t dont_optimize_this;
 
 // Install a protected region in the stack.  This is used to trigger a SIGSEGV if a stack
 // overflow is detected.  It is located right below the stack_begin_.
@@ -249,9 +254,9 @@
 // this by reading every page from the stack bottom (highest address) to the stack top.
 // We then madvise this away.
 void Thread::InstallImplicitProtection() {
-  byte* pregion = tlsPtr_.stack_begin - kStackOverflowProtectedSize;
-  byte* stack_himem = tlsPtr_.stack_end;
-  byte* stack_top = reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(&stack_himem) &
+  uint8_t* pregion = tlsPtr_.stack_begin - kStackOverflowProtectedSize;
+  uint8_t* stack_himem = tlsPtr_.stack_end;
+  uint8_t* stack_top = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(&stack_himem) &
       ~(kPageSize - 1));    // Page containing current top of stack.
 
   // First remove the protection on the protected region as will want to read and
@@ -265,7 +270,7 @@
   // a segv.
 
   // Read every page from the high address to the low.
-  for (byte* p = stack_top; p >= pregion; p -= kPageSize) {
+  for (uint8_t* p = stack_top; p >= pregion; p -= kPageSize) {
     dont_optimize_this = *p;
   }
 
@@ -343,40 +348,46 @@
   }
 }
 
-void Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm) {
+bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm) {
   // This function does all the initialization that must be run by the native thread it applies to.
   // (When we create a new thread from managed code, we allocate the Thread* in Thread::Create so
   // we can handshake with the corresponding native thread when it's ready.) Check this native
   // thread hasn't been through here already...
   CHECK(Thread::Current() == nullptr);
+
+  // Set pthread_self_ ahead of pthread_setspecific, that makes Thread::Current function, this
+  // avoids pthread_self_ ever being invalid when discovered from Thread::Current().
+  tlsPtr_.pthread_self = pthread_self();
+  CHECK(is_started_);
+
   SetUpAlternateSignalStack();
+  if (!InitStackHwm()) {
+    return false;
+  }
   InitCpu();
   InitTlsEntryPoints();
   RemoveSuspendTrigger();
   InitCardTable();
   InitTid();
-  // Set pthread_self_ ahead of pthread_setspecific, that makes Thread::Current function, this
-  // avoids pthread_self_ ever being invalid when discovered from Thread::Current().
-  tlsPtr_.pthread_self = pthread_self();
-  CHECK(is_started_);
+
   CHECK_PTHREAD_CALL(pthread_setspecific, (Thread::pthread_key_self_, this), "attach self");
   DCHECK_EQ(Thread::Current(), this);
 
   tls32_.thin_lock_thread_id = thread_list->AllocThreadId(this);
-  InitStackHwm();
 
   tlsPtr_.jni_env = new JNIEnvExt(this, java_vm);
   thread_list->Register(this);
+  return true;
 }
 
 Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group,
                        bool create_peer) {
-  Thread* self;
   Runtime* runtime = Runtime::Current();
   if (runtime == nullptr) {
     LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name;
     return nullptr;
   }
+  Thread* self;
   {
     MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
     if (runtime->IsShuttingDownLocked()) {
@@ -385,8 +396,12 @@
     } else {
       Runtime::Current()->StartThreadBirth();
       self = new Thread(as_daemon);
-      self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
+      bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
       Runtime::Current()->EndThreadBirth();
+      if (!init_success) {
+        delete self;
+        return nullptr;
+      }
     }
   }
 
@@ -409,6 +424,11 @@
     }
   }
 
+  {
+    ScopedObjectAccess soa(self);
+    Dbg::PostThreadStart(self);
+  }
+
   return self;
 }
 
@@ -421,6 +441,11 @@
     thread_group = runtime->GetMainThreadGroup();
   }
   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF(name));
+  // Add missing null check in case of OOM b/18297817
+  if (name != nullptr && thread_name.get() == nullptr) {
+    CHECK(IsExceptionPending());
+    return;
+  }
   jint thread_priority = GetNativePriority();
   jboolean thread_is_daemon = as_daemon;
 
@@ -484,19 +509,13 @@
   Dbg::DdmSendThreadNotification(this, CHUNK_TYPE("THNM"));
 }
 
-void Thread::InitStackHwm() {
+bool Thread::InitStackHwm() {
   void* read_stack_base;
   size_t read_stack_size;
   size_t read_guard_size;
   GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size);
 
-  // This is included in the SIGQUIT output, but it's useful here for thread debugging.
-  VLOG(threads) << StringPrintf("Native stack is at %p (%s with %s guard)",
-                                read_stack_base,
-                                PrettySize(read_stack_size).c_str(),
-                                PrettySize(read_guard_size).c_str());
-
-  tlsPtr_.stack_begin = reinterpret_cast<byte*>(read_stack_base);
+  tlsPtr_.stack_begin = reinterpret_cast<uint8_t*>(read_stack_base);
   tlsPtr_.stack_size = read_stack_size;
 
   // The minimum stack size we can cope with is the overflow reserved bytes (typically
@@ -506,10 +525,18 @@
   uint32_t min_stack = GetStackOverflowReservedBytes(kRuntimeISA) + kStackOverflowProtectedSize
     + 4 * KB;
   if (read_stack_size <= min_stack) {
-    LOG(FATAL) << "Attempt to attach a thread with a too-small stack (" << read_stack_size
-               << " bytes)";
+    // Note, as we know the stack is small, avoid operations that could use a lot of stack.
+    LogMessage::LogLineLowStack(__PRETTY_FUNCTION__, __LINE__, ERROR,
+                                "Attempt to attach a thread with a too-small stack");
+    return false;
   }
 
+  // This is included in the SIGQUIT output, but it's useful here for thread debugging.
+  VLOG(threads) << StringPrintf("Native stack is at %p (%s with %s guard)",
+                                read_stack_base,
+                                PrettySize(read_stack_size).c_str(),
+                                PrettySize(read_guard_size).c_str());
+
   // Set stack_end_ to the bottom of the stack saving space of stack overflows
 
   Runtime* runtime = Runtime::Current();
@@ -532,6 +559,8 @@
   // Sanity check.
   int stack_variable;
   CHECK_GT(&stack_variable, reinterpret_cast<void*>(tlsPtr_.stack_end));
+
+  return true;
 }
 
 void Thread::ShortDump(std::ostream& os) const {
@@ -563,13 +592,13 @@
 }
 
 uint64_t Thread::GetCpuMicroTime() const {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
   clockid_t cpu_clock_id;
   pthread_getcpuclockid(tlsPtr_.pthread_self, &cpu_clock_id);
   timespec now;
   clock_gettime(cpu_clock_id, &now);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000);
-#else
+#else  // __APPLE__
   UNIMPLEMENTED(WARNING);
   return -1;
 #endif
@@ -830,10 +859,11 @@
 }
 
 struct StackDumpVisitor : public StackVisitor {
-  StackDumpVisitor(std::ostream& os, Thread* thread, Context* context, bool can_allocate)
+  StackDumpVisitor(std::ostream& os_in, Thread* thread_in, Context* context, bool can_allocate_in)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, context), os(os), thread(thread), can_allocate(can_allocate),
-        last_method(nullptr), last_line_number(0), repetition_count(0), frame_count(0) {
+      : StackVisitor(thread_in, context), os(os_in), thread(thread_in),
+        can_allocate(can_allocate_in), last_method(nullptr), last_line_number(0),
+        repetition_count(0), frame_count(0) {
   }
 
   virtual ~StackDumpVisitor() {
@@ -902,7 +932,10 @@
         os << StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)", reinterpret_cast<intptr_t>(o),
                            PrettyTypeOf(o).c_str());
       } else {
-        os << StringPrintf("<0x%08x> (a %s)", o->IdentityHashCode(), PrettyTypeOf(o).c_str());
+        // IdentityHashCode can cause thread suspension, which would invalidate o if it moved. So
+        // we get the pretty type beofre we call IdentityHashCode.
+        const std::string pretty_type(PrettyTypeOf(o));
+        os << StringPrintf("<0x%08x> (a %s)", o->IdentityHashCode(), pretty_type.c_str());
       }
     }
     os << "\n";
@@ -947,10 +980,37 @@
 }
 
 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.
+  // Thread::Current() instead of this in case a thread is dumping the stack of another suspended
+  // thread.
+  StackHandleScope<3> scope(Thread::Current());
+  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 {
@@ -1005,7 +1065,8 @@
   }
 
   // Allocate a TLS slot.
-  CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback), "self key");
+  CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
+                     "self key");
 
   // Double-check the TLS slot allocation.
   if (pthread_getspecific(pthread_key_self_) != nullptr) {
@@ -1090,8 +1151,7 @@
   }
 }
 
-static void MonitorExitVisitor(mirror::Object** object, void* arg, uint32_t /*thread_id*/,
-                               RootType /*root_type*/)
+static void MonitorExitVisitor(mirror::Object** object, void* arg, const RootInfo& /*root_info*/)
     NO_THREAD_SAFETY_ANALYSIS {
   Thread* self = reinterpret_cast<Thread*>(arg);
   mirror::Object* entered_monitor = *object;
@@ -1110,7 +1170,7 @@
 
   if (tlsPtr_.jni_env != nullptr) {
     // On thread detach, all monitors entered with JNI MonitorEnter are automatically exited.
-    tlsPtr_.jni_env->monitors.VisitRoots(MonitorExitVisitor, self, 0, kRootVMInternal);
+    tlsPtr_.jni_env->monitors.VisitRoots(MonitorExitVisitor, self, RootInfo(kRootVMInternal));
     // Release locally held global references which releasing may require the mutator lock.
     if (tlsPtr_.jpeer != nullptr) {
       // If pthread_create fails we don't have a jni env here.
@@ -1153,7 +1213,10 @@
     tlsPtr_.opeer = nullptr;
   }
 
-  Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
+  {
+    ScopedObjectAccess soa(self);
+    Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
+  }
 }
 
 Thread::~Thread() {
@@ -1269,7 +1332,7 @@
       mirror::Object* object = cur->GetReference(j);
       if (object != nullptr) {
         mirror::Object* old_obj = object;
-        visitor(&object, arg, thread_id, kRootNativeStack);
+        visitor(&object, arg, RootInfo(kRootNativeStack, thread_id));
         if (old_obj != object) {
           cur->SetReference(j, object);
         }
@@ -1279,7 +1342,6 @@
 }
 
 mirror::Object* Thread::DecodeJObject(jobject obj) const {
-  Locks::mutator_lock_->AssertSharedHeld(this);
   if (obj == nullptr) {
     return nullptr;
   }
@@ -1786,7 +1848,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")
@@ -1809,16 +1870,6 @@
   JNI_ENTRY_POINT_INFO(pDlsymLookup)
 #undef JNI_ENTRY_POINT_INFO
 
-#define PORTABLE_ENTRY_POINT_INFO(x) \
-    if (PORTABLE_ENTRYPOINT_OFFSET(ptr_size, x).Uint32Value() == offset) { \
-      os << #x; \
-      return; \
-    }
-  PORTABLE_ENTRY_POINT_INFO(pPortableImtConflictTrampoline)
-  PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampoline)
-  PORTABLE_ENTRY_POINT_INFO(pPortableToInterpreterBridge)
-#undef PORTABLE_ENTRY_POINT_INFO
-
 #define QUICK_ENTRY_POINT_INFO(x) \
     if (QUICK_ENTRYPOINT_OFFSET(ptr_size, x).Uint32Value() == offset) { \
       os << #x; \
@@ -1939,6 +1990,7 @@
   exception_handler.UpdateInstrumentationStack();
   exception_handler.DoLongJump();
   LOG(FATAL) << "UNREACHABLE";
+  UNREACHABLE();
 }
 
 Context* Thread::GetLongJumpContext() {
@@ -2045,7 +2097,7 @@
     } else {
       // Java method.
       // Portable path use DexGcMap and store in Method.native_gc_map_.
-      const uint8_t* gc_map = m->GetNativeGcMap();
+      const uint8_t* gc_map = m->GetNativeGcMap(sizeof(void*));
       CHECK(gc_map != nullptr) << PrettyMethod(m);
       verifier::DexPcToReferenceMap dex_gc_map(gc_map);
       uint32_t dex_pc = shadow_frame->GetDexPC();
@@ -2079,10 +2131,10 @@
 
     // Process register map (which native and runtime methods don't have)
     if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
-      if (m->IsOptimized()) {
+      if (m->IsOptimized(sizeof(void*))) {
         Runtime* runtime = Runtime::Current();
-        const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
-        uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
+        const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m, sizeof(void*));
+        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) {
@@ -2100,7 +2152,7 @@
           }
         }
       } else {
-        const uint8_t* native_gc_map = m->GetNativeGcMap();
+        const uint8_t* native_gc_map = m->GetNativeGcMap(sizeof(void*));
         CHECK(native_gc_map != nullptr) << PrettyMethod(m);
         const DexFile::CodeItem* code_item = m->GetCodeItem();
         // Can't be nullptr or how would we compile its instructions?
@@ -2110,15 +2162,14 @@
                                    static_cast<size_t>(code_item->registers_size_));
         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);
+          const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m, sizeof(void*));
+          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);
-          const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+          const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
           QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
           // For all dex registers in the bitmap
-          StackReference<mirror::ArtMethod>* cur_quick_frame = GetCurrentQuickFrame();
           DCHECK(cur_quick_frame != nullptr);
           for (size_t reg = 0; reg < num_regs; ++reg) {
             // Does this register hold a reference?
@@ -2167,8 +2218,8 @@
   RootCallbackVisitor(RootCallback* callback, void* arg, uint32_t tid)
      : callback_(callback), arg_(arg), tid_(tid) {}
 
-  void operator()(mirror::Object** obj, size_t, const StackVisitor*) const {
-    callback_(obj, arg_, tid_, kRootJavaFrame);
+  void operator()(mirror::Object** obj, size_t vreg, const StackVisitor* stack_visitor) const {
+    callback_(obj, arg_, JavaFrameRootInfo(tid_, stack_visitor, vreg));
   }
 
  private:
@@ -2180,23 +2231,24 @@
 void Thread::VisitRoots(RootCallback* visitor, void* arg) {
   uint32_t thread_id = GetThreadId();
   if (tlsPtr_.opeer != nullptr) {
-    visitor(&tlsPtr_.opeer, arg, thread_id, kRootThreadObject);
+    visitor(&tlsPtr_.opeer, arg, RootInfo(kRootThreadObject, thread_id));
   }
   if (tlsPtr_.exception != nullptr && tlsPtr_.exception != GetDeoptimizationException()) {
-    visitor(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), arg, thread_id, kRootNativeStack);
+    visitor(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), arg,
+            RootInfo(kRootNativeStack, thread_id));
   }
   tlsPtr_.throw_location.VisitRoots(visitor, arg);
   if (tlsPtr_.monitor_enter_object != nullptr) {
-    visitor(&tlsPtr_.monitor_enter_object, arg, thread_id, kRootNativeStack);
+    visitor(&tlsPtr_.monitor_enter_object, arg, RootInfo(kRootNativeStack, thread_id));
   }
-  tlsPtr_.jni_env->locals.VisitRoots(visitor, arg, thread_id, kRootJNILocal);
-  tlsPtr_.jni_env->monitors.VisitRoots(visitor, arg, thread_id, kRootJNIMonitor);
+  tlsPtr_.jni_env->locals.VisitRoots(visitor, arg, RootInfo(kRootJNILocal, thread_id));
+  tlsPtr_.jni_env->monitors.VisitRoots(visitor, arg, RootInfo(kRootJNIMonitor, thread_id));
   HandleScopeVisitRoots(visitor, arg, thread_id);
   if (tlsPtr_.debug_invoke_req != nullptr) {
-    tlsPtr_.debug_invoke_req->VisitRoots(visitor, arg, thread_id, kRootDebugger);
+    tlsPtr_.debug_invoke_req->VisitRoots(visitor, arg, RootInfo(kRootDebugger, thread_id));
   }
   if (tlsPtr_.single_step_control != nullptr) {
-    tlsPtr_.single_step_control->VisitRoots(visitor, arg, thread_id, kRootDebugger);
+    tlsPtr_.single_step_control->VisitRoots(visitor, arg, RootInfo(kRootDebugger, thread_id));
   }
   if (tlsPtr_.deoptimization_shadow_frame != nullptr) {
     RootCallbackVisitor visitorToCallback(visitor, arg, thread_id);
@@ -2207,8 +2259,8 @@
     }
   }
   if (tlsPtr_.shadow_frame_under_construction != nullptr) {
-    RootCallbackVisitor visitorToCallback(visitor, arg, thread_id);
-    ReferenceMapVisitor<RootCallbackVisitor> mapper(this, nullptr, visitorToCallback);
+    RootCallbackVisitor visitor_to_callback(visitor, arg, thread_id);
+    ReferenceMapVisitor<RootCallbackVisitor> mapper(this, nullptr, visitor_to_callback);
     for (ShadowFrame* shadow_frame = tlsPtr_.shadow_frame_under_construction;
         shadow_frame != nullptr;
         shadow_frame = shadow_frame->GetLink()) {
@@ -2217,21 +2269,22 @@
   }
   // Visit roots on this thread's stack
   Context* context = GetLongJumpContext();
-  RootCallbackVisitor visitorToCallback(visitor, arg, thread_id);
-  ReferenceMapVisitor<RootCallbackVisitor> mapper(this, context, visitorToCallback);
+  RootCallbackVisitor visitor_to_callback(visitor, arg, thread_id);
+  ReferenceMapVisitor<RootCallbackVisitor> mapper(this, context, visitor_to_callback);
   mapper.WalkStack();
   ReleaseLongJumpContext(context);
   for (instrumentation::InstrumentationStackFrame& frame : *GetInstrumentationStack()) {
     if (frame.this_object_ != nullptr) {
-      visitor(&frame.this_object_, arg, thread_id, kRootJavaFrame);
+      visitor(&frame.this_object_, arg, RootInfo(kRootVMInternal, thread_id));
     }
     DCHECK(frame.method_ != nullptr);
-    visitor(reinterpret_cast<mirror::Object**>(&frame.method_), arg, thread_id, kRootJavaFrame);
+    visitor(reinterpret_cast<mirror::Object**>(&frame.method_), arg,
+            RootInfo(kRootVMInternal, thread_id));
   }
 }
 
-static void VerifyRoot(mirror::Object** root, void* /*arg*/, uint32_t /*thread_id*/,
-                       RootType /*root_type*/) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static void VerifyRoot(mirror::Object** root, void* /*arg*/, const RootInfo& /*root_info*/)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   VerifyObject(*root);
 }
 
@@ -2264,7 +2317,7 @@
   }
 }
 
-void Thread::SetTlab(byte* start, byte* end) {
+void Thread::SetTlab(uint8_t* start, uint8_t* end) {
   DCHECK_LE(start, end);
   tlsPtr_.thread_local_start = start;
   tlsPtr_.thread_local_pos  = tlsPtr_.thread_local_start;
diff --git a/runtime/thread.h b/runtime/thread.h
index 6c427b8..c3a9751 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -25,16 +25,16 @@
 #include <setjmp.h>
 #include <string>
 
+#include "arch/instruction_set.h"
 #include "atomic.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/jni/jni_entrypoints.h"
-#include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "globals.h"
 #include "handle_scope.h"
-#include "instruction_set.h"
+#include "instrumentation.h"
 #include "jvalue.h"
 #include "object_callbacks.h"
 #include "offsets.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) {
@@ -547,12 +549,6 @@
   }
 
   template<size_t pointer_size>
-  static ThreadOffset<pointer_size> PortableEntryPointOffset(size_t port_entrypoint_offset) {
-    return ThreadOffsetFromTlsPtr<pointer_size>(
-        OFFSETOF_MEMBER(tls_ptr_sized_values, portable_entrypoints) + port_entrypoint_offset);
-  }
-
-  template<size_t pointer_size>
   static ThreadOffset<pointer_size> SelfOffset() {
     return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, self));
   }
@@ -584,7 +580,7 @@
     return tlsPtr_.stack_size - (tlsPtr_.stack_end - tlsPtr_.stack_begin);
   }
 
-  byte* GetStackEndForInterpreter(bool implicit_overflow_check) const {
+  uint8_t* GetStackEndForInterpreter(bool implicit_overflow_check) const {
     if (implicit_overflow_check) {
       // The interpreter needs the extra overflow bytes that stack_end does
       // not include.
@@ -594,7 +590,7 @@
     }
   }
 
-  byte* GetStackEnd() const {
+  uint8_t* GetStackEnd() const {
     return tlsPtr_.stack_end;
   }
 
@@ -634,13 +630,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;
   }
@@ -692,7 +681,7 @@
   }
 
   void PushHandleScope(HandleScope* handle_scope) {
-    handle_scope->SetLink(tlsPtr_.top_handle_scope);
+    DCHECK_EQ(handle_scope->GetLink(), tlsPtr_.top_handle_scope);
     tlsPtr_.top_handle_scope = handle_scope;
   }
 
@@ -790,7 +779,7 @@
   size_t TlabSize() const;
   // Doesn't check that there is room.
   mirror::Object* AllocTlab(size_t bytes);
-  void SetTlab(byte* start, byte* end);
+  void SetTlab(uint8_t* start, uint8_t* end);
   bool HasTlab() const;
 
   // Remove the suspend trigger for this thread by making the suspend_trigger_ TLS value
@@ -898,14 +887,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void RemoveFromThreadGroup(ScopedObjectAccess& soa) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void Init(ThreadList*, JavaVMExt*) EXCLUSIVE_LOCKS_REQUIRED(Locks::runtime_shutdown_lock_);
+  bool Init(ThreadList*, JavaVMExt*) EXCLUSIVE_LOCKS_REQUIRED(Locks::runtime_shutdown_lock_);
   void InitCardTable();
   void InitCpu();
   void CleanupCpu();
   void InitTlsEntryPoints();
   void InitTid();
   void InitPthreadKeySelf();
-  void InitStackHwm();
+  bool InitStackHwm();
 
   void SetUpAlternateSignalStack();
   void TearDownAlternateSignalStack();
@@ -932,7 +921,7 @@
     // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47409
     DISALLOW_COPY_AND_ASSIGN(StateAndFlags);
   };
-  COMPILE_ASSERT(sizeof(StateAndFlags) == sizeof(int32_t), weird_state_and_flags_size);
+  static_assert(sizeof(StateAndFlags) == sizeof(int32_t), "Weird state_and_flags size");
 
   static void ThreadExitCallback(void* arg);
 
@@ -968,8 +957,8 @@
     }
 
     union StateAndFlags state_and_flags;
-    COMPILE_ASSERT(sizeof(union StateAndFlags) == sizeof(int32_t),
-                   sizeof_state_and_flags_and_int32_are_different);
+    static_assert(sizeof(union StateAndFlags) == sizeof(int32_t),
+                  "Size of state_and_flags and int32 are different");
 
     // A non-zero value is used to tell the current thread to enter a safe point
     // at the next poll.
@@ -1043,14 +1032,14 @@
     }
 
     // The biased card table, see CardTable for details.
-    byte* card_table;
+    uint8_t* card_table;
 
     // The pending exception or NULL.
     mirror::Throwable* exception;
 
     // The end of this thread's stack. This is the lowest safely-addressable address on the stack.
     // We leave extra space so there's room for the code that throws StackOverflowError.
-    byte* stack_end;
+    uint8_t* stack_end;
 
     // The top of the managed stack often manipulated directly by compiler generated code.
     ManagedStack managed_stack;
@@ -1073,7 +1062,7 @@
     jobject jpeer;
 
     // The "lowest addressable byte" of the stack.
-    byte* stack_begin;
+    uint8_t* stack_begin;
 
     // Size of the stack.
     size_t stack_size;
@@ -1133,13 +1122,12 @@
     // TODO: move this to more of a global offset table model to avoid per-thread duplication.
     InterpreterEntryPoints interpreter_entrypoints;
     JniEntryPoints jni_entrypoints;
-    PortableEntryPoints portable_entrypoints;
     QuickEntryPoints quick_entrypoints;
 
     // Thread-local allocation pointer.
-    byte* thread_local_start;
-    byte* thread_local_pos;
-    byte* thread_local_end;
+    uint8_t* thread_local_start;
+    uint8_t* thread_local_pos;
+    uint8_t* thread_local_end;
     size_t thread_local_objects;
 
     // There are RosAlloc::kNumThreadLocalSizeBrackets thread-local size brackets per thread.
@@ -1194,11 +1182,10 @@
 
  private:
   Thread* const self_;
-  const char* old_cause_;
+  const char* const old_cause_;
 };
 
 std::ostream& operator<<(std::ostream& os, const Thread& thread);
-std::ostream& operator<<(std::ostream& os, const ThreadState& state);
 
 }  // namespace art
 
diff --git a/runtime/thread_android.cc b/runtime/thread_android.cc
index 73a9e54..d5db983 100644
--- a/runtime/thread_android.cc
+++ b/runtime/thread_android.cc
@@ -55,6 +55,13 @@
   int newNice = kNiceValues[newPriority-1];
   pid_t tid = GetTid();
 
+  // TODO: b/18249098 The code below is broken. It uses getpriority() as a proxy for whether a
+  // thread is already in the SP_FOREGROUND cgroup. This is not necessarily true for background
+  // processes, where all threads are in the SP_BACKGROUND cgroup. This means that callers will
+  // have to call setPriority twice to do what they want :
+  //
+  //     Thread.setPriority(Thread.MIN_PRIORITY);  // no-op wrt to cgroups
+  //     Thread.setPriority(Thread.MAX_PRIORITY);  // will actually change cgroups.
   if (newNice >= ANDROID_PRIORITY_BACKGROUND) {
     set_sched_policy(tid, SP_BACKGROUND);
   } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
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 ec5b775..6ec40d4 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -25,6 +25,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <sstream>
+
+#include "base/histogram-inl.h"
 #include "base/mutex.h"
 #include "base/mutex-inl.h"
 #include "base/timing_logger.h"
@@ -34,6 +37,7 @@
 #include "monitor.h"
 #include "scoped_thread_state_change.h"
 #include "thread.h"
+#include "trace.h"
 #include "utils.h"
 #include "well_known_classes.h"
 
@@ -43,7 +47,8 @@
 
 ThreadList::ThreadList()
     : suspend_all_count_(0), debug_suspend_all_count_(0),
-      thread_exit_cond_("thread exit condition variable", *Locks::thread_list_lock_) {
+      thread_exit_cond_("thread exit condition variable", *Locks::thread_list_lock_),
+      suspend_all_historam_("suspend all histogram", 16, 64) {
   CHECK(Monitor::IsValidLockWord(LockWord::FromThinLockId(kMaxThreadId, 1)));
 }
 
@@ -51,7 +56,13 @@
   // Detach the current thread if necessary. If we failed to start, there might not be any threads.
   // We need to detach the current thread here in case there's another thread waiting to join with
   // us.
-  if (Contains(Thread::Current())) {
+  bool contains = false;
+  {
+    Thread* self = Thread::Current();
+    MutexLock mu(self, *Locks::thread_list_lock_);
+    contains = Contains(self);
+  }
+  if (contains) {
     Runtime::Current()->DetachCurrentThread();
   }
 
@@ -88,6 +99,15 @@
 }
 
 void ThreadList::DumpForSigQuit(std::ostream& os) {
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    // Only print if we have samples.
+    if (suspend_all_historam_.SampleSize() > 0) {
+      Histogram<uint64_t>::CumulativeData data;
+      suspend_all_historam_.CreateHistogram(&data);
+      suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data);  // Dump time to suspend.
+    }
+  }
   Dump(os);
   DumpUnattachedThreads(os);
 }
@@ -130,6 +150,10 @@
   closedir(d);
 }
 
+// Dump checkpoint timeout in milliseconds. Larger amount on the host, as dumping will invoke
+// addr2line when available.
+static constexpr uint32_t kDumpWaitTimeout = kIsTargetBuild ? 10000 : 20000;
+
 // A closure used by Thread::Dump.
 class DumpCheckpoint FINAL : public Closure {
  public:
@@ -156,10 +180,11 @@
   void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) {
     Thread* self = Thread::Current();
     ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
-    const uint32_t kWaitTimeoutMs = 10000;
-    bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kWaitTimeoutMs);
+    bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kDumpWaitTimeout);
     if (timed_out) {
-      LOG(kIsDebugBuild ? FATAL : ERROR) << "Unexpected time out during dump checkpoint.";
+      // Avoid a recursive abort.
+      LOG((kIsDebugBuild && (gAborting == 0)) ? FATAL : ERROR)
+          << "Unexpected time out during dump checkpoint.";
     }
   }
 
@@ -199,6 +224,8 @@
   Runtime* runtime = Runtime::Current();
   std::ostringstream ss;
   ss << "Thread suspend timeout\n";
+  Locks::mutator_lock_->Dump(ss);
+  ss << "\n";
   runtime->GetThreadList()->Dump(ss);
   LOG(FATAL) << ss.str();
   exit(0);
@@ -209,7 +236,7 @@
 // individual thread requires polling. delay_us is the requested sleep and total_delay_us
 // accumulates the total time spent sleeping for timeouts. The first sleep is just a yield,
 // subsequently sleeps increase delay_us from 1ms to 500ms by doubling.
-static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us) {
+static void ThreadSuspendSleep(useconds_t* delay_us, useconds_t* total_delay_us) {
   useconds_t new_delay_us = (*delay_us) * 2;
   CHECK_GE(new_delay_us, *delay_us);
   if (new_delay_us < 500000) {  // Don't allow sleeping to be more than 0.5s.
@@ -230,7 +257,7 @@
   Locks::mutator_lock_->AssertNotExclusiveHeld(self);
   Locks::thread_list_lock_->AssertNotHeld(self);
   Locks::thread_suspend_count_lock_->AssertNotHeld(self);
-  if (kDebugLocking) {
+  if (kDebugLocking && gAborting == 0) {
     CHECK_NE(self->GetState(), kRunnable);
   }
 
@@ -274,7 +301,7 @@
       useconds_t total_delay_us = 0;
       do {
         useconds_t delay_us = 100;
-        ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+        ThreadSuspendSleep(&delay_us, &total_delay_us);
       } while (!thread->IsSuspended());
       // Shouldn't need to wait for longer than 1000 microseconds.
       constexpr useconds_t kLongWaitThresholdUS = 1000;
@@ -338,7 +365,7 @@
     VLOG(threads) << "Thread[null] SuspendAll starting...";
   }
   ATRACE_BEGIN("Suspending mutator threads");
-  uint64_t start_time = NanoTime();
+  const uint64_t start_time = NanoTime();
 
   Locks::mutator_lock_->AssertNotHeld(self);
   Locks::thread_list_lock_->AssertNotHeld(self);
@@ -371,9 +398,11 @@
   Locks::mutator_lock_->ExclusiveLock(self);
 #endif
 
-  uint64_t end_time = NanoTime();
-  if (end_time - start_time > kLongThreadSuspendThreshold) {
-    LOG(WARNING) << "Suspending all threads took: " << PrettyDuration(end_time - start_time);
+  const uint64_t end_time = NanoTime();
+  const uint64_t suspend_time = end_time - start_time;
+  suspend_all_historam_.AdjustAndAddValue(suspend_time);
+  if (suspend_time > kLongThreadSuspendThreshold) {
+    LOG(WARNING) << "Suspending all threads took: " << PrettyDuration(suspend_time);
   }
 
   if (kDebugLocking) {
@@ -441,6 +470,9 @@
 }
 
 void ThreadList::Resume(Thread* thread, bool for_debugger) {
+  // This assumes there was an ATRACE_BEGIN when we suspended the thread.
+  ATRACE_END();
+
   Thread* self = Thread::Current();
   DCHECK_NE(thread, self);
   VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") starting..."
@@ -471,17 +503,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();
   }
 }
 
@@ -490,9 +523,9 @@
   static const useconds_t kTimeoutUs = 30 * 1000000;  // 30s.
   useconds_t total_delay_us = 0;
   useconds_t delay_us = 0;
-  bool did_suspend_request = false;
   *timed_out = false;
   Thread* self = Thread::Current();
+  Thread* suspended_thread = nullptr;
   VLOG(threads) << "SuspendThreadByPeer starting";
   while (true) {
     Thread* thread;
@@ -503,24 +536,39 @@
       // than request thread suspension, to avoid potential cycles in threads requesting each other
       // suspend.
       ScopedObjectAccess soa(self);
-      MutexLock mu(self, *Locks::thread_list_lock_);
+      MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
       thread = Thread::FromManagedThread(soa, peer);
       if (thread == nullptr) {
+        if (suspended_thread != nullptr) {
+          MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_);
+          // If we incremented the suspend count but the thread reset its peer, we need to
+          // re-decrement it since it is shutting down and may deadlock the runtime in
+          // ThreadList::WaitForOtherNonDaemonThreadsToExit.
+          suspended_thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
+        }
         ThreadSuspendByPeerWarning(self, WARNING, "No such thread for suspend", peer);
         return nullptr;
       }
       if (!Contains(thread)) {
+        CHECK(suspended_thread == nullptr);
         VLOG(threads) << "SuspendThreadByPeer failed for unattached thread: "
             << reinterpret_cast<void*>(thread);
         return nullptr;
       }
       VLOG(threads) << "SuspendThreadByPeer found thread: " << *thread;
       {
-        MutexLock mu(self, *Locks::thread_suspend_count_lock_);
+        MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_);
         if (request_suspension) {
-          thread->ModifySuspendCount(self, +1, debug_suspension);
+          if (self->GetSuspendCount() > 0) {
+            // We hold the suspend count lock but another thread is trying to suspend us. Its not
+            // safe to try to suspend another thread in case we get a cycle. Start the loop again
+            // which will allow this thread to be suspended.
+            continue;
+          }
+          CHECK(suspended_thread == nullptr);
+          suspended_thread = thread;
+          suspended_thread->ModifySuspendCount(self, +1, debug_suspension);
           request_suspension = false;
-          did_suspend_request = true;
         } else {
           // If the caller isn't requesting suspension, a suspension should have already occurred.
           CHECK_GT(thread->GetSuspendCount(), 0);
@@ -535,12 +583,19 @@
         // done.
         if (thread->IsSuspended()) {
           VLOG(threads) << "SuspendThreadByPeer thread suspended: " << *thread;
+          if (ATRACE_ENABLED()) {
+            std::string name;
+            thread->GetThreadName(name);
+            ATRACE_BEGIN(StringPrintf("SuspendThreadByPeer suspended %s for peer=%p", name.c_str(),
+                                      peer).c_str());
+          }
           return thread;
         }
         if (total_delay_us >= kTimeoutUs) {
           ThreadSuspendByPeerWarning(self, FATAL, "Thread suspension timed out", peer);
-          if (did_suspend_request) {
-            thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
+          if (suspended_thread != nullptr) {
+            CHECK_EQ(suspended_thread, thread);
+            suspended_thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
           }
           *timed_out = true;
           return nullptr;
@@ -549,12 +604,13 @@
       // Release locks and come out of runnable state.
     }
     VLOG(threads) << "SuspendThreadByPeer sleeping to allow thread chance to suspend";
-    ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+    ThreadSuspendSleep(&delay_us, &total_delay_us);
   }
 }
 
-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,
@@ -575,7 +631,7 @@
       // than request thread suspension, to avoid potential cycles in threads requesting each other
       // suspend.
       ScopedObjectAccess soa(self);
-      MutexLock mu(self, *Locks::thread_list_lock_);
+      MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
       Thread* thread = nullptr;
       for (const auto& it : list_) {
         if (it->GetThreadId() == thread_id) {
@@ -593,8 +649,14 @@
       VLOG(threads) << "SuspendThreadByThreadId found thread: " << *thread;
       DCHECK(Contains(thread));
       {
-        MutexLock mu(self, *Locks::thread_suspend_count_lock_);
+        MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_);
         if (suspended_thread == nullptr) {
+          if (self->GetSuspendCount() > 0) {
+            // We hold the suspend count lock but another thread is trying to suspend us. Its not
+            // safe to try to suspend another thread in case we get a cycle. Start the loop again
+            // which will allow this thread to be suspended.
+            continue;
+          }
           thread->ModifySuspendCount(self, +1, debug_suspension);
           suspended_thread = thread;
         } else {
@@ -611,6 +673,12 @@
         // count, or else we've waited and it has self suspended) or is the current thread, we're
         // done.
         if (thread->IsSuspended()) {
+          if (ATRACE_ENABLED()) {
+            std::string name;
+            thread->GetThreadName(name);
+            ATRACE_BEGIN(StringPrintf("SuspendThreadByThreadId suspended %s id=%d",
+                                      name.c_str(), thread_id).c_str());
+          }
           VLOG(threads) << "SuspendThreadByThreadId thread suspended: " << *thread;
           return thread;
         }
@@ -626,7 +694,7 @@
       // Release locks and come out of runnable state.
     }
     VLOG(threads) << "SuspendThreadByThreadId sleeping to allow thread chance to suspend";
-    ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+    ThreadSuspendSleep(&delay_us, &total_delay_us);
   }
 }
 
@@ -649,10 +717,11 @@
   VLOG(threads) << *self << " SuspendAllForDebugger starting...";
 
   {
-    MutexLock mu(self, *Locks::thread_list_lock_);
+    MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
     {
-      MutexLock mu(self, *Locks::thread_suspend_count_lock_);
+      MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_);
       // Update global suspend all state for attaching threads.
+      DCHECK_GE(suspend_all_count_, debug_suspend_all_count_);
       ++suspend_all_count_;
       ++debug_suspend_all_count_;
       // Increment everybody's suspend count (except our own).
@@ -744,6 +813,56 @@
   VLOG(threads) << *self << " self-reviving (debugger)";
 }
 
+void ThreadList::ResumeAllForDebugger() {
+  Thread* self = Thread::Current();
+  Thread* debug_thread = Dbg::GetDebugThread();
+
+  VLOG(threads) << *self << " ResumeAllForDebugger starting...";
+
+  // Threads can't resume if we exclusively hold the mutator lock.
+  Locks::mutator_lock_->AssertNotExclusiveHeld(self);
+
+  {
+    MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
+    {
+      MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_);
+      // Update global suspend all state for attaching threads.
+      DCHECK_GE(suspend_all_count_, debug_suspend_all_count_);
+      if (debug_suspend_all_count_ > 0) {
+        --suspend_all_count_;
+        --debug_suspend_all_count_;
+      } else {
+        // We've been asked to resume all threads without being asked to
+        // suspend them all before. That may happen if a debugger tries
+        // to resume some suspended threads (with suspend count == 1)
+        // at once with a VirtualMachine.Resume command. Let's print a
+        // warning.
+        LOG(WARNING) << "Debugger attempted to resume all threads without "
+                     << "having suspended them all before.";
+      }
+      // Decrement everybody's suspend count (except our own).
+      for (const auto& thread : list_) {
+        if (thread == self || thread == debug_thread) {
+          continue;
+        }
+        if (thread->GetDebugSuspendCount() == 0) {
+          // This thread may have been individually resumed with ThreadReference.Resume.
+          continue;
+        }
+        VLOG(threads) << "requesting thread resume: " << *thread;
+        thread->ModifySuspendCount(self, -1, true);
+      }
+    }
+  }
+
+  {
+    MutexLock mu(self, *Locks::thread_suspend_count_lock_);
+    Thread::resume_cond_->Broadcast(self);
+  }
+
+  VLOG(threads) << *self << " ResumeAllForDebugger complete";
+}
+
 void ThreadList::UndoDebuggerSuspensions() {
   Thread* self = Thread::Current();
 
@@ -869,6 +988,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
@@ -923,28 +1045,6 @@
   }
 }
 
-class VerifyRootWrapperArg {
- public:
-  VerifyRootWrapperArg(VerifyRootCallback* callback, void* arg) : callback_(callback), arg_(arg) {
-  }
-  VerifyRootCallback* const callback_;
-  void* const arg_;
-};
-
-static void VerifyRootWrapperCallback(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
-                                      RootType root_type) {
-  VerifyRootWrapperArg* wrapperArg = reinterpret_cast<VerifyRootWrapperArg*>(arg);
-  wrapperArg->callback_(*root, wrapperArg->arg_, 0, NULL, root_type);
-}
-
-void ThreadList::VerifyRoots(VerifyRootCallback* callback, void* arg) const {
-  VerifyRootWrapperArg wrapper(callback, arg);
-  MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
-  for (const auto& thread : list_) {
-    thread->VisitRoots(VerifyRootWrapperCallback, &wrapper);
-  }
-}
-
 uint32_t ThreadList::AllocThreadId(Thread* self) {
   MutexLock mu(self, *Locks::allocated_thread_ids_lock_);
   for (size_t i = 0; i < allocated_ids_.size(); ++i) {
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 9f47f9f..6751bf5 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -17,7 +17,9 @@
 #ifndef ART_RUNTIME_THREAD_LIST_H_
 #define ART_RUNTIME_THREAD_LIST_H_
 
+#include "base/histogram.h"
 #include "base/mutex.h"
+#include "gc_root.h"
 #include "jni.h"
 #include "object_callbacks.h"
 
@@ -39,11 +41,10 @@
   ~ThreadList();
 
   void DumpForSigQuit(std::ostream& os)
-      LOCKS_EXCLUDED(Locks::thread_list_lock_);
+      LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::mutator_lock_);
   // For thread suspend timeout dumps.
   void Dump(std::ostream& os)
-      LOCKS_EXCLUDED(Locks::thread_list_lock_,
-                     Locks::thread_suspend_count_lock_);
+      LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_);
   pid_t GetLockOwner();  // For SignalCatcher.
 
   // Thread suspension support.
@@ -68,7 +69,6 @@
   // is set to true.
   Thread* SuspendThreadByPeer(jobject peer, bool request_suspension, bool debug_suspension,
                               bool* timed_out)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_suspend_thread_lock_)
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
@@ -78,7 +78,6 @@
   // the thread terminating. Note that as thread ids are recycled this may not suspend the expected
   // thread, that may be terminating. If the suspension times out then *timeout is set to true.
   Thread* SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspension, bool* timed_out)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_suspend_thread_lock_)
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
@@ -105,6 +104,11 @@
   void SuspendSelfForDebugger()
       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_);
 
+  // Resume all threads
+  void ResumeAllForDebugger()
+      LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                     Locks::thread_suspend_count_lock_);
+
   void UndoDebuggerSuspensions()
       LOCKS_EXCLUDED(Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
@@ -122,9 +126,6 @@
   void VisitRoots(RootCallback* callback, void* arg) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void VerifyRoots(VerifyRootCallback* callback, void* arg) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // Return a copy of the thread list.
   std::list<Thread*> GetList() EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_) {
     return list_;
@@ -166,6 +167,10 @@
   // Signaled when threads terminate. Used to determine when all non-daemons have terminated.
   ConditionVariable thread_exit_cond_ GUARDED_BY(Locks::thread_list_lock_);
 
+  // Thread suspend time histogram. Only modified when all the threads are suspended, so guarding
+  // by mutator lock ensures no thread can read when another thread is modifying it.
+  Histogram<uint64_t> suspend_all_historam_ GUARDED_BY(Locks::mutator_lock_);
+
   friend class Thread;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadList);
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index e8c9ff8..587eb32 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -42,14 +42,14 @@
 }
 
 ThreadPoolWorker::~ThreadPoolWorker() {
-  CHECK_PTHREAD_CALL(pthread_join, (pthread_, NULL), "thread pool worker shutdown");
+  CHECK_PTHREAD_CALL(pthread_join, (pthread_, nullptr), "thread pool worker shutdown");
 }
 
 void ThreadPoolWorker::Run() {
   Thread* self = Thread::Current();
-  Task* task = NULL;
+  Task* task = nullptr;
   thread_pool_->creation_barier_.Wait(self);
-  while ((task = thread_pool_->GetTask(self)) != NULL) {
+  while ((task = thread_pool_->GetTask(self)) != nullptr) {
     task->Run(self);
     task->Finalize();
   }
@@ -58,11 +58,11 @@
 void* ThreadPoolWorker::Callback(void* arg) {
   ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg);
   Runtime* runtime = Runtime::Current();
-  CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, NULL, false));
+  CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, nullptr, false));
   // Do work until its time to shut down.
   worker->Run();
   runtime->DetachCurrentThread();
-  return NULL;
+  return nullptr;
 }
 
 void ThreadPool::AddTask(Thread* self, Task* task) {
@@ -89,8 +89,9 @@
     max_active_workers_(num_threads) {
   Thread* self = Thread::Current();
   while (GetThreadCount() < num_threads) {
-    const std::string name = StringPrintf("%s worker thread %zu", name_.c_str(), GetThreadCount());
-    threads_.push_back(new ThreadPoolWorker(this, name, ThreadPoolWorker::kDefaultStackSize));
+    const std::string worker_name = StringPrintf("%s worker thread %zu", name_.c_str(),
+                                                 GetThreadCount());
+    threads_.push_back(new ThreadPoolWorker(this, worker_name, ThreadPoolWorker::kDefaultStackSize));
   }
   // Wait for all of the threads to attach.
   creation_barier_.Wait(self);
@@ -137,8 +138,8 @@
     const size_t active_threads = thread_count - waiting_count_;
     // <= since self is considered an active worker.
     if (active_threads <= max_active_workers_) {
-      Task* task = TryGetTaskLocked(self);
-      if (task != NULL) {
+      Task* task = TryGetTaskLocked();
+      if (task != nullptr) {
         return task;
       }
     }
@@ -157,28 +158,28 @@
     --waiting_count_;
   }
 
-  // We are shutting down, return NULL to tell the worker thread to stop looping.
-  return NULL;
+  // We are shutting down, return nullptr to tell the worker thread to stop looping.
+  return nullptr;
 }
 
 Task* ThreadPool::TryGetTask(Thread* self) {
   MutexLock mu(self, task_queue_lock_);
-  return TryGetTaskLocked(self);
+  return TryGetTaskLocked();
 }
 
-Task* ThreadPool::TryGetTaskLocked(Thread* self) {
+Task* ThreadPool::TryGetTaskLocked() {
   if (started_ && !tasks_.empty()) {
     Task* task = tasks_.front();
     tasks_.pop_front();
     return task;
   }
-  return NULL;
+  return nullptr;
 }
 
 void ThreadPool::Wait(Thread* self, bool do_work, bool may_hold_locks) {
   if (do_work) {
-    Task* task = NULL;
-    while ((task = TryGetTask(self)) != NULL) {
+    Task* task = nullptr;
+    while ((task = TryGetTask(self)) != nullptr) {
       task->Run(self);
       task->Finalize();
     }
@@ -201,17 +202,17 @@
 
 WorkStealingWorker::WorkStealingWorker(ThreadPool* thread_pool, const std::string& name,
                                        size_t stack_size)
-    : ThreadPoolWorker(thread_pool, name, stack_size), task_(NULL) {}
+    : ThreadPoolWorker(thread_pool, name, stack_size), task_(nullptr) {}
 
 void WorkStealingWorker::Run() {
   Thread* self = Thread::Current();
-  Task* task = NULL;
+  Task* task = nullptr;
   WorkStealingThreadPool* thread_pool = down_cast<WorkStealingThreadPool*>(thread_pool_);
-  while ((task = thread_pool_->GetTask(self)) != NULL) {
+  while ((task = thread_pool_->GetTask(self)) != nullptr) {
     WorkStealingTask* stealing_task = down_cast<WorkStealingTask*>(task);
 
     {
-      CHECK(task_ == NULL);
+      CHECK(task_ == nullptr);
       MutexLock mu(self, thread_pool->work_steal_lock_);
       // Register that we are running the task
       ++stealing_task->ref_count_;
@@ -221,7 +222,7 @@
     // Mark ourselves as not running a task so that nobody tries to steal from us.
     // There is a race condition that someone starts stealing from us at this point. This is okay
     // due to the reference counting.
-    task_ = NULL;
+    task_ = nullptr;
 
     bool finalize;
 
@@ -229,13 +230,13 @@
     // all that happens when the race occurs is that we steal some work instead of processing a
     // task from the queue.
     while (thread_pool->GetTaskCount(self) == 0) {
-      WorkStealingTask* steal_from_task  = NULL;
+      WorkStealingTask* steal_from_task  = nullptr;
 
       {
         MutexLock mu(self, thread_pool->work_steal_lock_);
         // Try finding a task to steal from.
-        steal_from_task = thread_pool->FindTaskToStealFrom(self);
-        if (steal_from_task != NULL) {
+        steal_from_task = thread_pool->FindTaskToStealFrom();
+        if (steal_from_task != nullptr) {
           CHECK_NE(stealing_task, steal_from_task)
               << "Attempting to steal from completed self task";
           steal_from_task->ref_count_++;
@@ -244,7 +245,7 @@
         }
       }
 
-      if (steal_from_task != NULL) {
+      if (steal_from_task != nullptr) {
         // Task which completed earlier is going to steal some work.
         stealing_task->StealFrom(self, steal_from_task);
 
@@ -279,12 +280,13 @@
       work_steal_lock_("work stealing lock"),
       steal_index_(0) {
   while (GetThreadCount() < num_threads) {
-    const std::string name = StringPrintf("Work stealing worker %zu", GetThreadCount());
-    threads_.push_back(new WorkStealingWorker(this, name, ThreadPoolWorker::kDefaultStackSize));
+    const std::string worker_name = StringPrintf("Work stealing worker %zu", GetThreadCount());
+    threads_.push_back(new WorkStealingWorker(this, worker_name,
+                                              ThreadPoolWorker::kDefaultStackSize));
   }
 }
 
-WorkStealingTask* WorkStealingThreadPool::FindTaskToStealFrom(Thread* self) {
+WorkStealingTask* WorkStealingThreadPool::FindTaskToStealFrom() {
   const size_t thread_count = GetThreadCount();
   for (size_t i = 0; i < thread_count; ++i) {
     // TODO: Use CAS instead of lock.
@@ -301,7 +303,7 @@
     }
   }
   // Couldn't find something to steal.
-  return NULL;
+  return nullptr;
 }
 
 WorkStealingThreadPool::~WorkStealingThreadPool() {}
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index c816c84..79b57af 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -22,19 +22,32 @@
 
 #include "barrier.h"
 #include "base/mutex.h"
-#include "closure.h"
 #include "mem_map.h"
 
 namespace art {
 
 class ThreadPool;
 
+class Closure {
+ public:
+  virtual ~Closure() { }
+  virtual void Run(Thread* self) = 0;
+};
+
 class Task : public Closure {
  public:
-  // Called when references reaches 0.
+  // Called after Closure::Run has been called.
   virtual void Finalize() { }
 };
 
+class SelfDeletingTask : public Task {
+ public:
+  virtual ~SelfDeletingTask() { }
+  virtual void Finalize() {
+    delete this;
+  }
+};
+
 class ThreadPoolWorker {
  public:
   static const size_t kDefaultStackSize = 1 * MB;
@@ -101,7 +114,7 @@
 
   // Try to get a task, returning NULL if there is none available.
   Task* TryGetTask(Thread* self);
-  Task* TryGetTaskLocked(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_);
+  Task* TryGetTaskLocked() EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_);
 
   // Are we shutting down?
   bool IsShuttingDown() const EXCLUSIVE_LOCKS_REQUIRED(task_queue_lock_) {
@@ -178,7 +191,7 @@
   size_t steal_index_;
 
   // Find a task to steal from
-  WorkStealingTask* FindTaskToStealFrom(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_);
+  WorkStealingTask* FindTaskToStealFrom() EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_);
 
   friend class WorkStealingWorker;
 };
diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc
index 4bd44dc..d5f17d1 100644
--- a/runtime/thread_pool_test.cc
+++ b/runtime/thread_pool_test.cc
@@ -95,11 +95,7 @@
   EXPECT_EQ(0, bad_count.LoadSequentiallyConsistent());
   // Allow tasks to finish up and delete themselves.
   thread_pool.StartWorkers(self);
-  while (count.LoadSequentiallyConsistent() != num_tasks &&
-      bad_count.LoadSequentiallyConsistent() != 1) {
-    usleep(200);
-  }
-  thread_pool.StopWorkers(self);
+  thread_pool.Wait(self, false, false);
 }
 
 class TreeTask : public Task {
diff --git a/runtime/thread_state.h b/runtime/thread_state.h
index 0e47d21..b5479ed 100644
--- a/runtime/thread_state.h
+++ b/runtime/thread_state.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_THREAD_STATE_H_
 #define ART_RUNTIME_THREAD_STATE_H_
 
+#include <ostream>
+
 namespace art {
 
 enum ThreadState {
@@ -39,10 +41,12 @@
   kWaitingInMainSignalCatcherLoop,  // WAITING        TS_WAIT      blocking/reading/processing signals
   kWaitingForDeoptimization,        // WAITING        TS_WAIT      waiting for deoptimization suspend all
   kWaitingForMethodTracingStart,    // WAITING        TS_WAIT      waiting for method tracing to start
+  kWaitingForVisitObjects,          // WAITING        TS_WAIT      waiting for visiting objects
   kStarting,                        // NEW            TS_WAIT      native thread started, not yet ready to run managed code
   kNative,                          // RUNNABLE       TS_RUNNING   running in a JNI native method
   kSuspended,                       // RUNNABLE       TS_RUNNING   suspended by GC or debugger
 };
+std::ostream& operator<<(std::ostream& os, const ThreadState& rhs);
 
 }  // namespace art
 
diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc
index 04abe64..4d2aec0 100644
--- a/runtime/throw_location.cc
+++ b/runtime/throw_location.cc
@@ -34,11 +34,11 @@
 
 void ThrowLocation::VisitRoots(RootCallback* visitor, void* arg) {
   if (this_object_ != nullptr) {
-    visitor(&this_object_, arg, 0, kRootVMInternal);
+    visitor(&this_object_, arg, RootInfo(kRootVMInternal));
     DCHECK(this_object_ != nullptr);
   }
   if (method_ != nullptr) {
-    visitor(reinterpret_cast<mirror::Object**>(&method_), arg, 0, kRootVMInternal);
+    visitor(reinterpret_cast<mirror::Object**>(&method_), arg, RootInfo(kRootVMInternal));
     DCHECK(method_ != nullptr);
   }
 }
diff --git a/runtime/throw_location.h b/runtime/throw_location.h
index b36eb67..bec0da4 100644
--- a/runtime/throw_location.h
+++ b/runtime/throw_location.h
@@ -20,6 +20,7 @@
 #include "object_callbacks.h"
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "gc_root.h"
 
 #include <stdint.h>
 #include <string>
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 027f62d..5066e03 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"
@@ -35,9 +38,7 @@
 #include "ScopedLocalRef.h"
 #include "thread.h"
 #include "thread_list.h"
-#if !defined(ART_USE_PORTABLE_COMPILER)
 #include "entrypoints/quick/quick_entrypoints.h"
-#endif
 
 namespace art {
 
@@ -149,7 +150,7 @@
 }
 
 void Trace::SetDefaultClockSource(TraceClockSource clock_source) {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
   default_clock_source_ = clock_source;
 #else
   if (clock_source != kTraceClockSourceWall) {
@@ -241,7 +242,8 @@
   the_trace->CompareAndUpdateStackTrace(thread, stack_trace);
 }
 
-static void ClearThreadStackTraceAndClockBase(Thread* thread, void* arg) {
+static void ClearThreadStackTraceAndClockBase(Thread* thread ATTRIBUTE_UNUSED,
+                                              void* arg ATTRIBUTE_UNUSED) {
   thread->SetTraceClockBase(0);
   std::vector<mirror::ArtMethod*>* stack_trace = thread->GetStackTraceSample();
   thread->SetStackTraceSample(NULL);
@@ -427,6 +429,15 @@
                                                     instrumentation::Instrumentation::kMethodExited |
                                                     instrumentation::Instrumentation::kMethodUnwind);
     }
+    if (the_trace->trace_file_.get() != nullptr) {
+      // Do not try to erase, so flush and close explicitly.
+      if (the_trace->trace_file_->Flush() != 0) {
+        PLOG(ERROR) << "Could not flush trace file.";
+      }
+      if (the_trace->trace_file_->Close() != 0) {
+        PLOG(ERROR) << "Could not close trace file.";
+      }
+    }
     delete the_trace;
   }
   runtime->GetThreadList()->ResumeAll();
@@ -558,27 +569,30 @@
 
 void Trace::DexPcMoved(Thread* thread, mirror::Object* this_object,
                        mirror::ArtMethod* method, uint32_t new_dex_pc) {
+  UNUSED(thread, this_object, method, new_dex_pc);
   // We're not recorded to listen to this kind of event, so complain.
   LOG(ERROR) << "Unexpected dex PC event in tracing " << PrettyMethod(method) << " " << new_dex_pc;
 }
 
-void Trace::FieldRead(Thread* /*thread*/, mirror::Object* this_object,
+void Trace::FieldRead(Thread* thread, mirror::Object* this_object,
                        mirror::ArtMethod* method, uint32_t dex_pc, mirror::ArtField* field)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  UNUSED(thread, this_object, method, dex_pc, field);
   // We're not recorded to listen to this kind of event, so complain.
   LOG(ERROR) << "Unexpected field read event in tracing " << PrettyMethod(method) << " " << dex_pc;
 }
 
-void Trace::FieldWritten(Thread* /*thread*/, mirror::Object* this_object,
+void Trace::FieldWritten(Thread* thread, mirror::Object* this_object,
                           mirror::ArtMethod* method, uint32_t dex_pc, mirror::ArtField* field,
                           const JValue& field_value)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  UNUSED(thread, this_object, method, dex_pc, field, field_value);
   // We're not recorded to listen to this kind of event, so complain.
   LOG(ERROR) << "Unexpected field write event in tracing " << PrettyMethod(method) << " " << dex_pc;
 }
 
-void Trace::MethodEntered(Thread* thread, mirror::Object* this_object,
-                          mirror::ArtMethod* method, uint32_t dex_pc) {
+void Trace::MethodEntered(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED,
+                          mirror::ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) {
   uint32_t thread_clock_diff = 0;
   uint32_t wall_clock_diff = 0;
   ReadClocks(thread, &thread_clock_diff, &wall_clock_diff);
@@ -586,10 +600,9 @@
                       thread_clock_diff, wall_clock_diff);
 }
 
-void Trace::MethodExited(Thread* thread, mirror::Object* this_object,
-                         mirror::ArtMethod* method, uint32_t dex_pc,
-                         const JValue& return_value) {
-  UNUSED(return_value);
+void Trace::MethodExited(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED,
+                         mirror::ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED,
+                         const JValue& return_value ATTRIBUTE_UNUSED) {
   uint32_t thread_clock_diff = 0;
   uint32_t wall_clock_diff = 0;
   ReadClocks(thread, &thread_clock_diff, &wall_clock_diff);
@@ -597,8 +610,8 @@
                       thread_clock_diff, wall_clock_diff);
 }
 
-void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object,
-                         mirror::ArtMethod* method, uint32_t dex_pc) {
+void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED,
+                         mirror::ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) {
   uint32_t thread_clock_diff = 0;
   uint32_t wall_clock_diff = 0;
   ReadClocks(thread, &thread_clock_diff, &wall_clock_diff);
@@ -610,6 +623,7 @@
                             mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
                             mirror::Throwable* exception_object)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  UNUSED(thread, throw_location, catch_method, catch_dex_pc, exception_object);
   LOG(ERROR) << "Unexpected exception caught event in tracing";
 }
 
@@ -706,9 +720,23 @@
 
 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 same thread/tid may be used multiple times. As SafeMap::Put does not allow to override
+    // a previous mapping, use SafeMap::Overwrite.
+    the_trace_->exited_threads_.Overwrite(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/transaction.cc b/runtime/transaction.cc
index b496f25..118c1a2 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -144,7 +144,7 @@
   LogInternedString(log);
 }
 
-void Transaction::LogInternedString(InternStringLog& log) {
+void Transaction::LogInternedString(const InternStringLog& log) {
   Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
   MutexLock mu(Thread::Current(), log_lock_);
   intern_string_logs_.push_front(log);
@@ -206,7 +206,7 @@
     it.second.VisitRoots(callback, arg);
     mirror::Object* old_root = it.first;
     mirror::Object* new_root = old_root;
-    callback(&new_root, arg, 0, kRootUnknown);
+    callback(&new_root, arg, RootInfo(kRootUnknown));
     if (new_root != old_root) {
       moving_roots.push_back(std::make_pair(old_root, new_root));
     }
@@ -233,7 +233,7 @@
     mirror::Array* old_root = it.first;
     CHECK(!old_root->IsObjectArray());
     mirror::Array* new_root = old_root;
-    callback(reinterpret_cast<mirror::Object**>(&new_root), arg, 0, kRootUnknown);
+    callback(reinterpret_cast<mirror::Object**>(&new_root), arg, RootInfo(kRootUnknown));
     if (new_root != old_root) {
       moving_roots.push_back(std::make_pair(old_root, new_root));
     }
@@ -384,7 +384,7 @@
       }
       break;
     default:
-      LOG(FATAL) << "Unknown value kind " << field_value.kind;
+      LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
       break;
   }
 }
@@ -396,7 +396,7 @@
       mirror::Object* obj =
           reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
       if (obj != nullptr) {
-        callback(&obj, arg, 0, kRootUnknown);
+        callback(&obj, arg, RootInfo(kRootUnknown));
         field_value.value = reinterpret_cast<uintptr_t>(obj);
       }
     }
@@ -406,42 +406,42 @@
 void Transaction::InternStringLog::Undo(InternTable* intern_table) {
   DCHECK(intern_table != nullptr);
   switch (string_op_) {
-      case InternStringLog::kInsert: {
-        switch (string_kind_) {
-          case InternStringLog::kStrongString:
-            intern_table->RemoveStrongFromTransaction(str_);
-            break;
-          case InternStringLog::kWeakString:
-            intern_table->RemoveWeakFromTransaction(str_);
-            break;
-          default:
-            LOG(FATAL) << "Unknown interned string kind";
-            break;
-        }
-        break;
+    case InternStringLog::kInsert: {
+      switch (string_kind_) {
+        case InternStringLog::kStrongString:
+          intern_table->RemoveStrongFromTransaction(str_);
+          break;
+        case InternStringLog::kWeakString:
+          intern_table->RemoveWeakFromTransaction(str_);
+          break;
+        default:
+          LOG(FATAL) << "Unknown interned string kind";
+          break;
       }
-      case InternStringLog::kRemove: {
-        switch (string_kind_) {
-          case InternStringLog::kStrongString:
-            intern_table->InsertStrongFromTransaction(str_);
-            break;
-          case InternStringLog::kWeakString:
-            intern_table->InsertWeakFromTransaction(str_);
-            break;
-          default:
-            LOG(FATAL) << "Unknown interned string kind";
-            break;
-        }
-        break;
-      }
-      default:
-        LOG(FATAL) << "Unknown interned string op";
-        break;
+      break;
     }
+    case InternStringLog::kRemove: {
+      switch (string_kind_) {
+        case InternStringLog::kStrongString:
+          intern_table->InsertStrongFromTransaction(str_);
+          break;
+        case InternStringLog::kWeakString:
+          intern_table->InsertWeakFromTransaction(str_);
+          break;
+        default:
+          LOG(FATAL) << "Unknown interned string kind";
+          break;
+      }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unknown interned string op";
+      break;
+  }
 }
 
 void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
-  callback(reinterpret_cast<mirror::Object**>(&str_), arg, 0, kRootInternedString);
+  callback(reinterpret_cast<mirror::Object**>(&str_), arg, RootInfo(kRootInternedString));
 }
 
 void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 21d3c98..8c82847 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -19,6 +19,8 @@
 
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "base/value_object.h"
+#include "gc_root.h"
 #include "object_callbacks.h"
 #include "offsets.h"
 #include "primitive.h"
@@ -35,7 +37,7 @@
 }
 class InternTable;
 
-class Transaction {
+class Transaction FINAL {
  public:
   Transaction();
   ~Transaction();
@@ -92,7 +94,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  class ObjectLog {
+  class ObjectLog : public ValueObject {
    public:
     void LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile);
     void LogByteValue(MemberOffset offset, int8_t value, bool is_volatile);
@@ -119,7 +121,7 @@
       k64Bits,
       kReference
     };
-    struct FieldValue {
+    struct FieldValue : public ValueObject {
       // TODO use JValue instead ?
       uint64_t value;
       FieldValueKind kind;
@@ -134,7 +136,7 @@
     std::map<uint32_t, FieldValue> field_values_;
   };
 
-  class ArrayLog {
+  class ArrayLog : public ValueObject {
    public:
     void LogValue(size_t index, uint64_t value);
 
@@ -153,7 +155,7 @@
     std::map<size_t, uint64_t> array_values_;
   };
 
-  class InternStringLog {
+  class InternStringLog : public ValueObject {
    public:
     enum StringKind {
       kStrongString,
@@ -175,11 +177,11 @@
 
    private:
     mirror::String* str_;
-    StringKind string_kind_;
-    StringOp string_op_;
+    const StringKind string_kind_;
+    const StringOp string_op_;
   };
 
-  void LogInternedString(InternStringLog& log)
+  void LogInternedString(const InternStringLog& log)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
       LOCKS_EXCLUDED(log_lock_);
 
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index a14889c..8c4b90d 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -147,12 +147,12 @@
   mirror::ArtField* floatField = h_klass->FindDeclaredStaticField("floatField", "F");
   ASSERT_TRUE(floatField != nullptr);
   ASSERT_EQ(floatField->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
-  ASSERT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
+  ASSERT_FLOAT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
 
   mirror::ArtField* doubleField = h_klass->FindDeclaredStaticField("doubleField", "D");
   ASSERT_TRUE(doubleField != nullptr);
   ASSERT_EQ(doubleField->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
-  ASSERT_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
+  ASSERT_DOUBLE_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
 
   mirror::ArtField* objectField = h_klass->FindDeclaredStaticField("objectField",
                                                                       "Ljava/lang/Object;");
@@ -190,8 +190,8 @@
   EXPECT_EQ(shortField->GetShort(h_klass.Get()), 0);
   EXPECT_EQ(intField->GetInt(h_klass.Get()), 0);
   EXPECT_EQ(longField->GetLong(h_klass.Get()), static_cast<int64_t>(0));
-  EXPECT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
-  EXPECT_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
+  EXPECT_FLOAT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
+  EXPECT_DOUBLE_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
   EXPECT_EQ(objectField->GetObject(h_klass.Get()), nullptr);
 }
 
@@ -246,12 +246,12 @@
   mirror::ArtField* floatField = h_klass->FindDeclaredInstanceField("floatField", "F");
   ASSERT_TRUE(floatField != nullptr);
   ASSERT_EQ(floatField->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
-  ASSERT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
+  ASSERT_FLOAT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
 
   mirror::ArtField* doubleField = h_klass->FindDeclaredInstanceField("doubleField", "D");
   ASSERT_TRUE(doubleField != nullptr);
   ASSERT_EQ(doubleField->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
-  ASSERT_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
+  ASSERT_DOUBLE_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
 
   mirror::ArtField* objectField = h_klass->FindDeclaredInstanceField("objectField",
                                                                         "Ljava/lang/Object;");
@@ -289,8 +289,8 @@
   EXPECT_EQ(shortField->GetShort(h_instance.Get()), 0);
   EXPECT_EQ(intField->GetInt(h_instance.Get()), 0);
   EXPECT_EQ(longField->GetLong(h_instance.Get()), static_cast<int64_t>(0));
-  EXPECT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
-  EXPECT_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
+  EXPECT_FLOAT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
+  EXPECT_DOUBLE_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
   EXPECT_EQ(objectField->GetObject(h_instance.Get()), nullptr);
 }
 
@@ -356,14 +356,14 @@
   mirror::FloatArray* floatArray = floatArrayField->GetObject(h_klass.Get())->AsFloatArray();
   ASSERT_TRUE(floatArray != nullptr);
   ASSERT_EQ(floatArray->GetLength(), 1);
-  ASSERT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+  ASSERT_FLOAT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
 
   mirror::ArtField* doubleArrayField = h_klass->FindDeclaredStaticField("doubleArrayField", "[D");
   ASSERT_TRUE(doubleArrayField != nullptr);
   mirror::DoubleArray* doubleArray = doubleArrayField->GetObject(h_klass.Get())->AsDoubleArray();
   ASSERT_TRUE(doubleArray != nullptr);
   ASSERT_EQ(doubleArray->GetLength(), 1);
-  ASSERT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+  ASSERT_DOUBLE_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
 
   mirror::ArtField* objectArrayField = h_klass->FindDeclaredStaticField("objectArrayField",
                                                                            "[Ljava/lang/Object;");
@@ -404,8 +404,8 @@
   EXPECT_EQ(shortArray->GetWithoutChecks(0), 0);
   EXPECT_EQ(intArray->GetWithoutChecks(0), 0);
   EXPECT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
-  EXPECT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
-  EXPECT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+  EXPECT_FLOAT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+  EXPECT_DOUBLE_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
   EXPECT_EQ(objectArray->GetWithoutChecks(0), nullptr);
 }
 
diff --git a/runtime/utf.cc b/runtime/utf.cc
index 02cbe3b..05b847b 100644
--- a/runtime/utf.cc
+++ b/runtime/utf.cc
@@ -70,27 +70,27 @@
 
 int32_t ComputeUtf16Hash(mirror::CharArray* chars, int32_t offset,
                          size_t char_count) {
-  int32_t hash = 0;
+  uint32_t hash = 0;
   for (size_t i = 0; i < char_count; i++) {
     hash = hash * 31 + chars->Get(offset + i);
   }
-  return hash;
+  return static_cast<int32_t>(hash);
 }
 
 int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count) {
-  int32_t hash = 0;
+  uint32_t hash = 0;
   while (char_count--) {
     hash = hash * 31 + *chars++;
   }
-  return hash;
+  return static_cast<int32_t>(hash);
 }
 
-int32_t ComputeUtf8Hash(const char* chars) {
-  int32_t hash = 0;
+size_t ComputeModifiedUtf8Hash(const char* chars) {
+  size_t hash = 0;
   while (*chars != '\0') {
-    hash = hash * 31 + GetUtf16FromUtf8(&chars);
+    hash = hash * 31 + *chars++;
   }
-  return hash;
+  return static_cast<int32_t>(hash);
 }
 
 int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2) {
diff --git a/runtime/utf.h b/runtime/utf.h
index a09db9d..b55227b 100644
--- a/runtime/utf.h
+++ b/runtime/utf.h
@@ -79,8 +79,9 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count);
 
-// Compute a hash code of a UTF-8 string.
-int32_t ComputeUtf8Hash(const char* chars);
+// Compute a hash code of a modified UTF-8 string. Not the standard java hash since it returns a
+// size_t and hashes individual chars instead of codepoint words.
+size_t ComputeModifiedUtf8Hash(const char* chars);
 
 /*
  * Retrieve the next UTF-16 character from a UTF-8 string.
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 0496d97..908cfbd2 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -28,7 +28,6 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file-inl.h"
-#include "field_helper.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -40,17 +39,10 @@
 #include "scoped_thread_state_change.h"
 #include "utf-inl.h"
 
-#if !defined(HAVE_POSIX_CLOCKS)
-#include <sys/time.h>
-#endif
-
-#if defined(HAVE_PRCTL)
-#include <sys/prctl.h>
-#endif
-
 #if defined(__APPLE__)
 #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
 #include <sys/syscall.h>
+#include <sys/time.h>
 #endif
 
 #include <backtrace/Backtrace.h>  // For DumpNativeStack.
@@ -61,6 +53,10 @@
 
 namespace art {
 
+#if defined(__linux__)
+static constexpr bool kUseAddr2line = !kIsTargetBuild;
+#endif
+
 pid_t GetTid() {
 #if defined(__APPLE__)
   uint64_t owner;
@@ -92,7 +88,7 @@
   // (On Mac OS 10.7, it's the end.)
   int stack_variable;
   if (stack_addr > &stack_variable) {
-    *stack_base = reinterpret_cast<byte*>(stack_addr) - *stack_size;
+    *stack_base = reinterpret_cast<uint8_t*>(stack_addr) - *stack_size;
   } else {
     *stack_base = stack_addr;
   }
@@ -165,11 +161,11 @@
 }
 
 uint64_t MilliTime() {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
   timespec now;
   clock_gettime(CLOCK_MONOTONIC, &now);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000);
-#else
+#else  // __APPLE__
   timeval now;
   gettimeofday(&now, NULL);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000);
@@ -177,11 +173,11 @@
 }
 
 uint64_t MicroTime() {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
   timespec now;
   clock_gettime(CLOCK_MONOTONIC, &now);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000);
-#else
+#else  // __APPLE__
   timeval now;
   gettimeofday(&now, NULL);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec;
@@ -189,11 +185,11 @@
 }
 
 uint64_t NanoTime() {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
   timespec now;
   clock_gettime(CLOCK_MONOTONIC, &now);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
-#else
+#else  // __APPLE__
   timeval now;
   gettimeofday(&now, NULL);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000);
@@ -201,11 +197,11 @@
 }
 
 uint64_t ThreadCpuNanoTime() {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(__linux__)
   timespec now;
   clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
   return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
-#else
+#else  // __APPLE__
   UNIMPLEMENTED(WARNING);
   return -1;
 #endif
@@ -324,8 +320,8 @@
     result += PrettyDescriptor(f->GetTypeDescriptor());
     result += ' ';
   }
-  StackHandleScope<1> hs(Thread::Current());
-  result += PrettyDescriptor(FieldHelper(hs.NewHandle(f)).GetDeclaringClassDescriptor());
+  std::string temp;
+  result += PrettyDescriptor(f->GetDeclaringClass()->GetDescriptor(&temp));
   result += '.';
   result += f->GetName();
   return result;
@@ -963,7 +959,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 +970,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 +1005,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 +1019,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;
@@ -1059,21 +1054,17 @@
   } else {
     s = thread_name + len - 15;
   }
-#if defined(__BIONIC__)
+#if defined(__linux__)
   // pthread_setname_np fails rather than truncating long strings.
-  char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+  char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel.
   strncpy(buf, s, sizeof(buf)-1);
   buf[sizeof(buf)-1] = '\0';
   errno = pthread_setname_np(pthread_self(), buf);
   if (errno != 0) {
     PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'";
   }
-#elif defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+#else  // __APPLE__
   pthread_setname_np(thread_name);
-#elif defined(HAVE_PRCTL)
-  prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);  // NOLINT (unsigned long)
-#else
-  UNIMPLEMENTED(WARNING) << thread_name;
 #endif
 }
 
@@ -1087,7 +1078,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,14 +1095,14 @@
     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);
-    for (size_t i = 0; i < cgroups.size(); ++i) {
-      if (cgroups[i] == "cpu") {
+    Split(cgroup_fields[1], ',', &cgroups);
+    for (size_t j = 0; j < cgroups.size(); ++j) {
+      if (cgroups[j] == "cpu") {
         return cgroup_fields[2].substr(1);  // Skip the leading slash.
       }
     }
@@ -1119,11 +1110,92 @@
   return "";
 }
 
+#if defined(__linux__)
+
+ALWAYS_INLINE
+static inline void WritePrefix(std::ostream* os, const char* prefix, bool odd) {
+  if (prefix != nullptr) {
+    *os << prefix;
+  }
+  *os << "  ";
+  if (!odd) {
+    *os << " ";
+  }
+}
+
+static bool RunCommand(std::string cmd, std::ostream* os, const char* prefix) {
+  FILE* stream = popen(cmd.c_str(), "r");
+  if (stream) {
+    if (os != nullptr) {
+      bool odd_line = true;               // We indent them differently.
+      bool wrote_prefix = false;          // Have we already written a prefix?
+      constexpr size_t kMaxBuffer = 128;  // Relatively small buffer. Should be OK as we're on an
+                                          // alt stack, but just to be sure...
+      char buffer[kMaxBuffer];
+      while (!feof(stream)) {
+        if (fgets(buffer, kMaxBuffer, stream) != nullptr) {
+          // Split on newlines.
+          char* tmp = buffer;
+          for (;;) {
+            char* new_line = strchr(tmp, '\n');
+            if (new_line == nullptr) {
+              // Print the rest.
+              if (*tmp != 0) {
+                if (!wrote_prefix) {
+                  WritePrefix(os, prefix, odd_line);
+                }
+                wrote_prefix = true;
+                *os << tmp;
+              }
+              break;
+            }
+            if (!wrote_prefix) {
+              WritePrefix(os, prefix, odd_line);
+            }
+            char saved = *(new_line + 1);
+            *(new_line + 1) = 0;
+            *os << tmp;
+            *(new_line + 1) = saved;
+            tmp = new_line + 1;
+            odd_line = !odd_line;
+            wrote_prefix = false;
+          }
+        }
+      }
+    }
+    pclose(stream);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static void Addr2line(const std::string& map_src, uintptr_t offset, std::ostream& os,
+                      const char* prefix) {
+  std::string cmdline(StringPrintf("addr2line --functions --inlines --demangle -e %s %zx",
+                                   map_src.c_str(), offset));
+  RunCommand(cmdline.c_str(), &os, prefix);
+}
+#endif
+
 void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix,
-    mirror::ArtMethod* current_method) {
-#ifdef __linux__
+    mirror::ArtMethod* current_method, void* ucontext_ptr) {
+#if __linux__
+  // b/18119146
+  if (RUNNING_ON_VALGRIND != 0) {
+    return;
+  }
+
+#if !defined(HAVE_ANDROID_OS)
+  if (GetTid() != tid) {
+    // TODO: dumping of other threads is disabled to avoid crashes during stress testing.
+    //       b/15446488.
+    return;
+  }
+#endif
+
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
-  if (!backtrace->Unwind(0)) {
+  if (!backtrace->Unwind(0, reinterpret_cast<ucontext*>(ucontext_ptr))) {
     os << prefix << "(backtrace::Unwind failed for thread " << tid << ")\n";
     return;
   } else if (backtrace->NumFrames() == 0) {
@@ -1131,6 +1203,16 @@
     return;
   }
 
+  // Check whether we have and should use addr2line.
+  bool use_addr2line;
+  if (kUseAddr2line) {
+    // Try to run it to see whether we have it. Push an argument so that it doesn't assume a.out
+    // and print to stderr.
+    use_addr2line = (gAborting > 0) && RunCommand("addr2line -h", nullptr, nullptr);
+  } else {
+    use_addr2line = false;
+  }
+
   for (Backtrace::const_iterator it = backtrace->begin();
        it != backtrace->end(); ++it) {
     // We produce output like this:
@@ -1142,6 +1224,7 @@
     // after the <RELATIVE_ADDR>. There can be any prefix data before the
     // #XX. <RELATIVE_ADDR> has to be a hex number but with no 0x prefix.
     os << prefix << StringPrintf("#%02zu pc ", it->num);
+    bool try_addr2line = false;
     if (!it->map) {
       os << StringPrintf("%08" PRIxPTR "  ???", it->pc);
     } else {
@@ -1152,9 +1235,10 @@
         if (it->func_offset != 0) {
           os << "+" << it->func_offset;
         }
+        try_addr2line = true;
       } 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));
@@ -1164,7 +1248,12 @@
       os << ")";
     }
     os << "\n";
+    if (try_addr2line && use_addr2line) {
+      Addr2line(it->map->name, it->pc - it->map->start, os, prefix);
+    }
   }
+#else
+  UNUSED(os, tid, prefix, current_method, ucontext_ptr);
 #endif
 }
 
@@ -1189,7 +1278,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();
@@ -1369,11 +1458,11 @@
 }
 
 bool IsDexMagic(uint32_t magic) {
-  return DexFile::IsMagicValid(reinterpret_cast<const byte*>(&magic));
+  return DexFile::IsMagicValid(reinterpret_cast<const uint8_t*>(&magic));
 }
 
 bool IsOatMagic(uint32_t magic) {
-  return (memcmp(reinterpret_cast<const byte*>(magic),
+  return (memcmp(reinterpret_cast<const uint8_t*>(magic),
                  OatHeader::kOatMagic,
                  sizeof(OatHeader::kOatMagic)) == 0);
 }
diff --git a/runtime/utils.h b/runtime/utils.h
index 3f2d829..b5413e7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -24,10 +24,10 @@
 #include <string>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/logging.h"
 #include "base/mutex.h"
 #include "globals.h"
-#include "instruction_set.h"
 #include "primitive.h"
 
 namespace art {
@@ -84,7 +84,7 @@
 
 template<int n, typename T>
 static inline bool IsAligned(T x) {
-  COMPILE_ASSERT((n & (n - 1)) == 0, n_not_power_of_two);
+  static_assert((n & (n - 1)) == 0, "n is not a power of two");
   return (x & (n - 1)) == 0;
 }
 
@@ -108,23 +108,37 @@
   DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value)
 
 // Check whether an N-bit two's-complement representation can hold value.
-static inline bool IsInt(int N, word value) {
+static inline bool IsInt(int N, intptr_t value) {
   CHECK_LT(0, N);
-  CHECK_LT(N, kBitsPerWord);
-  word limit = static_cast<word>(1) << (N - 1);
+  CHECK_LT(N, kBitsPerIntPtrT);
+  intptr_t limit = static_cast<intptr_t>(1) << (N - 1);
   return (-limit <= value) && (value < limit);
 }
 
-static inline bool IsUint(int N, word value) {
+static inline bool IsInt32(int N, int32_t value) {
   CHECK_LT(0, N);
-  CHECK_LT(N, kBitsPerWord);
-  word limit = static_cast<word>(1) << N;
+  CHECK_LT(static_cast<size_t>(N), 8 * sizeof(int32_t));
+  int32_t limit = static_cast<int32_t>(1) << (N - 1);
+  return (-limit <= value) && (value < limit);
+}
+
+static inline bool IsInt64(int N, int64_t value) {
+  CHECK_LT(0, N);
+  CHECK_LT(static_cast<size_t>(N), 8 * sizeof(int64_t));
+  int64_t limit = static_cast<int64_t>(1) << (N - 1);
+  return (-limit <= value) && (value < limit);
+}
+
+static inline bool IsUint(int N, intptr_t value) {
+  CHECK_LT(0, N);
+  CHECK_LT(N, kBitsPerIntPtrT);
+  intptr_t limit = static_cast<intptr_t>(1) << N;
   return (0 <= value) && (value < limit);
 }
 
-static inline bool IsAbsoluteUint(int N, word value) {
+static inline bool IsAbsoluteUint(int N, intptr_t value) {
   CHECK_LT(0, N);
-  CHECK_LT(N, kBitsPerWord);
+  CHECK_LT(N, kBitsPerIntPtrT);
   if (value < 0) value = -value;
   return IsUint(N, value);
 }
@@ -145,24 +159,24 @@
   return static_cast<uint32_t>(value >> 32);
 }
 
-// A static if which determines whether to return type A or B based on the condition boolean.
-template <bool condition, typename A, typename B>
-struct TypeStaticIf {
-  typedef A type;
-};
-
-// Specialization to handle the false case.
-template <typename A, typename B>
-struct TypeStaticIf<false, A,  B> {
-  typedef B type;
-};
-
 // Type identity.
 template <typename T>
 struct TypeIdentity {
   typedef T type;
 };
 
+// Like sizeof, but count how many bits a type takes. Pass type explicitly.
+template <typename T>
+static constexpr size_t BitSizeOf() {
+  return sizeof(T) * CHAR_BIT;
+}
+
+// Like sizeof, but count how many bits a type takes. Infers type from parameter.
+template <typename T>
+static constexpr size_t BitSizeOf(T /*x*/) {
+  return sizeof(T) * CHAR_BIT;
+}
+
 // For rounding integers.
 template<typename T>
 static constexpr T RoundDown(T x, typename TypeIdentity<T>::type n) WARN_UNUSED;
@@ -199,22 +213,39 @@
   return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uintptr_t>(x), n));
 }
 
-// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
+namespace utils {
+namespace detail {  // Private, implementation-specific namespace. Do not poke outside of this file.
+template <typename T>
+static constexpr inline T RoundUpToPowerOfTwoRecursive(T x, size_t bit) {
+  return bit == (BitSizeOf<T>()) ? x: RoundUpToPowerOfTwoRecursive(x | x >> bit, bit << 1);
+}
+}  // namespace detail
+}  // namespace utils
+
+// Recursive implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
 // figure 3-3, page 48, where the function is called clp2.
-static inline uint32_t RoundUpToPowerOfTwo(uint32_t x) {
-  x = x - 1;
-  x = x | (x >> 1);
-  x = x | (x >> 2);
-  x = x | (x >> 4);
-  x = x | (x >> 8);
-  x = x | (x >> 16);
-  return x + 1;
+template <typename T>
+static constexpr inline T RoundUpToPowerOfTwo(T x) {
+  return art::utils::detail::RoundUpToPowerOfTwoRecursive(x - 1, 1) + 1;
+}
+
+// Find the bit position of the most significant bit (0-based), or -1 if there were no bits set.
+template <typename T>
+static constexpr ssize_t MostSignificantBit(T value) {
+  return (value == 0) ? -1 : (MostSignificantBit(value >> 1) + 1);
+}
+
+// How many bits (minimally) does it take to store the constant 'value'? i.e. 1 for 1, 3 for 5, etc.
+template <typename T>
+static constexpr size_t MinimumBitsToStore(T value) {
+  return static_cast<size_t>(MostSignificantBit(value) + 1);
 }
 
 template<typename T>
 static constexpr int CLZ(T x) {
+  static_assert(sizeof(T) <= sizeof(long long), "T too large, must be smaller than long long");  // NOLINT [runtime/int] [4]
   return (sizeof(T) == sizeof(uint32_t))
-      ? __builtin_clz(x)
+      ? __builtin_clz(x)  // TODO: __builtin_clz[ll] has undefined behavior for x=0
       : __builtin_clzll(x);
 }
 
@@ -246,7 +277,7 @@
 // of V >= size of U (compile-time checked).
 template<typename U, typename V>
 static inline V bit_cast(U in) {
-  COMPILE_ASSERT(sizeof(U) <= sizeof(V), size_of_u_not_le_size_of_v);
+  static_assert(sizeof(U) <= sizeof(V), "Size of U not <= size of V");
   union {
     U u;
     V v;
@@ -399,18 +430,19 @@
 // Sleep for the given number of nanoseconds, a bad way to handle contention.
 void NanoSleep(uint64_t ns);
 
-// Initialize a timespec to either an absolute or relative time.
+// Initialize a timespec to either a relative time (ms,ns), or to the absolute
+// time corresponding to the indicated clock value plus the supplied offset.
 void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts);
 
 // 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();
@@ -433,7 +465,7 @@
 
 // Dumps the native stack for thread 'tid' to 'os'.
 void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "",
-    mirror::ArtMethod* current_method = nullptr)
+    mirror::ArtMethod* current_method = nullptr, void* ucontext = nullptr)
     NO_THREAD_SAFETY_ANALYSIS;
 
 // Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86.
@@ -491,15 +523,12 @@
 
   template <typename A, typename B>
   inline void operator() (A a, B b) const {
-    UNUSED(a);
-    UNUSED(b);
+    UNUSED(a, b);
   }
 
   template <typename A, typename B, typename C>
   inline void operator() (A a, B b, C c) const {
-    UNUSED(a);
-    UNUSED(b);
-    UNUSED(c);
+    UNUSED(a, b, c);
   }
 };
 
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 1b2c3ee..a3dd13c 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);
 }
 
@@ -392,6 +392,9 @@
 }
 
 TEST_F(UtilsTest, ExecError) {
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
   std::vector<std::string> command;
   command.push_back("bogus");
   std::string error_msg;
@@ -402,4 +405,36 @@
   }
 }
 
+TEST_F(UtilsTest, RoundUpToPowerOfTwo) {
+  // Tests the constexpr variant since all the parameters are constexpr
+  EXPECT_EQ(0, RoundUpToPowerOfTwo(0));
+  EXPECT_EQ(1, RoundUpToPowerOfTwo(1));
+  EXPECT_EQ(2, RoundUpToPowerOfTwo(2));
+  EXPECT_EQ(4, RoundUpToPowerOfTwo(3));
+  EXPECT_EQ(8, RoundUpToPowerOfTwo(7));
+
+  EXPECT_EQ(0b10000L, RoundUpToPowerOfTwo(0b01101L));
+  EXPECT_EQ(1ULL << 63, RoundUpToPowerOfTwo(1ULL << 62 | 1ULL));
+}
+
+TEST_F(UtilsTest, MostSignificantBit) {
+  EXPECT_EQ(-1, MostSignificantBit(0));
+  EXPECT_EQ(0, MostSignificantBit(1));
+  EXPECT_EQ(31, MostSignificantBit(~static_cast<uint32_t>(0)));
+  EXPECT_EQ(2, MostSignificantBit(0b110));
+  EXPECT_EQ(2, MostSignificantBit(0b100));
+}
+
+TEST_F(UtilsTest, MinimumBitsToStore) {
+  EXPECT_EQ(0u, MinimumBitsToStore(0));
+  EXPECT_EQ(1u, MinimumBitsToStore(1));
+  EXPECT_EQ(2u, MinimumBitsToStore(0b10));
+  EXPECT_EQ(2u, MinimumBitsToStore(0b11));
+  EXPECT_EQ(3u, MinimumBitsToStore(0b100));
+  EXPECT_EQ(3u, MinimumBitsToStore(0b110));
+  EXPECT_EQ(3u, MinimumBitsToStore(0b101));
+  EXPECT_EQ(8u, MinimumBitsToStore(0xFF));
+  EXPECT_EQ(32u, MinimumBitsToStore(~static_cast<uint32_t>(0)));
+}
+
 }  // namespace art
diff --git a/runtime/verifier/instruction_flags.h b/runtime/verifier/instruction_flags.h
index 36a6e55..e67067c 100644
--- a/runtime/verifier/instruction_flags.h
+++ b/runtime/verifier/instruction_flags.h
@@ -130,7 +130,8 @@
   uint8_t flags_;
 };
 
-COMPILE_ASSERT(sizeof(InstructionFlags) == sizeof(uint8_t), err);
+static_assert(sizeof(InstructionFlags) == sizeof(uint8_t),
+              "Size of InstructionFlags not equal to uint8_t");
 
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9747b4e..88944d7 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -25,12 +25,10 @@
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "dex_instruction_visitor.h"
-#include "field_helper.h"
 #include "gc/accounting/card_table-inl.h"
 #include "indenter.h"
 #include "intern_table.h"
 #include "leb128.h"
-#include "method_helper-inl.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class.h"
@@ -88,6 +86,31 @@
   }
 }
 
+// Note: returns true on failure.
+ALWAYS_INLINE static inline bool FailOrAbort(MethodVerifier* verifier, bool condition,
+                                             const char* error_msg, uint32_t work_insn_idx) {
+  if (kIsDebugBuild) {
+    // In a debug build, abort if the error condition is wrong.
+    DCHECK(condition) << error_msg << work_insn_idx;
+  } else {
+    // In a non-debug build, just fail the class.
+    if (!condition) {
+      verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static void SafelyMarkAllRegistersAsConflicts(MethodVerifier* verifier, RegisterLine* reg_line) {
+  if (verifier->IsConstructor()) {
+    // Before we mark all regs as conflicts, check that we don't have an uninitialized this.
+    reg_line->CheckConstructorReturn(verifier);
+  }
+  reg_line->MarkAllRegistersAsConflicts(verifier);
+}
+
 MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
                                                         mirror::Class* klass,
                                                         bool allow_soft_failures,
@@ -133,7 +156,7 @@
                                                         bool allow_soft_failures,
                                                         std::string* error) {
   DCHECK(class_def != nullptr);
-  const byte* class_data = dex_file->GetClassData(*class_def);
+  const uint8_t* class_data = dex_file->GetClassData(*class_def);
   if (class_data == nullptr) {
     // empty class, probably a marker interface
     return kNoFailure;
@@ -263,7 +286,7 @@
 
   MethodVerifier verifier(self, dex_file, dex_cache, class_loader, class_def, code_item,
                           method_idx, method, method_access_flags, true, allow_soft_failures,
-                          need_precise_constants);
+                          need_precise_constants, true);
   if (verifier.Verify()) {
     // Verification completed, however failures may be pending that didn't cause the verification
     // to hard fail.
@@ -329,7 +352,8 @@
                                const DexFile::CodeItem* code_item, uint32_t dex_method_idx,
                                Handle<mirror::ArtMethod> method, uint32_t method_access_flags,
                                bool can_load_classes, bool allow_soft_failures,
-                               bool need_precise_constants, bool verify_to_dump)
+                               bool need_precise_constants, bool verify_to_dump,
+                               bool allow_thread_suspension)
     : self_(self),
       reg_types_(can_load_classes),
       work_insn_idx_(-1),
@@ -354,7 +378,8 @@
       need_precise_constants_(need_precise_constants),
       has_check_casts_(false),
       has_virtual_or_interface_invokes_(false),
-      verify_to_dump_(verify_to_dump) {
+      verify_to_dump_(verify_to_dump),
+      allow_thread_suspension_(allow_thread_suspension) {
   Runtime::Current()->AddMethodVerifier(this);
   DCHECK(class_def != nullptr);
 }
@@ -373,7 +398,7 @@
   Handle<mirror::ArtMethod> method(hs.NewHandle(m));
   MethodVerifier verifier(self, m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
                           m->GetCodeItem(), m->GetDexMethodIndex(), method, m->GetAccessFlags(),
-                          false, true, false);
+                          false, true, false, false);
   verifier.interesting_dex_pc_ = dex_pc;
   verifier.monitor_enter_dex_pcs_ = monitor_enter_dex_pcs;
   verifier.FindLocksAtDexPc();
@@ -420,7 +445,7 @@
   Handle<mirror::ArtMethod> method(hs.NewHandle(m));
   MethodVerifier verifier(self, m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
                           m->GetCodeItem(), m->GetDexMethodIndex(), method, m->GetAccessFlags(),
-                          true, true, false);
+                          true, true, false, true);
   return verifier.FindAccessedFieldAtDexPc(dex_pc);
 }
 
@@ -452,7 +477,7 @@
   Handle<mirror::ArtMethod> method(hs.NewHandle(m));
   MethodVerifier verifier(self, m->GetDexFile(), dex_cache, class_loader, &m->GetClassDef(),
                           m->GetCodeItem(), m->GetDexMethodIndex(), method, m->GetAccessFlags(),
-                          true, true, false);
+                          true, true, false, true);
   return verifier.FindInvokedMethodAtDexPc(dex_pc);
 }
 
@@ -659,7 +684,7 @@
     }
   }
   // Iterate over each of the handlers to verify target addresses.
-  const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
   uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   for (uint32_t idx = 0; idx < handlers_size; idx++) {
@@ -710,7 +735,16 @@
     /* Flag instructions that are garbage collection points */
     // All invoke points are marked as "Throw" points already.
     // We are relying on this to also count all the invokes as interesting.
-    if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow()) {
+    if (inst->IsBranch()) {
+      insn_flags_[dex_pc].SetCompileTimeInfoPoint();
+      // The compiler also needs safepoints for fall-through to loop heads.
+      // Such a loop head must be a target of a branch.
+      int32_t offset = 0;
+      bool cond, self_ok;
+      bool target_ok = GetBranchOffset(dex_pc, &offset, &cond, &self_ok);
+      DCHECK(target_ok);
+      insn_flags_[dex_pc + offset].SetCompileTimeInfoPoint();
+    } else if (inst->IsSwitch() || inst->IsThrow()) {
       insn_flags_[dex_pc].SetCompileTimeInfoPoint();
     } else if (inst->IsReturn()) {
       insn_flags_[dex_pc].SetCompileTimeInfoPointAndReturn();
@@ -1174,11 +1208,6 @@
   return os;
 }
 
-extern "C" void MethodVerifierGdbDump(MethodVerifier* v)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  v->Dump(std::cerr);
-}
-
 void MethodVerifier::Dump(std::ostream& os) {
   if (code_item_ == nullptr) {
     os << "Native method\n";
@@ -1375,7 +1404,9 @@
 
   /* Continue until no instructions are marked "changed". */
   while (true) {
-    self_->AllowThreadSuspension();
+    if (allow_thread_suspension_) {
+      self_->AllowThreadSuspension();
+    }
     // Find the first marked one. Use "start_guess" as a way to find one quickly.
     uint32_t insn_idx = start_guess;
     for (; insn_idx < insns_size; insn_idx++) {
@@ -1540,6 +1571,16 @@
   std::unique_ptr<RegisterLine> branch_line;
   std::unique_ptr<RegisterLine> fallthrough_line;
 
+  /*
+   * If we are in a constructor, and we currently have an UninitializedThis type
+   * in a register somewhere, we need to make sure it isn't overwritten.
+   */
+  bool track_uninitialized_this = false;
+  size_t uninitialized_this_loc = 0;
+  if (IsConstructor()) {
+    track_uninitialized_this = work_line_->GetUninitializedThisLoc(this, &uninitialized_this_loc);
+  }
+
   switch (inst->Opcode()) {
     case Instruction::NOP:
       /*
@@ -2014,7 +2055,11 @@
         while (0 != instance_of_idx && !insn_flags_[instance_of_idx].IsOpcode()) {
           instance_of_idx--;
         }
-        CHECK(insn_flags_[instance_of_idx].IsOpcode());
+        if (FailOrAbort(this, insn_flags_[instance_of_idx].IsOpcode(),
+                        "Unable to get previous instruction of if-eqz/if-nez for work index ",
+                        work_insn_idx_)) {
+          break;
+        }
       } else {
         break;
       }
@@ -2072,7 +2117,11 @@
             while (0 != move_idx && !insn_flags_[move_idx].IsOpcode()) {
               move_idx--;
             }
-            CHECK(insn_flags_[move_idx].IsOpcode());
+            if (FailOrAbort(this, insn_flags_[move_idx].IsOpcode(),
+                            "Unable to get previous instruction of if-eqz/if-nez for work index ",
+                            work_insn_idx_)) {
+              break;
+            }
             const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx);
             switch (move_inst->Opcode()) {
               case Instruction::MOVE_OBJECT:
@@ -2155,91 +2204,95 @@
       break;
 
     case Instruction::IGET_BOOLEAN:
-      VerifyISGet(inst, reg_types_.Boolean(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IGET_BYTE:
-      VerifyISGet(inst, reg_types_.Byte(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IGET_CHAR:
-      VerifyISGet(inst, reg_types_.Char(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IGET_SHORT:
-      VerifyISGet(inst, reg_types_.Short(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IGET:
-      VerifyISGet(inst, reg_types_.Integer(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IGET_WIDE:
-      VerifyISGet(inst, reg_types_.LongLo(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IGET_OBJECT:
-      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
+                                                    false);
       break;
 
     case Instruction::IPUT_BOOLEAN:
-      VerifyISPut(inst, reg_types_.Boolean(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IPUT_BYTE:
-      VerifyISPut(inst, reg_types_.Byte(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IPUT_CHAR:
-      VerifyISPut(inst, reg_types_.Char(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IPUT_SHORT:
-      VerifyISPut(inst, reg_types_.Short(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IPUT:
-      VerifyISPut(inst, reg_types_.Integer(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IPUT_WIDE:
-      VerifyISPut(inst, reg_types_.LongLo(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
-      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
+                                                    false);
       break;
 
     case Instruction::SGET_BOOLEAN:
-      VerifyISGet(inst, reg_types_.Boolean(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SGET_BYTE:
-      VerifyISGet(inst, reg_types_.Byte(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SGET_CHAR:
-      VerifyISGet(inst, reg_types_.Char(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SGET_SHORT:
-      VerifyISGet(inst, reg_types_.Short(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SGET:
-      VerifyISGet(inst, reg_types_.Integer(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SGET_WIDE:
-      VerifyISGet(inst, reg_types_.LongLo(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SGET_OBJECT:
-      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
+                                                    true);
       break;
 
     case Instruction::SPUT_BOOLEAN:
-      VerifyISPut(inst, reg_types_.Boolean(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SPUT_BYTE:
-      VerifyISPut(inst, reg_types_.Byte(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SPUT_CHAR:
-      VerifyISPut(inst, reg_types_.Char(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SPUT_SHORT:
-      VerifyISPut(inst, reg_types_.Short(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SPUT:
-      VerifyISPut(inst, reg_types_.Integer(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SPUT_WIDE:
-      VerifyISPut(inst, reg_types_.LongLo(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SPUT_OBJECT:
-      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
+                                                    true);
       break;
 
     case Instruction::INVOKE_VIRTUAL:
@@ -2256,8 +2309,7 @@
       if (called_method != nullptr) {
         StackHandleScope<1> hs(self_);
         Handle<mirror::ArtMethod> h_called_method(hs.NewHandle(called_method));
-        MethodHelper mh(h_called_method);
-        mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
+        mirror::Class* return_type_class = h_called_method->GetReturnType(can_load_classes_);
         if (return_type_class != nullptr) {
           return_type = &reg_types_.FromClass(h_called_method->GetReturnTypeDescriptor(),
                                               return_type_class,
@@ -2301,8 +2353,7 @@
         return_type_descriptor = called_method->GetReturnTypeDescriptor();
         StackHandleScope<1> hs(self_);
         Handle<mirror::ArtMethod> h_called_method(hs.NewHandle(called_method));
-        MethodHelper mh(h_called_method);
-        mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
+        mirror::Class* return_type_class = h_called_method->GetReturnType(can_load_classes_);
         if (return_type_class != nullptr) {
           return_type = &reg_types_.FromClass(return_type_descriptor,
                                               return_type_class,
@@ -2627,7 +2678,7 @@
                                          reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::ADD_INT_LIT16:
-    case Instruction::RSUB_INT:
+    case Instruction::RSUB_INT_LIT16:
     case Instruction::MUL_INT_LIT16:
     case Instruction::DIV_INT_LIT16:
     case Instruction::REM_INT_LIT16:
@@ -2668,34 +2719,46 @@
     // As such they use Class*/Field*/AbstractMethod* as these offsets only have
     // meaning if the class linking and resolution were successful.
     case Instruction::IGET_QUICK:
-      VerifyIGetQuick(inst, reg_types_.Integer(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true);
       break;
     case Instruction::IGET_WIDE_QUICK:
-      VerifyIGetQuick(inst, reg_types_.LongLo(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::IGET_OBJECT_QUICK:
-      VerifyIGetQuick(inst, reg_types_.JavaLangObject(false), false);
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false);
+      break;
+    case Instruction::IGET_BOOLEAN_QUICK:
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true);
+      break;
+    case Instruction::IGET_BYTE_QUICK:
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true);
+      break;
+    case Instruction::IGET_CHAR_QUICK:
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true);
+      break;
+    case Instruction::IGET_SHORT_QUICK:
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true);
       break;
     case Instruction::IPUT_QUICK:
-      VerifyIPutQuick(inst, reg_types_.Integer(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true);
       break;
     case Instruction::IPUT_BOOLEAN_QUICK:
-        VerifyIPutQuick(inst, reg_types_.Boolean(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true);
       break;
     case Instruction::IPUT_BYTE_QUICK:
-        VerifyIPutQuick(inst, reg_types_.Byte(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true);
       break;
     case Instruction::IPUT_CHAR_QUICK:
-        VerifyIPutQuick(inst, reg_types_.Char(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true);
       break;
     case Instruction::IPUT_SHORT_QUICK:
-        VerifyIPutQuick(inst, reg_types_.Short(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true);
       break;
     case Instruction::IPUT_WIDE_QUICK:
-      VerifyIPutQuick(inst, reg_types_.LongLo(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::IPUT_OBJECT_QUICK:
-      VerifyIPutQuick(inst, reg_types_.JavaLangObject(false), false);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false);
       break;
     case Instruction::INVOKE_VIRTUAL_QUICK:
     case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
@@ -2715,31 +2778,10 @@
     }
 
     /* These should never appear during verification. */
-    case Instruction::UNUSED_3E:
-    case Instruction::UNUSED_3F:
-    case Instruction::UNUSED_40:
-    case Instruction::UNUSED_41:
-    case Instruction::UNUSED_42:
-    case Instruction::UNUSED_43:
+    case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
+    case Instruction::UNUSED_F3 ... Instruction::UNUSED_FF:
     case Instruction::UNUSED_79:
     case Instruction::UNUSED_7A:
-    case Instruction::UNUSED_EF:
-    case Instruction::UNUSED_F0:
-    case Instruction::UNUSED_F1:
-    case Instruction::UNUSED_F2:
-    case Instruction::UNUSED_F3:
-    case Instruction::UNUSED_F4:
-    case Instruction::UNUSED_F5:
-    case Instruction::UNUSED_F6:
-    case Instruction::UNUSED_F7:
-    case Instruction::UNUSED_F8:
-    case Instruction::UNUSED_F9:
-    case Instruction::UNUSED_FA:
-    case Instruction::UNUSED_FB:
-    case Instruction::UNUSED_FC:
-    case Instruction::UNUSED_FD:
-    case Instruction::UNUSED_FE:
-    case Instruction::UNUSED_FF:
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_);
       break;
 
@@ -2749,6 +2791,20 @@
      */
   }  // end - switch (dec_insn.opcode)
 
+  /*
+   * If we are in a constructor, and we had an UninitializedThis type
+   * in a register somewhere, we need to make sure it wasn't overwritten.
+   */
+  if (track_uninitialized_this) {
+    bool was_invoke_direct = (inst->Opcode() == Instruction::INVOKE_DIRECT ||
+                              inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
+    if (work_line_->WasUninitializedThisOverwritten(this, uninitialized_this_loc,
+                                                    was_invoke_direct)) {
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+          << "Constructor failed to initialize this object";
+    }
+  }
+
   if (have_pending_hard_failure_) {
     if (Runtime::Current()->IsCompiler()) {
       /* When compiling, check that the last failure is a hard failure */
@@ -2930,7 +2986,7 @@
       const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx);
       Instruction::Code opcode = ret_inst->Opcode();
       if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) {
-        work_line_->MarkAllRegistersAsConflicts(this);
+        SafelyMarkAllRegistersAsConflicts(this, work_line_.get());
       } else {
         if (opcode == Instruction::RETURN_WIDE) {
           work_line_->MarkAllRegistersAsConflictsExceptWide(this, ret_inst->VRegA_11x());
@@ -3012,7 +3068,7 @@
 const RegType& MethodVerifier::GetCaughtExceptionType() {
   const RegType* common_super = nullptr;
   if (code_item_->tries_size_ != 0) {
-    const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+    const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
     uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
     for (uint32_t i = 0; i < handlers_size; i++) {
       CatchHandlerIterator iterator(handlers_ptr);
@@ -3037,7 +3093,12 @@
               // odd case, but nothing to do
             } else {
               common_super = &common_super->Merge(exception, &reg_types_);
-              CHECK(reg_types_.JavaLangThrowable(false).IsAssignableFrom(*common_super));
+              if (FailOrAbort(this,
+                              reg_types_.JavaLangThrowable(false).IsAssignableFrom(*common_super),
+                              "java.lang.Throwable is not assignable-from common_super at ",
+                              work_insn_idx_)) {
+                break;
+              }
             }
           }
         }
@@ -3134,7 +3195,7 @@
   }
   // See if the method type implied by the invoke instruction matches the access flags for the
   // target method.
-  if ((method_type == METHOD_DIRECT && !res_method->IsDirect()) ||
+  if ((method_type == METHOD_DIRECT && (!res_method->IsDirect() || res_method->IsStatic())) ||
       (method_type == METHOD_STATIC && !res_method->IsStatic()) ||
       ((method_type == METHOD_VIRTUAL || method_type == METHOD_INTERFACE) && res_method->IsDirect())
       ) {
@@ -3362,31 +3423,54 @@
   if (klass->IsInterface()) {
     // Derive Object.class from Class.class.getSuperclass().
     mirror::Class* object_klass = klass->GetClass()->GetSuperClass();
-    CHECK(object_klass->IsObjectClass());
+    if (FailOrAbort(this, object_klass->IsObjectClass(),
+                    "Failed to find Object class in quickened invoke receiver",
+                    work_insn_idx_)) {
+      return nullptr;
+    }
     dispatch_class = object_klass;
   } else {
     dispatch_class = klass;
   }
-  CHECK(dispatch_class->HasVTable()) << PrettyDescriptor(dispatch_class);
+  if (FailOrAbort(this, dispatch_class->HasVTable(),
+                  "Receiver class has no vtable for quickened invoke at ",
+                  work_insn_idx_)) {
+    return nullptr;
+  }
   uint16_t vtable_index = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
-  CHECK_LT(static_cast<int32_t>(vtable_index), dispatch_class->GetVTableLength())
-      << PrettyDescriptor(klass) << " in method "
-      << PrettyMethod(dex_method_idx_, *dex_file_, true);
+  if (FailOrAbort(this, static_cast<int32_t>(vtable_index) < dispatch_class->GetVTableLength(),
+                  "Receiver class has not enough vtable slots for quickened invoke at ",
+                  work_insn_idx_)) {
+    return nullptr;
+  }
   mirror::ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index);
-  CHECK(!self_->IsExceptionPending());
+  if (FailOrAbort(this, !self_->IsExceptionPending(),
+                  "Unexpected exception pending for quickened invoke at ",
+                  work_insn_idx_)) {
+    return nullptr;
+  }
   return res_method;
 }
 
 mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst,
                                                                 bool is_range) {
-  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
+  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_)
+      << PrettyMethod(dex_method_idx_, *dex_file_, true) << "@" << work_insn_idx_;
+
   mirror::ArtMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(),
                                                              is_range);
   if (res_method == nullptr) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name();
     return nullptr;
   }
-  CHECK(!res_method->IsDirect() && !res_method->IsStatic());
+  if (FailOrAbort(this, !res_method->IsDirect(), "Quick-invoked method is direct at ",
+                  work_insn_idx_)) {
+    return nullptr;
+  }
+  if (FailOrAbort(this, !res_method->IsStatic(), "Quick-invoked method is static at ",
+                  work_insn_idx_)) {
+    return nullptr;
+  }
 
   // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
   // match the call to the signature. Also, we might be calling through an abstract method
@@ -3751,8 +3835,9 @@
   }
 }
 
-void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_type,
-                                 bool is_primitive, bool is_static) {
+template <MethodVerifier::FieldAccessType kAccType>
+void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& insn_type,
+                                         bool is_primitive, bool is_static) {
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   mirror::ArtField* field;
   if (is_static) {
@@ -3760,85 +3845,25 @@
   } else {
     const RegType& object_type = work_line_->GetRegisterType(this, inst->VRegB_22c());
     field = GetInstanceField(object_type, field_idx);
+    if (UNLIKELY(have_pending_hard_failure_)) {
+      return;
+    }
   }
   const RegType* field_type = nullptr;
   if (field != nullptr) {
-    mirror::Class* field_type_class;
-    {
-      StackHandleScope<1> hs(self_);
-      HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
-      field_type_class = FieldHelper(h_field).GetType(can_load_classes_);
+    if (kAccType == FieldAccessType::kAccPut) {
+      if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
+        Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
+                                        << " from other class " << GetDeclaringClass();
+        return;
+      }
     }
-    if (field_type_class != nullptr) {
-      field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
-                                         field_type_class->CannotBeAssignedFromOtherTypes());
-    } else {
-      DCHECK(!can_load_classes_ || self_->IsExceptionPending());
-      self_->ClearException();
-    }
-  }
-  if (field_type == nullptr) {
-    const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
-    const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
-    field_type = &reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
-  }
-  DCHECK(field_type != nullptr);
-  const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
-  if (is_primitive) {
-    if (field_type->Equals(insn_type) ||
-        (field_type->IsFloat() && insn_type.IsInteger()) ||
-        (field_type->IsDouble() && insn_type.IsLong())) {
-      // expected that read is of the correct primitive type or that int reads are reading
-      // floats or long reads are reading doubles
-    } else {
-      // This is a global failure rather than a class change failure as the instructions and
-      // the descriptors for the type should have been consistent within the same file at
-      // compile time
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
-                                        << " to be of type '" << insn_type
-                                        << "' but found type '" << *field_type << "' in get";
-      return;
-    }
-  } else {
-    if (!insn_type.IsAssignableFrom(*field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << *field_type
-                                        << "' in Get-object";
-      work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
-      return;
-    }
-  }
-  if (!field_type->IsLowHalf()) {
-    work_line_->SetRegisterType(this, vregA, *field_type);
-  } else {
-    work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
-  }
-}
 
-void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_type,
-                                 bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
-  mirror::ArtField* field;
-  if (is_static) {
-    field = GetStaticField(field_idx);
-  } else {
-    const RegType& object_type = work_line_->GetRegisterType(this, inst->VRegB_22c());
-    field = GetInstanceField(object_type, field_idx);
-  }
-  const RegType* field_type = nullptr;
-  if (field != nullptr) {
-    if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
-      Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
-                                      << " from other class " << GetDeclaringClass();
-      return;
-    }
     mirror::Class* field_type_class;
     {
       StackHandleScope<1> hs(self_);
       HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
-      FieldHelper fh(h_field);
-      field_type_class = fh.GetType(can_load_classes_);
+      field_type_class = h_field->GetType(can_load_classes_);
     }
     if (field_type_class != nullptr) {
       field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
@@ -3855,17 +3880,56 @@
   }
   DCHECK(field_type != nullptr);
   const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
-  if (is_primitive) {
-    VerifyPrimitivePut(*field_type, insn_type, vregA);
-  } else {
-    if (!insn_type.IsAssignableFrom(*field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << *field_type
-                                        << "' in put-object";
-      return;
+  static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
+                "Unexpected third access type");
+  if (kAccType == FieldAccessType::kAccPut) {
+    // sput or iput.
+    if (is_primitive) {
+      VerifyPrimitivePut(*field_type, insn_type, vregA);
+    } else {
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                                << " to be compatible with type '" << insn_type
+                                                << "' but found type '" << *field_type
+                                                << "' in put-object";
+        return;
+      }
+      work_line_->VerifyRegisterType(this, vregA, *field_type);
     }
-    work_line_->VerifyRegisterType(this, vregA, *field_type);
+  } else if (kAccType == FieldAccessType::kAccGet) {
+    // sget or iget.
+    if (is_primitive) {
+      if (field_type->Equals(insn_type) ||
+          (field_type->IsFloat() && insn_type.IsInteger()) ||
+          (field_type->IsDouble() && insn_type.IsLong())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+                                          << " to be of type '" << insn_type
+                                          << "' but found type '" << *field_type << "' in get";
+        return;
+      }
+    } else {
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                          << " to be compatible with type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in get-object";
+        work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        return;
+      }
+    }
+    if (!field_type->IsLowHalf()) {
+      work_line_->SetRegisterType(this, vregA, *field_type);
+    } else {
+      work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
+    }
+  } else {
+    LOG(FATAL) << "Unexpected case.";
   }
 }
 
@@ -3874,6 +3938,10 @@
   DCHECK(inst->Opcode() == Instruction::IGET_QUICK ||
          inst->Opcode() == Instruction::IGET_WIDE_QUICK ||
          inst->Opcode() == Instruction::IGET_OBJECT_QUICK ||
+         inst->Opcode() == Instruction::IGET_BOOLEAN_QUICK ||
+         inst->Opcode() == Instruction::IGET_BYTE_QUICK ||
+         inst->Opcode() == Instruction::IGET_CHAR_QUICK ||
+         inst->Opcode() == Instruction::IGET_SHORT_QUICK ||
          inst->Opcode() == Instruction::IPUT_QUICK ||
          inst->Opcode() == Instruction::IPUT_WIDE_QUICK ||
          inst->Opcode() == Instruction::IPUT_OBJECT_QUICK ||
@@ -3896,131 +3964,137 @@
   return f;
 }
 
-void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
-                                     bool is_primitive) {
+template <MethodVerifier::FieldAccessType kAccType>
+void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type,
+                                            bool is_primitive) {
   DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
-  mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
-  if (field == nullptr) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
-    return;
-  }
-  mirror::Class* field_type_class;
-  {
-    StackHandleScope<1> hs(self_);
-    HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
-    FieldHelper fh(h_field);
-    field_type_class = fh.GetType(can_load_classes_);
-  }
-  const RegType* field_type;
-  if (field_type_class != nullptr) {
-    field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
-                                       field_type_class->CannotBeAssignedFromOtherTypes());
-  } else {
-    DCHECK(!can_load_classes_ || self_->IsExceptionPending());
-    self_->ClearException();
-    field_type = &reg_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
-                                            field->GetTypeDescriptor(), false);
-  }
-  DCHECK(field_type != nullptr);
-  const uint32_t vregA = inst->VRegA_22c();
-  if (is_primitive) {
-    if (field_type->Equals(insn_type) ||
-        (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
-        (field_type->IsDouble() && insn_type.IsLongTypes())) {
-      // expected that read is of the correct primitive type or that int reads are reading
-      // floats or long reads are reading doubles
-    } else {
-      // This is a global failure rather than a class change failure as the instructions and
-      // the descriptors for the type should have been consistent within the same file at
-      // compile time
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
-                                        << " to be of type '" << insn_type
-                                        << "' but found type '" << *field_type << "' in Get";
-      return;
-    }
-  } else {
-    if (!insn_type.IsAssignableFrom(*field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << *field_type
-                                        << "' in get-object";
-      work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
-      return;
-    }
-  }
-  if (!field_type->IsLowHalf()) {
-    work_line_->SetRegisterType(this, vregA, *field_type);
-  } else {
-    work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
-  }
-}
 
-void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& insn_type,
-                                     bool is_primitive) {
-  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
   mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
   if (field == nullptr) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
     return;
   }
-  const char* descriptor = field->GetTypeDescriptor();
-  mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
-  const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
-  if (field != nullptr) {
+
+  // For an IPUT_QUICK, we now test for final flag of the field.
+  if (kAccType == FieldAccessType::kAccPut) {
     if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
       Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
                                       << " from other class " << GetDeclaringClass();
       return;
     }
   }
-  const uint32_t vregA = inst->VRegA_22c();
-  if (is_primitive) {
-    // Primitive field assignability rules are weaker than regular assignability rules
-    bool instruction_compatible;
-    bool value_compatible;
-    const RegType& value_type = work_line_->GetRegisterType(this, vregA);
-    if (field_type.IsIntegralTypes()) {
-      instruction_compatible = insn_type.IsIntegralTypes();
-      value_compatible = value_type.IsIntegralTypes();
-    } else if (field_type.IsFloat()) {
-      instruction_compatible = insn_type.IsInteger();  // no [is]put-float, so expect [is]put-int
-      value_compatible = value_type.IsFloatTypes();
-    } else if (field_type.IsLong()) {
-      instruction_compatible = insn_type.IsLong();
-      value_compatible = value_type.IsLongTypes();
-    } else if (field_type.IsDouble()) {
-      instruction_compatible = insn_type.IsLong();  // no [is]put-double, so expect [is]put-long
-      value_compatible = value_type.IsDoubleTypes();
+
+  // Get the field type.
+  const RegType* field_type;
+  {
+    mirror::Class* field_type_class;
+    {
+      StackHandleScope<1> hs(Thread::Current());
+      HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
+      field_type_class = h_field->GetType(can_load_classes_);
+    }
+
+    if (field_type_class != nullptr) {
+      field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
+                                         field_type_class->CannotBeAssignedFromOtherTypes());
     } else {
-      instruction_compatible = false;  // reference field with primitive store
-      value_compatible = false;  // unused
+      Thread* self = Thread::Current();
+      DCHECK(!can_load_classes_ || self->IsExceptionPending());
+      self->ClearException();
+      field_type = &reg_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
+                                              field->GetTypeDescriptor(), false);
     }
-    if (!instruction_compatible) {
-      // This is a global failure rather than a class change failure as the instructions and
-      // the descriptors for the type should have been consistent within the same file at
-      // compile time
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
-                                        << " to be of type '" << insn_type
-                                        << "' but found type '" << field_type
-                                        << "' in put";
+    if (field_type == nullptr) {
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field type from " << inst->Name();
       return;
     }
-    if (!value_compatible) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
-          << " of type " << value_type
-          << " but expected " << field_type
-          << " for store to " << PrettyField(field) << " in put";
-      return;
+  }
+
+  const uint32_t vregA = inst->VRegA_22c();
+  static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
+                "Unexpected third access type");
+  if (kAccType == FieldAccessType::kAccPut) {
+    if (is_primitive) {
+      // Primitive field assignability rules are weaker than regular assignability rules
+      bool instruction_compatible;
+      bool value_compatible;
+      const RegType& value_type = work_line_->GetRegisterType(this, vregA);
+      if (field_type->IsIntegralTypes()) {
+        instruction_compatible = insn_type.IsIntegralTypes();
+        value_compatible = value_type.IsIntegralTypes();
+      } else if (field_type->IsFloat()) {
+        instruction_compatible = insn_type.IsInteger();  // no [is]put-float, so expect [is]put-int
+        value_compatible = value_type.IsFloatTypes();
+      } else if (field_type->IsLong()) {
+        instruction_compatible = insn_type.IsLong();
+        value_compatible = value_type.IsLongTypes();
+      } else if (field_type->IsDouble()) {
+        instruction_compatible = insn_type.IsLong();  // no [is]put-double, so expect [is]put-long
+        value_compatible = value_type.IsDoubleTypes();
+      } else {
+        instruction_compatible = false;  // reference field with primitive store
+        value_compatible = false;  // unused
+      }
+      if (!instruction_compatible) {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+                                          << " to be of type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in put";
+        return;
+      }
+      if (!value_compatible) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
+            << " of type " << value_type
+            << " but expected " << *field_type
+            << " for store to " << PrettyField(field) << " in put";
+        return;
+      }
+    } else {
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                          << " to be compatible with type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in put-object";
+        return;
+      }
+      work_line_->VerifyRegisterType(this, vregA, *field_type);
+    }
+  } else if (kAccType == FieldAccessType::kAccGet) {
+    if (is_primitive) {
+      if (field_type->Equals(insn_type) ||
+          (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
+          (field_type->IsDouble() && insn_type.IsLongTypes())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+                                          << " to be of type '" << insn_type
+                                          << "' but found type '" << *field_type << "' in Get";
+        return;
+      }
+    } else {
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                          << " to be compatible with type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in get-object";
+        work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        return;
+      }
+    }
+    if (!field_type->IsLowHalf()) {
+      work_line_->SetRegisterType(this, vregA, *field_type);
+    } else {
+      work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
     }
   } else {
-    if (!insn_type.IsAssignableFrom(field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << field_type
-                                        << "' in put-object";
-      return;
-    }
-    work_line_->VerifyRegisterType(this, vregA, field_type);
+    LOG(FATAL) << "Unexpected case.";
   }
 }
 
@@ -4067,7 +4141,7 @@
       const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
       Instruction::Code opcode = ret_inst->Opcode();
       if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) {
-        target_line->MarkAllRegistersAsConflicts(this);
+        SafelyMarkAllRegistersAsConflicts(this, target_line);
       } else {
         target_line->CopyFromLine(merge_line);
         if (opcode == Instruction::RETURN_WIDE) {
@@ -4112,9 +4186,7 @@
 const RegType& MethodVerifier::GetMethodReturnType() {
   if (return_type_ == nullptr) {
     if (mirror_method_.Get() != nullptr) {
-      StackHandleScope<1> hs(self_);
-      mirror::Class* return_type_class =
-          MethodHelper(hs.NewHandle(mirror_method_.Get())).GetReturnType(can_load_classes_);
+      mirror::Class* return_type_class = mirror_method_->GetReturnType(can_load_classes_);
       if (return_type_class != nullptr) {
         return_type_ = &reg_types_.FromClass(mirror_method_->GetReturnTypeDescriptor(),
                                              return_type_class,
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 9f5efe8..b83e647 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -18,32 +18,26 @@
 #define ART_RUNTIME_VERIFIER_METHOD_VERIFIER_H_
 
 #include <memory>
-#include <set>
 #include <vector>
 
-#include "base/casts.h"
 #include "base/macros.h"
-#include "base/stl_util.h"
-#include "class_reference.h"
 #include "dex_file.h"
-#include "dex_instruction.h"
 #include "handle.h"
 #include "instruction_flags.h"
 #include "method_reference.h"
-#include "reg_type.h"
 #include "reg_type_cache.h"
-#include "register_line.h"
-#include "safe_map.h"
 
 namespace art {
 
+class Instruction;
 struct ReferenceMap2Visitor;
-template<class T> class Handle;
 
 namespace verifier {
 
-class MethodVerifier;
 class DexPcToReferenceMap;
+class MethodVerifier;
+class RegisterLine;
+class RegType;
 
 /*
  * "Direct" and "virtual" methods are stored independently. The type of call used to invoke the
@@ -128,6 +122,8 @@
  private:
   std::unique_ptr<RegisterLine*[]> register_lines_;
   size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(PcToRegisterLineTable);
 };
 
 // The verifier
@@ -211,10 +207,11 @@
                  const DexFile::CodeItem* code_item, uint32_t method_idx,
                  Handle<mirror::ArtMethod> method,
                  uint32_t access_flags, bool can_load_classes, bool allow_soft_failures,
-                 bool need_precise_constants) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+                 bool need_precise_constants, bool allow_thread_suspension)
+          SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : MethodVerifier(self, dex_file, dex_cache, class_loader, class_def, code_item, method_idx,
                        method, access_flags, can_load_classes, allow_soft_failures,
-                       need_precise_constants, false) {}
+                       need_precise_constants, false, allow_thread_suspension) {}
 
   ~MethodVerifier();
 
@@ -242,6 +239,20 @@
   bool HasFailures() const;
   const RegType& ResolveCheckedClass(uint32_t class_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
+                                           RegisterLine* reg_line,
+                                           bool is_range)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Is the method being verified a constructor?
+  bool IsConstructor() const {
+    return (method_access_flags_ & kAccConstructor) != 0;
+  }
+
+  // Is the method verified static?
+  bool IsStatic() const {
+    return (method_access_flags_ & kAccStatic) != 0;
+  }
 
  private:
   // Private constructor for dumping.
@@ -250,7 +261,7 @@
                  const DexFile::CodeItem* code_item, uint32_t method_idx,
                  Handle<mirror::ArtMethod> method, uint32_t access_flags,
                  bool can_load_classes, bool allow_soft_failures, bool need_precise_constants,
-                 bool verify_to_dump)
+                 bool verify_to_dump, bool allow_thread_suspension)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Adds the given string to the beginning of the last failure message.
@@ -511,14 +522,14 @@
   // Lookup static field and fail for resolution violations
   mirror::ArtField* GetStaticField(int field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Perform verification of an iget or sget instruction.
-  void VerifyISGet(const Instruction* inst, const RegType& insn_type,
-                   bool is_primitive, bool is_static)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Perform verification of an iput or sput instruction.
-  void VerifyISPut(const Instruction* inst, const RegType& insn_type,
-                   bool is_primitive, bool is_static)
+  // Perform verification of an iget/sget/iput/sput instruction.
+  enum class FieldAccessType {  // private
+    kAccGet,
+    kAccPut
+  };
+  template <FieldAccessType kAccType>
+  void VerifyISFieldAccess(const Instruction* inst, const RegType& insn_type,
+                           bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns the access field of a quick field access (iget/iput-quick) or nullptr
@@ -526,14 +537,8 @@
   mirror::ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Perform verification of an iget-quick instruction.
-  void VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
-                       bool is_primitive)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Perform verification of an iput-quick instruction.
-  void VerifyIPutQuick(const Instruction* inst, const RegType& insn_type,
-                       bool is_primitive)
+  template <FieldAccessType kAccType>
+  void VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type, bool is_primitive)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolves a class based on an index and performs access checks to ensure the referrer can
@@ -596,11 +601,6 @@
                                                       mirror::ArtMethod* res_method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
-                                           RegisterLine* reg_line,
-                                           bool is_range)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   mirror::ArtMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range)
   SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -636,16 +636,6 @@
   bool UpdateRegisters(uint32_t next_insn, RegisterLine* merge_line, bool update_merge_line)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Is the method being verified a constructor?
-  bool IsConstructor() const {
-    return (method_access_flags_ & kAccConstructor) != 0;
-  }
-
-  // Is the method verified static?
-  bool IsStatic() const {
-    return (method_access_flags_ & kAccStatic) != 0;
-  }
-
   // Return the register type for the method.
   const RegType& GetMethodReturnType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -739,6 +729,13 @@
   // even though we might detect to be a compiler. Should only be set when running
   // VerifyMethodAndDump.
   const bool verify_to_dump_;
+
+  // Whether or not we call AllowThreadSuspension periodically, we want a way to disable this for
+  // thread dumping checkpoints since we may get thread suspension at an inopportune time due to
+  // FindLocksAtDexPC, resulting in deadlocks.
+  const bool allow_thread_suspension_;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodVerifier);
 };
 std::ostream& operator<<(std::ostream& os, const MethodVerifier::FailureKind& rhs);
 
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 770ca7e..f67adc1 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -41,14 +41,12 @@
         << error_msg;
   }
 
-  void VerifyDexFile(const DexFile* dex)
+  void VerifyDexFile(const DexFile& dex)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ASSERT_TRUE(dex != NULL);
-
     // Verify all the classes defined in this file
-    for (size_t i = 0; i < dex->NumClassDefs(); i++) {
-      const DexFile::ClassDef& class_def = dex->GetClassDef(i);
-      const char* descriptor = dex->GetClassDescriptor(class_def);
+    for (size_t i = 0; i < dex.NumClassDefs(); i++) {
+      const DexFile::ClassDef& class_def = dex.GetClassDef(i);
+      const char* descriptor = dex.GetClassDescriptor(class_def);
       VerifyClass(descriptor);
     }
   }
@@ -56,7 +54,8 @@
 
 TEST_F(MethodVerifierTest, LibCore) {
   ScopedObjectAccess soa(Thread::Current());
-  VerifyDexFile(java_lang_dex_file_);
+  ASSERT_TRUE(java_lang_dex_file_ != nullptr);
+  VerifyDexFile(*java_lang_dex_file_);
 }
 
 }  // namespace verifier
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index 480ed40..f445132 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -81,6 +81,9 @@
       return rhs.IsLongTypes();
     } else if (lhs.IsDoubleLo()) {
       return rhs.IsDoubleTypes();
+    } else if (lhs.IsConflict()) {
+      LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!";
+      return false;
     } else {
       CHECK(lhs.IsReferenceTypes())
           << "Unexpected register type in IsAssignableFrom: '"
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 41541b5..3510665 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -779,9 +779,7 @@
 }
 
 void RegType::VisitRoots(RootCallback* callback, void* arg) const {
-  if (!klass_.IsNull()) {
-    callback(reinterpret_cast<mirror::Object**>(&klass_), arg, 0, kRootUnknown);
-  }
+  klass_.VisitRootIfNonNull(callback, arg, RootInfo(kRootUnknown));
 }
 
 void UninitializedThisReferenceType::CheckInvariants() const {
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 34d6caa..05958b5 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -17,17 +17,14 @@
 #ifndef ART_RUNTIME_VERIFIER_REG_TYPE_H_
 #define ART_RUNTIME_VERIFIER_REG_TYPE_H_
 
-#include <limits>
 #include <stdint.h>
+#include <limits>
 #include <set>
 #include <string>
 
-#include "jni.h"
-
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "gc_root.h"
-#include "globals.h"
 #include "object_callbacks.h"
 #include "primitive.h"
 
@@ -35,6 +32,7 @@
 namespace mirror {
 class Class;
 }  // namespace mirror
+
 namespace verifier {
 
 class RegTypeCache;
@@ -578,17 +576,17 @@
 
   bool IsConstantChar() const OVERRIDE {
     return IsConstant() && ConstantValue() >= 0 &&
-           ConstantValue() <= std::numeric_limits<jchar>::max();
+           ConstantValue() <= std::numeric_limits<uint16_t>::max();
   }
   bool IsConstantByte() const OVERRIDE {
     return IsConstant() &&
-           ConstantValue() >= std::numeric_limits<jbyte>::min() &&
-           ConstantValue() <= std::numeric_limits<jbyte>::max();
+           ConstantValue() >= std::numeric_limits<int8_t>::min() &&
+           ConstantValue() <= std::numeric_limits<int8_t>::max();
   }
   bool IsConstantShort() const OVERRIDE {
     return IsConstant() &&
-           ConstantValue() >= std::numeric_limits<jshort>::min() &&
-           ConstantValue() <= std::numeric_limits<jshort>::max();
+           ConstantValue() >= std::numeric_limits<int16_t>::min() &&
+           ConstantValue() <= std::numeric_limits<int16_t>::max();
   }
   virtual bool IsConstantTypes() const OVERRIDE { return true; }
 
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 7c40945..1dfbe51 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -148,7 +148,8 @@
   if (can_load_classes_) {
     klass = class_linker->FindClass(self, descriptor, class_loader);
   } else {
-    klass = class_linker->LookupClass(self, descriptor, loader);
+    klass = class_linker->LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor),
+                                      loader);
     if (klass != nullptr && !klass->IsLoaded()) {
       // We found the class but without it being loaded its not safe for use.
       klass = nullptr;
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 219e687..244deed 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -114,6 +114,17 @@
   }
 }
 
+inline size_t RegisterLine::GetMaxNonZeroReferenceReg(MethodVerifier* verifier,
+                                                      size_t max_ref_reg) const {
+  size_t i = static_cast<int>(max_ref_reg) < 0 ? 0 : max_ref_reg;
+  for (; i < num_regs_; i++) {
+    if (GetRegisterType(verifier, i).IsNonZeroReferenceTypes()) {
+      max_ref_reg = i;
+    }
+  }
+  return max_ref_reg;
+}
+
 inline bool RegisterLine::VerifyRegisterType(MethodVerifier* verifier, uint32_t vsrc,
                                              const RegType& check_type) {
   // Verify the src register type against the check type refining the type of the register
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 3139204..3b09871 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -25,6 +25,49 @@
 namespace art {
 namespace verifier {
 
+bool RegisterLine::WasUninitializedThisOverwritten(MethodVerifier* verifier,
+                                                   size_t this_loc,
+                                                   bool was_invoke_direct) const {
+  DCHECK(verifier->IsConstructor());
+
+  // Is the UnintializedThis type still there?
+  if (GetRegisterType(verifier, this_loc).IsUninitializedThisReference() ||
+      GetRegisterType(verifier, this_loc).IsUnresolvedAndUninitializedThisReference()) {
+    return false;
+  }
+
+  // If there is an initialized reference here now, did we just perform an invoke-direct? Note that
+  // this is the correct approach for dex bytecode: results of invoke-direct are stored in the
+  // result register. Overwriting "this_loc" can only be done by a constructor call.
+  if (GetRegisterType(verifier, this_loc).IsReferenceTypes() && was_invoke_direct) {
+    return false;
+    // Otherwise we could have just copied a different initialized reference to this location.
+  }
+
+  // The UnintializedThis in the register is gone, so check to see if it's somewhere else now.
+  for (size_t i = 0; i < num_regs_; i++) {
+    if (GetRegisterType(verifier, i).IsUninitializedThisReference() ||
+        GetRegisterType(verifier, i).IsUnresolvedAndUninitializedThisReference()) {
+      // We found it somewhere else...
+      return false;
+    }
+  }
+
+  // The UninitializedThis is gone from the original register, and now we can't find it.
+  return true;
+}
+
+bool RegisterLine::GetUninitializedThisLoc(MethodVerifier* verifier, size_t* vreg) const {
+  for (size_t i = 0; i < num_regs_; i++) {
+    if (GetRegisterType(verifier, i).IsUninitializedThisReference() ||
+        GetRegisterType(verifier, i).IsUnresolvedAndUninitializedThisReference()) {
+      *vreg = i;
+      return true;
+    }
+  }
+  return false;
+}
+
 bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const {
   for (size_t i = 0; i < num_regs_; i++) {
     if (GetRegisterType(verifier, i).IsUninitializedThisReference() ||
@@ -310,8 +353,12 @@
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter stack overflow: "
         << monitors_.size();
   } else {
-    SetRegToLockDepth(reg_idx, monitors_.size());
-    monitors_.push_back(insn_idx);
+    if (SetRegToLockDepth(reg_idx, monitors_.size())) {
+      monitors_.push_back(insn_idx);
+    } else {
+      verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected monitor-enter on register v" <<
+          reg_idx;
+    }
   }
 }
 
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index c7fd369..ca61a0b 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -20,14 +20,16 @@
 #include <memory>
 #include <vector>
 
-#include "dex_instruction.h"
-#include "reg_type.h"
 #include "safe_map.h"
 
 namespace art {
+
+class Instruction;
+
 namespace verifier {
 
 class MethodVerifier;
+class RegType;
 
 /*
  * Register type categories, for type checking.
@@ -118,9 +120,7 @@
 
   void FillWithGarbage() {
     memset(&line_, 0xf1, num_regs_ * sizeof(uint16_t));
-    while (!monitors_.empty()) {
-      monitors_.pop_back();
-    }
+    monitors_.clear();
     reg_to_lock_depths_.clear();
   }
 
@@ -157,6 +157,18 @@
    */
   bool CheckConstructorReturn(MethodVerifier* verifier) const;
 
+  /*
+   * Check if an UninitializedThis at the specified location has been overwritten before
+   * being correctly initialized.
+   */
+  bool WasUninitializedThisOverwritten(MethodVerifier* verifier, size_t this_loc,
+                                       bool was_invoke_direct) const;
+
+  /*
+   * Get the first location of an UninitializedThis type, or return kInvalidVreg if there are none.
+   */
+  bool GetUninitializedThisLoc(MethodVerifier* verifier, size_t* vreg) const;
+
   // Compare two register lines. Returns 0 if they match.
   // Using this for a sort is unwise, since the value can change based on machine endianness.
   int CompareLine(const RegisterLine* line2) const {
@@ -277,15 +289,7 @@
   bool MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  size_t GetMaxNonZeroReferenceReg(MethodVerifier* verifier, size_t max_ref_reg) {
-    size_t i = static_cast<int>(max_ref_reg) < 0 ? 0 : max_ref_reg;
-    for (; i < num_regs_; i++) {
-      if (GetRegisterType(verifier, i).IsNonZeroReferenceTypes()) {
-        max_ref_reg = i;
-      }
-    }
-    return max_ref_reg;
-  }
+  size_t GetMaxNonZeroReferenceReg(MethodVerifier* verifier, size_t max_ref_reg) const;
 
   // Write a bit at each register location that holds a reference.
   void WriteReferenceBitMap(MethodVerifier* verifier, std::vector<uint8_t>* data, size_t max_bytes);
@@ -315,15 +319,18 @@
     }
   }
 
-  void SetRegToLockDepth(size_t reg, size_t depth) {
+  bool SetRegToLockDepth(size_t reg, size_t depth) {
     CHECK_LT(depth, 32u);
-    DCHECK(!IsSetLockDepth(reg, depth));
+    if (IsSetLockDepth(reg, depth)) {
+      return false;  // Register already holds lock so locking twice is erroneous.
+    }
     auto it = reg_to_lock_depths_.find(reg);
     if (it == reg_to_lock_depths_.end()) {
       reg_to_lock_depths_.Put(reg, 1 << depth);
     } else {
       it->second |= (1 << depth);
     }
+    return true;
   }
 
   void ClearRegToLockDepth(size_t reg, size_t depth) {
@@ -349,21 +356,23 @@
     SetResultTypeToUnknown(verifier);
   }
 
-  // Storage for the result register's type, valid after an invocation
+  // Storage for the result register's type, valid after an invocation.
   uint16_t result_[2];
 
   // Length of reg_types_
   const uint32_t num_regs_;
 
-  // A stack of monitor enter locations
+  // A stack of monitor enter locations.
   std::vector<uint32_t, TrackingAllocator<uint32_t, kAllocatorTagVerifier>> monitors_;
   // A map from register to a bit vector of indices into the monitors_ stack. As we pop the monitor
   // stack we verify that monitor-enter/exit are correctly nested. That is, if there was a
-  // monitor-enter on v5 and then on v6, we expect the monitor-exit to be on v6 then on v5
+  // monitor-enter on v5 and then on v6, we expect the monitor-exit to be on v6 then on v5.
   AllocationTrackingSafeMap<uint32_t, uint32_t, kAllocatorTagVerifier> reg_to_lock_depths_;
 
   // An array of RegType Ids associated with each dex register.
   uint16_t line_[0];
+
+  DISALLOW_COPY_AND_ASSIGN(RegisterLine);
 };
 
 }  // namespace verifier
diff --git a/runtime/vmap_table.h b/runtime/vmap_table.h
index df5cd80..db9e1ea 100644
--- a/runtime/vmap_table.h
+++ b/runtime/vmap_table.h
@@ -65,7 +65,7 @@
     uint16_t adjusted_vreg = vreg + kEntryAdjustment;
     size_t end = DecodeUnsignedLeb128(&table);
     bool high_reg = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
-    bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64);
+    bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64) || (kRuntimeISA == kMips64);
     if (target64 && high_reg) {
       // Wide promoted registers are associated with the sreg of the low portion.
       adjusted_vreg--;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 4a3c3ec..e368d2c 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;
@@ -63,9 +66,9 @@
 jmethodID WellKnownClasses::java_lang_Character_valueOf;
 jmethodID WellKnownClasses::java_lang_ClassLoader_loadClass;
 jmethodID WellKnownClasses::java_lang_ClassNotFoundException_init;
-jmethodID WellKnownClasses::java_lang_Daemons_requestGC;
 jmethodID WellKnownClasses::java_lang_Daemons_requestHeapTrim;
 jmethodID WellKnownClasses::java_lang_Daemons_start;
+jmethodID WellKnownClasses::java_lang_Daemons_stop;
 jmethodID WellKnownClasses::java_lang_Double_valueOf;
 jmethodID WellKnownClasses::java_lang_Float_valueOf;
 jmethodID WellKnownClasses::java_lang_Integer_valueOf;
@@ -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");
@@ -196,9 +204,9 @@
   java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
   java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
 
-  java_lang_Daemons_requestGC = CacheMethod(env, java_lang_Daemons, true, "requestGC", "()V");
   java_lang_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V");
   java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V");
+  java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V");
 
   ScopedLocalRef<jclass> java_lang_ref_FinalizerReference(env, env->FindClass("java/lang/ref/FinalizerReference"));
   java_lang_ref_FinalizerReference_add = CacheMethod(env, java_lang_ref_FinalizerReference.get(), true, "add", "(Ljava/lang/Object;)V");
@@ -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..1a4f0f8 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;
@@ -76,9 +77,9 @@
   static jmethodID java_lang_Character_valueOf;
   static jmethodID java_lang_ClassLoader_loadClass;
   static jmethodID java_lang_ClassNotFoundException_init;
-  static jmethodID java_lang_Daemons_requestGC;
   static jmethodID java_lang_Daemons_requestHeapTrim;
   static jmethodID java_lang_Daemons_start;
+  static jmethodID java_lang_Daemons_stop;
   static jmethodID java_lang_Double_valueOf;
   static jmethodID java_lang_Float_valueOf;
   static jmethodID java_lang_Integer_valueOf;
@@ -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/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc
index 96abee2..70a4dda 100644
--- a/runtime/zip_archive_test.cc
+++ b/runtime/zip_archive_test.cc
@@ -41,7 +41,7 @@
 
   ScratchFile tmp;
   ASSERT_NE(-1, tmp.GetFd());
-  std::unique_ptr<File> file(new File(tmp.GetFd(), tmp.GetFilename()));
+  std::unique_ptr<File> file(new File(tmp.GetFd(), tmp.GetFilename(), false));
   ASSERT_TRUE(file.get() != NULL);
   bool success = zip_entry->ExtractToFile(*file, &error_msg);
   ASSERT_TRUE(success) << error_msg;
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
index d86735d..35dec4b 100644
--- a/sigchainlib/Android.mk
+++ b/sigchainlib/Android.mk
@@ -22,13 +22,27 @@
 LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+LOCAL_SRC_FILES := sigchain_dummy.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
+$(eval $(call set-target-local-clang-vars))
+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 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)
+$(eval $(call set-target-local-clang-vars))
+include $(BUILD_STATIC_LIBRARY)
 
 # Build host library.
 include $(CLEAR_VARS)
@@ -37,9 +51,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..2eb518c 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,21 +149,34 @@
   }
 }
 
-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
   // number should behave exactly as the libc sigaction.
   if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
-    if (old_action != NULL) {
-      *old_action = user_sigactions[signal].GetAction();
-    }
+    struct sigaction saved_action = user_sigactions[signal].GetAction();
     if (new_action != NULL) {
       user_sigactions[signal].SetAction(*new_action, false);
     }
+    if (old_action != NULL) {
+      *old_action = saved_action;
+    }
     return 0;
   }
 
@@ -181,13 +195,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 +238,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 +270,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 +301,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..76779ab
--- /dev/null
+++ b/sigchainlib/sigchain_dummy.cc
@@ -0,0 +1,76 @@
+/*
+ * 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"
+
+#define ATTRIBUTE_UNUSED __attribute__((__unused__))
+
+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);
+}
+
+namespace art {
+
+
+extern "C" void ClaimSignalChain(int signal ATTRIBUTE_UNUSED,
+                                 struct sigaction* oldaction ATTRIBUTE_UNUSED) {
+  log("ClaimSignalChain is not exported by the main executable.");
+  abort();
+}
+
+extern "C" void UnclaimSignalChain(int signal ATTRIBUTE_UNUSED) {
+  log("UnclaimSignalChain is not exported by the main executable.");
+  abort();
+}
+
+extern "C" void InvokeUserSignalHandler(int sig ATTRIBUTE_UNUSED,
+                                        siginfo_t* info ATTRIBUTE_UNUSED,
+                                        void* context ATTRIBUTE_UNUSED) {
+  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 ATTRIBUTE_UNUSED,
+                                   struct sigaction* expected_action ATTRIBUTE_UNUSED) {
+  log("EnsureFrontOfChain is not exported by the main executable.");
+  abort();
+}
+
+}  // namespace art
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-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index 6fc4484..544cbc5 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -172,7 +172,7 @@
 constexpr size_t kByteReturnSize = 7;
 jbyte byte_returns[kByteReturnSize] = { 0, 1, 2, 127, -1, -2, -128 };
 
-extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2,
+extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv*, jclass, jbyte b1, jbyte b2,
                                               jbyte b3, jbyte b4, jbyte b5, jbyte b6,
                                               jbyte b7, jbyte b8, jbyte b9, jbyte b10) {
   // We use b1 to drive the output.
@@ -197,7 +197,7 @@
     static_cast<jshort>(0x8000) };
 // The weird static_cast is because short int is only guaranteed down to -32767, not Java's -32768.
 
-extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2,
+extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv*, jclass, jshort s1, jshort s2,
                                                 jshort s3, jshort s4, jshort s5, jshort s6,
                                                 jshort s7, jshort s8, jshort s9, jshort s10) {
   // We use s1 to drive the output.
@@ -217,7 +217,7 @@
   return short_returns[s1];
 }
 
-extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1,
+extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv*, jclass, jboolean b1,
                                                     jboolean b2, jboolean b3, jboolean b4,
                                                     jboolean b5, jboolean b6, jboolean b7,
                                                     jboolean b8, jboolean b9, jboolean b10) {
@@ -239,7 +239,7 @@
 constexpr size_t kCharReturnSize = 8;
 jchar char_returns[kCharReturnSize] = { 0, 1, 2, 127, 255, 256, 15000, 34000 };
 
-extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv* env, jclass klacc, jchar c1, jchar c2,
+extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv*, jclass, jchar c1, jchar c2,
                                               jchar c3, jchar c4, jchar c5, jchar c6, jchar c7,
                                               jchar c8, jchar c9, jchar c10) {
   // We use c1 to drive the output.
@@ -294,25 +294,25 @@
     assert(!env->ExceptionCheck());
 
     // Create a string object.
-    jobject library_string = env->NewStringUTF("arttest");
+    jobject library_string = env->NewStringUTF("non_existing_library");
     assert(library_string != nullptr);
     assert(!env->ExceptionCheck());
 
     env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string);
-    if (env->ExceptionCheck()) {
-      // At most we expect UnsatisfiedLinkError.
-      jthrowable thrown = env->ExceptionOccurred();
-      env->ExceptionClear();
+    assert(env->ExceptionCheck());
 
-      jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
-      jclass thrown_class = env->GetObjectClass(thrown);
-      assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
-    }
+    // We expect UnsatisfiedLinkError.
+    jthrowable thrown = env->ExceptionOccurred();
+    env->ExceptionClear();
+
+    jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
+    jclass thrown_class = env->GetObjectClass(thrown);
+    assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
   }
 }
 
 // http://b/16867274
-extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetCallingClassLoader(JNIEnv* env,
+extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetCallingClassLoader(JNIEnv*,
                                                                                    jclass) {
   PthreadHelper(&testShallowGetCallingClassLoader);
 }
@@ -350,7 +350,7 @@
   // ourselves.
 }
 
-extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetStackClass2(JNIEnv* env, jclass) {
+extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetStackClass2(JNIEnv*, jclass) {
   PthreadHelper(&testShallowGetStackClass2);
 }
 
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index e914bd9..40be56c 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -19,10 +19,13 @@
 
 namespace art {
 
-#define CHECK_REGS_CONTAIN_REFS(native_pc_offset, ...) do { \
+#define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \
   int t[] = {__VA_ARGS__}; \
   int t_size = sizeof(t) / sizeof(*t); \
-  CheckReferences(t, t_size, m->NativePcOffset(m->ToNativePc(native_pc_offset))); \
+  uintptr_t native_quick_pc = m->ToNativeQuickPc(dex_pc, abort_if_not_found); \
+  if (native_quick_pc != UINTPTR_MAX) { \
+    CheckReferences(t, t_size, m->NativeQuickPcOffset(native_quick_pc)); \
+  } \
 } while (false);
 
 struct ReferenceMap2Visitor : public CheckReferenceMapVisitor {
@@ -40,31 +43,35 @@
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
     if (m_name.compare("f") == 0) {
-      CHECK_REGS_CONTAIN_REFS(0x03U, 8);  // v8: this
-      CHECK_REGS_CONTAIN_REFS(0x06U, 8, 1);  // v8: this, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x08U, 8, 3, 1);  // v8: this, v3: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x0cU, 8, 3, 1);  // v8: this, v3: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x0eU, 8, 3, 1);  // v8: this, v3: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x10U, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x03U, true, 8);  // v8: this
+      CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1);  // v8: this, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x08U, true, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x0eU, true, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1);  // v8: this, v3: y, v1: x
       // v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See:
       //   0024: move-object v3, v2
       //   0025: goto 0013
-      // Detaled dex instructions for ReferenceMap.java are at the end of this function.
+      // Detailed dex instructions for ReferenceMap.java are at the end of this function.
       // CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1);  // v8: this, v3: y, v2: y, v1: x
-      // We eliminate the non-live registers at a return, so only v3 is live:
-      CHECK_REGS_CONTAIN_REFS(0x13U);  // v3: y
-      CHECK_REGS_CONTAIN_REFS(0x18U, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
-      CHECK_REGS_CONTAIN_REFS(0x1aU, 8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
-      CHECK_REGS_CONTAIN_REFS(0x1dU, 8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
+      // We eliminate the non-live registers at a return, so only v3 is live.
+      // Note that it is OK for a compiler to not have a dex map at this dex PC because
+      // a return is not necessarily a safepoint.
+      CHECK_REGS_CONTAIN_REFS(0x13U, false);  // v3: y
+      CHECK_REGS_CONTAIN_REFS(0x18U, true, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x1aU, true, 8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x1dU, true, 8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
       // v5 is removed from the root set because there is a "merge" operation.
       // See 0015: if-nez v2, 001f.
-      CHECK_REGS_CONTAIN_REFS(0x1fU, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
-      CHECK_REGS_CONTAIN_REFS(0x21U, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
-      CHECK_REGS_CONTAIN_REFS(0x27U, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x29U, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x2cU, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x2fU, 8, 4, 3, 2, 1);  // v8: this, v4: ex, v3: y, v2: y, v1: x
-      CHECK_REGS_CONTAIN_REFS(0x32U, 8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x1fU, true, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x21U, true, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x27U, true, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x29U, true, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x2cU, true, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
+      // Note that it is OK for a compiler to not have a dex map at these two dex PCs because
+      // a goto is not necessarily a safepoint.
+      CHECK_REGS_CONTAIN_REFS(0x2fU, false, 8, 4, 3, 2, 1);  // v8: this, v4: ex, v3: y, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x32U, false, 8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
     }
 
     return true;
diff --git a/test/004-SignalTest/signaltest.cc b/test/004-SignalTest/signaltest.cc
index a6d9b66..31371f6 100644
--- a/test/004-SignalTest/signaltest.cc
+++ b/test/004-SignalTest/signaltest.cc
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
+#include <jni.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/ucontext.h>
 #include <unistd.h>
 
-#include "jni.h"
-
-#include <sys/ucontext.h>
+#include "base/macros.h"
 
 static int signal_count;
 static const int kMaxSignal = 2;
@@ -47,7 +47,8 @@
 #endif
 #endif
 
-static void signalhandler(int sig, siginfo_t* info, void* context) {
+static void signalhandler(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
+                          void* context) {
   printf("signal caught\n");
   ++signal_count;
   if (signal_count > kMaxSignal) {
diff --git a/test/004-SignalTest/src/Main.java b/test/004-SignalTest/src/Main.java
index 0391592..8b1f49b 100644
--- a/test/004-SignalTest/src/Main.java
+++ b/test/004-SignalTest/src/Main.java
@@ -20,7 +20,7 @@
     private static native int testSignal();
 
     private static void stackOverflow() {
-       stackOverflow();
+        stackOverflow();
     }
 
     public static void main(String[] args) {
@@ -40,7 +40,6 @@
         }
         try {
             stackOverflow();
-
             // Should never get here.
             throw new AssertionError();
         } catch (StackOverflowError e) {
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/005-annotations/build b/test/005-annotations/build
index 1690213..2474055 100644
--- a/test/005-annotations/build
+++ b/test/005-annotations/build
@@ -23,5 +23,6 @@
 ${JAVAC} -d classes `find src -name '*.java'`
 
 # ...but not at run time.
-rm classes/android/test/anno/MissingAnnotation.class
+rm 'classes/android/test/anno/MissingAnnotation.class'
+rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class'
 ${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
diff --git a/test/005-annotations/src/android/test/anno/ClassWithInnerAnnotationClass.java b/test/005-annotations/src/android/test/anno/ClassWithInnerAnnotationClass.java
new file mode 100644
index 0000000..c69e01a
--- /dev/null
+++ b/test/005-annotations/src/android/test/anno/ClassWithInnerAnnotationClass.java
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.*;
+
+public class ClassWithInnerAnnotationClass {
+  @Retention(RetentionPolicy.SOURCE)
+  public @interface MissingInnerAnnotationClass {}
+}
diff --git a/test/005-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java
index 4eabb12..1deff33 100644
--- a/test/005-annotations/src/android/test/anno/TestAnnotations.java
+++ b/test/005-annotations/src/android/test/anno/TestAnnotations.java
@@ -149,26 +149,24 @@
 
         testArrays();
         testArrayProblem();
-        //System.exit(0);
 
         System.out.println(
             "AnnoSimpleField " + AnnoSimpleField.class.isAnnotation() +
             ", SimplyNoted " + SimplyNoted.class.isAnnotation());
 
-        Class clazz;
-        clazz = SimplyNoted.class;
-        printAnnotations(clazz);
-        clazz = INoted.class;
-        printAnnotations(clazz);
-        clazz = SubNoted.class;
-        printAnnotations(clazz);
-        clazz = FullyNoted.class;
-        printAnnotations(clazz);
+        printAnnotations(SimplyNoted.class);
+        printAnnotations(INoted.class);
+        printAnnotations(SubNoted.class);
+        printAnnotations(FullyNoted.class);
 
-        Annotation anno;
+        try {
+            ClassWithInnerAnnotationClass.class.getDeclaredClasses();
+            throw new AssertionError();
+        } catch (NoClassDefFoundError expected) {
+        }
 
         // this is expected to be non-null
-        anno = SimplyNoted.class.getAnnotation(AnnoSimpleType.class);
+        Annotation anno = SimplyNoted.class.getAnnotation(AnnoSimpleType.class);
         System.out.println("SimplyNoted.get(AnnoSimpleType) = " + anno);
         // this is non-null if the @Inherited tag is present
         anno = SubNoted.class.getAnnotation(AnnoSimpleType.class);
diff --git a/test/015-switch/expected.txt b/test/015-switch/expected.txt
index 91b4714..be6d2ca 100644
--- a/test/015-switch/expected.txt
+++ b/test/015-switch/expected.txt
@@ -1,3 +1,119 @@
+packed
+default
+default
+0
+1
+2
+default
+default
+packed2
+-2
+-1
+0
+1
+2
+default
+default
+packed3
+default
+default
+default
+default
+2
+3
+4
+5
+6
+default
+default
+packed4
+default
+2147483646
+2147483647
+default
+packed5
+-2147483648
+-2147483647
+default
+packed6
+-2147483648
+default
+packed7
+default
+default
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+default
+sparse
+default
+default
+0
+1
+default
+3
+default
+default
+sparse2
+-2
+-1
+0
+default
+2
+default
+default
+sparse3
+default
+default
+default
+default
+2
+default
+4
+5
+6
+default
+default
+sparse4
+2147483645
+default
+2147483647
+default
+sparse5
+-2147483648
+default
+default
+sparse7
+default
+default
+1
+2
+default
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+default
 CORRECT (one)
 CORRECT (not found)
 CORRECT (large)
diff --git a/test/015-switch/src/Main.java b/test/015-switch/src/Main.java
index dd97a8c..2a7995a 100644
--- a/test/015-switch/src/Main.java
+++ b/test/015-switch/src/Main.java
@@ -18,7 +18,338 @@
  * Test switch() blocks
  */
 public class Main {
+
+    // TODO: This should be translated to smali tests, so it is guaranteed we have the right kind
+    //       of switch.
+
+    // Simple packed-switch.
+    public static void packedSwitch(int value) {
+        switch (value) {
+            case 0:
+                System.out.println("0"); break;
+            case 1:
+                System.out.println("1"); break;
+            case 2:
+                System.out.println("2"); break;
+            case 3:
+                System.out.println("3"); break;
+            case 4:
+                System.out.println("4"); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple packed-switch starting at a negative index.
+    public static void packedSwitch2(int value) {
+        switch (value) {
+            case -3:
+                System.out.println("-3"); break;
+            case -2:
+                System.out.println("-2"); break;
+            case -1:
+                System.out.println("-1"); break;
+            case 0:
+                System.out.println("0"); break;
+            case 1:
+                System.out.println("1"); break;
+            case 2:
+                System.out.println("2"); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple packed-switch starting above 0.
+    public static void packedSwitch3(int value) {
+        switch (value) {
+            case 2:
+                System.out.println("2"); break;
+            case 3:
+                System.out.println("3"); break;
+            case 4:
+                System.out.println("4"); break;
+            case 5:
+                System.out.println("5"); break;
+            case 6:
+                System.out.println("6"); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple packed-switch going up to max_int.
+    public static void packedSwitch4(int value) {
+        switch (value) {
+            case Integer.MAX_VALUE - 1:
+                System.out.println(Integer.MAX_VALUE - 1); break;
+            case Integer.MAX_VALUE:
+                System.out.println(Integer.MAX_VALUE); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple packed-switch starting at min_int.
+    public static void packedSwitch5(int value) {
+        switch (value) {
+            case Integer.MIN_VALUE:
+                System.out.println(Integer.MIN_VALUE); break;
+            case Integer.MIN_VALUE + 1:
+                System.out.println(Integer.MIN_VALUE + 1); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple (packed-)switch with only min_int.
+    public static void packedSwitch6(int value) {
+        switch (value) {
+            case Integer.MIN_VALUE:
+                System.out.println(Integer.MIN_VALUE); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Long packed-switch that might lead to not creating chained-ifs.
+    public static void packedSwitch7(int value) {
+        switch (value) {
+            case 1:
+                System.out.println(1); break;
+            case 2:
+                System.out.println(2); break;
+            case 3:
+                System.out.println(3); break;
+            case 4:
+                System.out.println(4); break;
+            case 5:
+                System.out.println(5); break;
+            case 6:
+                System.out.println(6); break;
+            case 7:
+                System.out.println(7); break;
+            case 8:
+                System.out.println(8); break;
+            case 9:
+                System.out.println(9); break;
+            case 10:
+                System.out.println(10); break;
+            case 11:
+                System.out.println(11); break;
+            case 12:
+                System.out.println(12); break;
+            case 13:
+                System.out.println(13); break;
+            case 14:
+                System.out.println(14); break;
+            case 15:
+                System.out.println(15); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Sparse switch, just leave a gap.
+    public static void sparseSwitch(int value) {
+        switch (value) {
+            case 0:
+                System.out.println("0"); break;
+            case 1:
+                System.out.println("1"); break;
+            case 3:
+                System.out.println("3"); break;
+            case 4:
+                System.out.println("4"); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple sparse-switch starting at a negative index.
+    public static void sparseSwitch2(int value) {
+        switch (value) {
+            case -3:
+                System.out.println("-3"); break;
+            case -2:
+                System.out.println("-2"); break;
+            case -1:
+                System.out.println("-1"); break;
+            case 0:
+                System.out.println("0"); break;
+            case 2:
+                System.out.println("2"); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple sparse-switch starting above 0.
+    public static void sparseSwitch3(int value) {
+        switch (value) {
+            case 2:
+                System.out.println("2"); break;
+            case 4:
+                System.out.println("4"); break;
+            case 5:
+                System.out.println("5"); break;
+            case 6:
+                System.out.println("6"); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple sparse-switch going up to max_int.
+    public static void sparseSwitch4(int value) {
+        switch (value) {
+            case Integer.MAX_VALUE - 2:
+                System.out.println(Integer.MAX_VALUE - 2); break;
+            case Integer.MAX_VALUE:
+                System.out.println(Integer.MAX_VALUE); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Simple sparse-switch starting at min_int.
+    public static void sparseSwitch5(int value) {
+        switch (value) {
+            case Integer.MIN_VALUE:
+                System.out.println(Integer.MIN_VALUE); break;
+            case Integer.MIN_VALUE + 2:
+                System.out.println(Integer.MIN_VALUE + 2); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
+    // Long sparse-switch that might lead to not creating chained-ifs.
+    public static void sparseSwitch7(int value) {
+        switch (value) {
+            case 1:
+                System.out.println(1); break;
+            case 2:
+                System.out.println(2); break;
+            case 4:
+                System.out.println(4); break;
+            case 5:
+                System.out.println(5); break;
+            case 6:
+                System.out.println(6); break;
+            case 7:
+                System.out.println(7); break;
+            case 8:
+                System.out.println(8); break;
+            case 9:
+                System.out.println(9); break;
+            case 10:
+                System.out.println(10); break;
+            case 11:
+                System.out.println(11); break;
+            case 12:
+                System.out.println(12); break;
+            case 13:
+                System.out.println(13); break;
+            case 14:
+                System.out.println(14); break;
+            case 15:
+                System.out.println(15); break;
+            default:
+                System.out.println("default"); break;
+        }
+    }
+
     public static void main(String args[]) {
+        /*
+         * Note: We are using for loops and calls to hopefully avoid simplifying the switch
+         *       structure from constant propagation. When inlining is supported, this needs to
+         *       be revisited.
+         */
+
+        System.out.println("packed");
+        for (int i = -2; i < 3; i++) {
+            packedSwitch(i);
+        }
+        packedSwitch(Integer.MIN_VALUE);
+        packedSwitch(Integer.MAX_VALUE);
+
+        System.out.println("packed2");
+        for (int i = -2; i < 3; i++) {
+            packedSwitch2(i);
+        }
+        packedSwitch2(Integer.MIN_VALUE);
+        packedSwitch2(Integer.MAX_VALUE);
+
+        System.out.println("packed3");
+        for (int i = -2; i < 7; i++) {
+            packedSwitch3(i);
+        }
+        packedSwitch3(Integer.MIN_VALUE);
+        packedSwitch3(Integer.MAX_VALUE);
+
+        System.out.println("packed4");
+        for (int i = Integer.MAX_VALUE - 2; i > 0; i++) {
+            packedSwitch4(i);
+        }
+        packedSwitch4(Integer.MIN_VALUE);
+
+        System.out.println("packed5");
+        for (int i = Integer.MIN_VALUE; i < Integer.MIN_VALUE + 2; i++) {
+            packedSwitch5(i);
+        }
+        packedSwitch5(Integer.MAX_VALUE);
+
+        System.out.println("packed6");
+        packedSwitch6(Integer.MIN_VALUE);
+        packedSwitch6(Integer.MAX_VALUE);
+
+        System.out.println("packed7");
+        for (int i = -1; i < 17; i++) {
+            packedSwitch7(i);
+        }
+
+
+        System.out.println("sparse");
+        for (int i = -2; i < 4; i++) {
+            sparseSwitch(i);
+        }
+        sparseSwitch(Integer.MIN_VALUE);
+        sparseSwitch(Integer.MAX_VALUE);
+
+        System.out.println("sparse2");
+        for (int i = -2; i < 3; i++) {
+            sparseSwitch2(i);
+        }
+        sparseSwitch2(Integer.MIN_VALUE);
+        sparseSwitch2(Integer.MAX_VALUE);
+
+        System.out.println("sparse3");
+        for (int i = -2; i < 7; i++) {
+            sparseSwitch3(i);
+        }
+        sparseSwitch3(Integer.MIN_VALUE);
+        sparseSwitch3(Integer.MAX_VALUE);
+
+        System.out.println("sparse4");
+        for (int i = Integer.MAX_VALUE - 2; i > 0; i++) {
+            sparseSwitch4(i);
+        }
+        sparseSwitch4(Integer.MIN_VALUE);
+
+        System.out.println("sparse5");
+        for (int i = Integer.MIN_VALUE; i < Integer.MIN_VALUE + 2; i++) {
+            sparseSwitch5(i);
+        }
+        sparseSwitch5(Integer.MAX_VALUE);
+
+        System.out.println("sparse7");
+        for (int i = -1; i < 17; i++) {
+            sparseSwitch7(i);
+        }
+
+        // Older tests.
+
         int a = 1;
 
         switch (a) {
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index 4ea52d9..ad42a2d 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -18,7 +18,7 @@
 set -e
 
 # Write out a bunch of interface source files.
-gcc -o iface-gen iface-gen.c
+gcc -Wall -Werror -o iface-gen iface-gen.c
 ./iface-gen
 
 mkdir classes
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/040-miranda/src/Main.java b/test/040-miranda/src/Main.java
index ff5eba0..65f4fb4 100644
--- a/test/040-miranda/src/Main.java
+++ b/test/040-miranda/src/Main.java
@@ -42,8 +42,8 @@
 
         System.out.println("Test getting miranda method via reflection:");
         try {
-          Class mirandaClass = Class.forName("MirandaAbstract");
-          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface", (Class[]) null);
+          Class<?> mirandaClass = Class.forName("MirandaAbstract");
+          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface");
           System.out.println("  did not expect to find miranda method");
         } catch (NoSuchMethodException nsme) {
           System.out.println("  caught expected NoSuchMethodException");
diff --git a/test/040-miranda/src/MirandaAbstract.java b/test/040-miranda/src/MirandaAbstract.java
index 309ecca..c8cfa34 100644
--- a/test/040-miranda/src/MirandaAbstract.java
+++ b/test/040-miranda/src/MirandaAbstract.java
@@ -21,6 +21,8 @@
 {
     protected MirandaAbstract() { }
 
+    // These will be miranda methods, as the interfaces define them, but they are not
+    // implemented in this abstract class:
     //public abstract boolean inInterface();
     //public abstract int inInterface2();
 
diff --git a/test/040-miranda/src/MirandaClass.java b/test/040-miranda/src/MirandaClass.java
index 0d942f0..4160992 100644
--- a/test/040-miranda/src/MirandaClass.java
+++ b/test/040-miranda/src/MirandaClass.java
@@ -22,17 +22,14 @@
     public MirandaClass() {}
 
     public boolean inInterface() {
-        //System.out.println("    MirandaClass inInterface");
         return true;
     }
 
     public int inInterface2() {
-        //System.out.println("    MirandaClass inInterface2");
         return 27;
     }
 
     public boolean inAbstract() {
-        //System.out.println("    MirandaClass inAbstract");
         return false;
     }
 }
diff --git a/test/040-miranda/src/MirandaClass2.java b/test/040-miranda/src/MirandaClass2.java
index e9bdf2b..143eb37 100644
--- a/test/040-miranda/src/MirandaClass2.java
+++ b/test/040-miranda/src/MirandaClass2.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
 class MirandaClass2 extends MirandaAbstract {
     public boolean inInterface() {
         return true;
diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt
index 943d1df..54e34af 100644
--- a/test/051-thread/expected.txt
+++ b/test/051-thread/expected.txt
@@ -9,4 +9,6 @@
 testSetName starting
 testSetName running
 testSetName finished
+testThreadPriorities starting
+testThreadPriorities finished
 thread test done
diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java
index 390685d..b81273e 100644
--- a/test/051-thread/src/Main.java
+++ b/test/051-thread/src/Main.java
@@ -20,12 +20,17 @@
  * Test some basic thread stuff.
  */
 public class Main {
+    static {
+        System.loadLibrary("arttest");
+    }
+
     public static void main(String[] args) throws Exception {
         System.out.println("thread test starting");
         testThreadCapacity();
         testThreadDaemons();
         testSleepZero();
         testSetName();
+        testThreadPriorities();
         System.out.println("thread test done");
     }
 
@@ -133,4 +138,53 @@
         }
         System.out.print("testSetName finished\n");
     }
+
+    private static void testThreadPriorities() throws Exception {
+        System.out.print("testThreadPriorities starting\n");
+
+        PriorityStoringThread t1 = new PriorityStoringThread(false);
+        t1.setPriority(Thread.MAX_PRIORITY);
+        t1.start();
+        t1.join();
+        if (supportsThreadPriorities() && (t1.getNativePriority() != Thread.MAX_PRIORITY)) {
+            System.out.print("thread priority for t1 was " + t1.getNativePriority() +
+                " [expected Thread.MAX_PRIORITY]\n");
+        }
+
+        PriorityStoringThread t2 = new PriorityStoringThread(true);
+        t2.start();
+        t2.join();
+        if (supportsThreadPriorities() && (t2.getNativePriority() != Thread.MAX_PRIORITY)) {
+            System.out.print("thread priority for t2 was " + t2.getNativePriority() +
+                " [expected Thread.MAX_PRIORITY]\n");
+        }
+
+        System.out.print("testThreadPriorities finished\n");
+    }
+
+    private static native int getNativePriority();
+    private static native boolean supportsThreadPriorities();
+
+    static class PriorityStoringThread extends Thread {
+        private final boolean setPriority;
+        private volatile int nativePriority;
+
+        public PriorityStoringThread(boolean setPriority) {
+            this.setPriority = setPriority;
+            this.nativePriority = -1;
+        }
+
+        @Override
+        public void run() {
+            if (setPriority) {
+                setPriority(Thread.MAX_PRIORITY);
+            }
+
+            nativePriority = Main.getNativePriority();
+        }
+
+        public int getNativePriority() {
+            return nativePriority;
+        }
+    }
 }
diff --git a/test/051-thread/thread_test.cc b/test/051-thread/thread_test.cc
new file mode 100644
index 0000000..2b8e675
--- /dev/null
+++ b/test/051-thread/thread_test.cc
@@ -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 "base/macros.h"
+#include "jni.h"
+#include "thread-inl.h"
+
+namespace art {
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getNativePriority(JNIEnv* env,
+                                                              jclass clazz ATTRIBUTE_UNUSED) {
+  return ThreadForEnv(env)->GetNativePriority();
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_supportsThreadPriorities(
+    JNIEnv* env ATTRIBUTE_UNUSED,
+    jclass clazz ATTRIBUTE_UNUSED) {
+#if defined(HAVE_ANDROID_OS)
+  return JNI_TRUE;
+#else
+  return JNI_FALSE;
+#endif
+}
+
+}  // namespace art
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/080-oom-throw-with-finalizer/expected.txt b/test/080-oom-throw-with-finalizer/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/080-oom-throw-with-finalizer/expected.txt
diff --git a/test/080-oom-throw-with-finalizer/info.txt b/test/080-oom-throw-with-finalizer/info.txt
new file mode 100644
index 0000000..37091ef
--- /dev/null
+++ b/test/080-oom-throw-with-finalizer/info.txt
@@ -0,0 +1 @@
+Regression test on correct processing of OOM thrown while adding a finalizer reference.
diff --git a/test/080-oom-throw-with-finalizer/src/Main.java b/test/080-oom-throw-with-finalizer/src/Main.java
new file mode 100644
index 0000000..57e9721
--- /dev/null
+++ b/test/080-oom-throw-with-finalizer/src/Main.java
@@ -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.
+ */
+
+import java.util.Vector;
+
+public class Main {
+    static char [][] holder;
+
+    static class ArrayMemEater {
+        static boolean sawOome;
+
+        static void blowup(char[][] holder) {
+            try {
+                for (int i = 0; i < holder.length; ++i) {
+                    holder[i] = new char[1024 * 1024];
+                }
+            } catch (OutOfMemoryError oome) {
+                ArrayMemEater.sawOome = true;
+            }
+        }
+    }
+
+    static class InstanceFinalizerMemEater {
+        public void finalize() {}
+    }
+
+    static boolean triggerArrayOOM(char[][] holder) {
+        ArrayMemEater.blowup(holder);
+        return ArrayMemEater.sawOome;
+    }
+
+    static boolean triggerInstanceFinalizerOOM() {
+        boolean sawOome = false;
+        try {
+            Vector v = new Vector();
+            while (true) {
+                v.add(new InstanceFinalizerMemEater());
+            }
+        } catch (OutOfMemoryError e) {
+            sawOome = true;
+        }
+        return sawOome;
+    }
+
+    public static void main(String[] args) {
+        // Keep holder alive to make instance OOM happen faster.
+        holder = new char[128 * 1024][];
+        if (!triggerArrayOOM(holder)) {
+            System.out.println("NEW_ARRAY did not throw OOME");
+        }
+
+        if (!triggerInstanceFinalizerOOM()) {
+            System.out.println("NEW_INSTANCE (finalize) did not throw OOME");
+        }
+
+        System.runFinalization();
+    }
+}
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 56972ff..862fe06 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -119,6 +119,9 @@
     }
   }
 
+  // Break up the charAt tests. The optimizing compiler doesn't optimize methods with try-catch yet,
+  // so we need to separate out the tests that are expected to throw exception
+
   public static void test_String_charAt() {
     String testStr = "Now is the time";
 
@@ -127,6 +130,12 @@
     Assert.assertEquals(' ', testStr.charAt(10));
     Assert.assertEquals('e', testStr.charAt(testStr.length()-1));
 
+    test_String_charAtExc();
+    test_String_charAtExc2();
+  }
+
+  private static void test_String_charAtExc() {
+    String testStr = "Now is the time";
     try {
       testStr.charAt(-1);
       Assert.fail();
@@ -146,6 +155,19 @@
     }
   }
 
+  private static void test_String_charAtExc2() {
+    try {
+      test_String_charAtExc3();
+      Assert.fail();
+    } catch (StringIndexOutOfBoundsException expected) {
+    }
+  }
+
+  private static void test_String_charAtExc3() {
+    String testStr = "Now is the time";
+    Assert.assertEquals('N', testStr.charAt(-1));
+  }
+
   static int start;
   private static int[] negIndex = { -100000 };
   public static void test_String_indexOf() {
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
index e907fd1..78c92fc 100644
--- a/test/083-compiler-regressions/expected.txt
+++ b/test/083-compiler-regressions/expected.txt
@@ -1,3 +1,5 @@
+b17325447 passes
+b17630605 passes
 b17411468 passes
 b2296099 passes
 b2302318 passes
@@ -16,6 +18,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..285c360 100644
--- a/test/083-compiler-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -30,6 +30,8 @@
     }
 
     public static void main(String args[]) throws Exception {
+        b17325447();
+        b17630605();
         b17411468();
         b2296099Test();
         b2302318Test();
@@ -38,6 +40,7 @@
         b13679511Test();
         b16177324TestWrapper();
         b16230771TestWrapper();
+        b17969907TestWrapper();
         largeFrameTest();
         largeFrameTestFloat();
         mulBy1Test();
@@ -62,6 +65,43 @@
         minDoubleWith3ConstsTest();
     }
 
+    public static double b17325447_i1(int i1, double f) {
+      return f;
+    }
+
+    public static double b17325447_i2(int i1, int i2, double f) {
+      return f;
+    }
+
+    public static double b17325447_i3(int i1, int i2, int i3, double f) {
+      return f;
+    }
+
+    public static void b17325447() {
+      // b/17325447 - x86 handling of special identity method w/ double spanning reg/mem.
+      double d = 0.0;
+      d += b17325447_i1(123, 1.0);
+      d += b17325447_i2(123, 456, 2.0);
+      d += b17325447_i3(123, 456, 789, 3.0);
+      if (d == 6.0) {
+        System.out.println("b17325447 passes");
+      } else {
+        System.out.println("b17325447 fails: " + d);
+      }
+    }
+
+    public static void b17630605() {
+      // b/17630605 - failure to properly handle min long immediates.
+      long a1 = 40455547223404749L;
+      long a2 = Long.MIN_VALUE;
+      long answer = a1 + a2;
+      if (answer == -9182916489631371059L) {
+          System.out.println("b17630605 passes");
+      } else {
+          System.out.println("b17630605 fails: " + answer);
+      }
+    }
+
     public static void b17411468() {
       // b/17411468 - inline Math.round failure.
       double d1 = 1.0;
@@ -977,6 +1017,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..65b7139
--- /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' -e '/^Max filename/d' -e '/^Max pathlength/d' "$2" > "$2.tmp"
+
+diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
\ No newline at end of file
diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt
index 1af4121..8fdeccc 100644
--- a/test/100-reflect2/expected.txt
+++ b/test/100-reflect2/expected.txt
@@ -32,7 +32,7 @@
 62 (class java.lang.Long)
 14 (class java.lang.Short)
 [public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)]
-[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final long java.lang.String.serialVersionUID, private static final char java.lang.String.REPLACEMENT_CHAR]
+[private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private final char[] java.lang.String.value, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID]
 [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)]
 []
 [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence]
diff --git a/test/109-suspend-check/src/Main.java b/test/109-suspend-check/src/Main.java
index ae10576..cd5130d 100644
--- a/test/109-suspend-check/src/Main.java
+++ b/test/109-suspend-check/src/Main.java
@@ -21,10 +21,15 @@
         System.out.println("Running (" + TEST_TIME + " seconds) ...");
         InfiniteForLoop forLoop = new InfiniteForLoop();
         InfiniteWhileLoop whileLoop = new InfiniteWhileLoop();
+        InfiniteWhileLoopWithIntrinsic whileLoopWithIntrinsic =
+            new InfiniteWhileLoopWithIntrinsic();
+        InfiniteDoWhileLoopWithLong doWhileLoopWithLong = new InfiniteDoWhileLoopWithLong();
         InfiniteDoWhileLoop doWhileLoop = new InfiniteDoWhileLoop();
         MakeGarbage garbage = new MakeGarbage();
         forLoop.start();
         whileLoop.start();
+        whileLoopWithIntrinsic.start();
+        doWhileLoopWithLong.start();
         doWhileLoop.start();
         garbage.start();
         for (int i = 0; i < TEST_TIME; i++) {
@@ -34,6 +39,8 @@
         }
         forLoop.stopNow();
         whileLoop.stopNow();
+        whileLoopWithIntrinsic.stopNow();
+        doWhileLoopWithLong.stopNow();
         doWhileLoop.stopNow();
         garbage.stopNow();
         System.out.println("Done.");
@@ -48,6 +55,35 @@
     }
 }
 
+class InfiniteWhileLoopWithIntrinsic extends Thread {
+  volatile private boolean keepGoing = true;
+  private String[] strings = { "a", "b", "c", "d" };
+  private int sum = 0;
+  public void run() {
+    int i = 0;
+    while (keepGoing) {
+      i++;
+      sum += strings[i & 3].length();
+    }
+  }
+  public void stopNow() {
+    keepGoing = false;
+  }
+}
+
+class InfiniteDoWhileLoopWithLong extends Thread {
+  volatile private long keepGoing = 7L;
+  public void run() {
+    int i = 0;
+    do {
+      i++;
+    } while (keepGoing >= 4L);
+  }
+  public void stopNow() {
+    keepGoing = 1L;
+  }
+}
+
 class InfiniteWhileLoop extends Thread {
   volatile private boolean keepGoing = true;
   public void run() {
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 8e2519d..48f9bd3 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -24,7 +24,10 @@
 
 public class Main implements Runnable {
 
-    public final static long TIMEOUT_VALUE = 5;  // Timeout in minutes.
+    // Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
+    // ART on timeout when running on the host.
+    public final static long TIMEOUT_VALUE = 12;
+
     public final static long MAX_SIZE = 1000;  // Maximum size of array-list to allocate.
 
     public static void main(String[] args) throws Exception {
diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt
index a5eedc6..16a71e4 100644
--- a/test/115-native-bridge/expected.txt
+++ b/test/115-native-bridge/expected.txt
@@ -1,3 +1,4 @@
+Code cache exists: './code_cache'.
 Native bridge initialized.
 Checking for getEnvValues.
 Ready for native bridge tests.
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 442f99c..6bcc1f5 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -18,12 +18,14 @@
 
 #include <algorithm>
 #include <dlfcn.h>
+#include <jni.h>
 #include <vector>
 
-#include "jni.h"
 #include "stdio.h"
 #include "unistd.h"
+#include "sys/stat.h"
 
+#include "base/macros.h"
 #include "nativebridge/native_bridge.h"
 
 struct NativeBridgeMethod {
@@ -208,7 +210,14 @@
 
 // NativeBridgeCallbacks implementations
 extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs,
-                                         const char* private_dir, const char* isa) {
+                                         const char* app_code_cache_dir,
+                                         const char* isa ATTRIBUTE_UNUSED) {
+  struct stat st;
+  if ((app_code_cache_dir != nullptr)
+      && (stat(app_code_cache_dir, &st) == 0)
+      && S_ISDIR(st.st_mode)) {
+    printf("Code cache exists: '%s'.\n", app_code_cache_dir);
+  }
   if (art_cbs != nullptr) {
     gNativeBridgeArtCallbacks = art_cbs;
     printf("Native bridge initialized.\n");
@@ -241,7 +250,7 @@
 }
 
 extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty,
-                                             uint32_t len) {
+                                             uint32_t len ATTRIBUTE_UNUSED) {
   printf("Getting trampoline for %s with shorty %s.\n", name, shorty);
 
   // The name here is actually the JNI name, so we can directly do the lookup.
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/116-nodex2oat/nodex2oat.cc b/test/116-nodex2oat/nodex2oat.cc
index 04cac45..564d58d 100644
--- a/test/116-nodex2oat/nodex2oat.cc
+++ b/test/116-nodex2oat/nodex2oat.cc
@@ -38,7 +38,7 @@
   return NoDex2OatTest::hasOat(cls);
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDex2OatEnabled(JNIEnv*, jclass cls) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDex2OatEnabled(JNIEnv*, jclass) {
   return Runtime::Current()->IsDex2OatEnabled();
 }
 
diff --git a/test/117-nopatchoat/expected.txt b/test/117-nopatchoat/expected.txt
index a1293ae..5cc02d1 100644
--- a/test/117-nopatchoat/expected.txt
+++ b/test/117-nopatchoat/expected.txt
@@ -1,9 +1,9 @@
 Run without dex2oat/patchoat
-dex2oat & patchoat are disabled, has oat is true, has executable oat is false.
+dex2oat & patchoat are disabled, has oat is true, has executable oat is expected.
 This is a function call
 Run with dexoat/patchoat
-dex2oat & patchoat are enabled, has oat is true, has executable oat is true.
+dex2oat & patchoat are enabled, has oat is true, has executable oat is expected.
 This is a function call
 Run default
-dex2oat & patchoat are enabled, has oat is true, has executable oat is true.
+dex2oat & patchoat are enabled, has oat is true, has executable oat is expected.
 This is a function call
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index 5994653..da276f2 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -24,18 +24,41 @@
 
 class NoPatchoatTest {
  public:
-  static bool hasExecutableOat(jclass cls) {
+  static const OatFile::OatDexFile* getOatDexFile(jclass cls) {
     ScopedObjectAccess soa(Thread::Current());
     mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
     const DexFile& dex_file = klass->GetDexFile();
+
     const OatFile::OatDexFile* oat_dex_file =
         Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+
+    return oat_dex_file;
+  }
+
+  static bool hasExecutableOat(jclass cls) {
+    const OatFile::OatDexFile* oat_dex_file = getOatDexFile(cls);
+
     return oat_dex_file != nullptr && oat_dex_file->GetOatFile()->IsExecutable();
   }
+
+  static bool isPic(jclass cls) {
+    const OatFile::OatDexFile* oat_dex_file = getOatDexFile(cls);
+
+    if (oat_dex_file == nullptr) {
+      return false;
+    }
+
+    const OatFile* oat_file = oat_dex_file->GetOatFile();
+    return oat_file->IsPic();
+  }
 };
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasExecutableOat(JNIEnv*, jclass cls) {
   return NoPatchoatTest::hasExecutableOat(cls);
 }
 
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isPic(JNIEnv*, jclass cls) {
+  return NoPatchoatTest::isPic(cls);
+}
+
 }  // namespace art
diff --git a/test/117-nopatchoat/src/Main.java b/test/117-nopatchoat/src/Main.java
index f3f91ce..7bc9dbb 100644
--- a/test/117-nopatchoat/src/Main.java
+++ b/test/117-nopatchoat/src/Main.java
@@ -16,9 +16,14 @@
 
 public class Main {
   public static void main(String[] args) {
+    boolean executable_correct = (isPic() ?
+                                  hasExecutableOat() == true :
+                                  hasExecutableOat() == isDex2OatEnabled());
+
     System.out.println(
         "dex2oat & patchoat are " + ((isDex2OatEnabled()) ? "enabled" : "disabled") +
-        ", has oat is " + hasOat() + ", has executable oat is " + hasExecutableOat() + ".");
+        ", has oat is " + hasOat() + ", has executable oat is " + (
+        executable_correct ? "expected" : "not expected") + ".");
 
     if (!hasOat() && isDex2OatEnabled()) {
       throw new Error("Application with dex2oat enabled runs without an oat file");
@@ -42,6 +47,8 @@
 
   private native static boolean isDex2OatEnabled();
 
+  private native static boolean isPic();
+
   private native static boolean hasOat();
 
   private native static boolean hasExecutableOat();
diff --git a/test/118-noimage-dex2oat/expected.txt b/test/118-noimage-dex2oat/expected.txt
index 6825fae..bcb695d 100644
--- a/test/118-noimage-dex2oat/expected.txt
+++ b/test/118-noimage-dex2oat/expected.txt
@@ -1,6 +1,9 @@
 Run -Xnoimage-dex2oat
 Has image is false, is image dex2oat enabled is false, is BOOTCLASSPATH on disk is false.
+testB18485243 PASS
 Run -Ximage-dex2oat
 Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
+testB18485243 PASS
 Run default
 Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
+testB18485243 PASS
diff --git a/test/118-noimage-dex2oat/noimage-dex2oat.cc b/test/118-noimage-dex2oat/noimage-dex2oat.cc
index 7340d9e..c49a13e 100644
--- a/test/118-noimage-dex2oat/noimage-dex2oat.cc
+++ b/test/118-noimage-dex2oat/noimage-dex2oat.cc
@@ -34,11 +34,11 @@
   }
 };
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage(JNIEnv*, jclass cls) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage(JNIEnv*, jclass) {
   return Runtime::Current()->GetHeap()->HasImageSpace();
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled(JNIEnv*, jclass cls) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled(JNIEnv*, jclass) {
   return Runtime::Current()->IsImageDex2OatEnabled();
 }
 
diff --git a/test/118-noimage-dex2oat/smali/b_18485243.smali b/test/118-noimage-dex2oat/smali/b_18485243.smali
new file mode 100644
index 0000000..41fbc74
--- /dev/null
+++ b/test/118-noimage-dex2oat/smali/b_18485243.smali
@@ -0,0 +1,22 @@
+.class public LB18485243;
+.super Ljava/lang/Object;
+.source "b_18485243.smali"
+
+.method public constructor <init>()V
+    .registers 2
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method private static toInt()I
+    .registers 1
+    const v0, 0
+    return v0
+.end method
+
+.method public run()I
+    .registers 3
+    invoke-direct {p0}, LB18485243;->toInt()I
+    move-result v0
+    return v0
+.end method
diff --git a/test/118-noimage-dex2oat/src/Main.java b/test/118-noimage-dex2oat/src/Main.java
index c83b84d..9bf5bb3 100644
--- a/test/118-noimage-dex2oat/src/Main.java
+++ b/test/118-noimage-dex2oat/src/Main.java
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 public class Main {
@@ -36,6 +37,8 @@
     } else if (!hasImage && isBootClassPathOnDisk) {
       throw new Error("Image with dex2oat enabled runs without an image file");
     }
+
+    testB18485243();
   }
 
   static {
@@ -67,4 +70,19 @@
       return (boolean) isBootClassPathOnDiskMethod.invoke(null, instructionSet);
     }
   }
+
+  private static void testB18485243() throws Exception {
+    Class<?> k = Class.forName("B18485243");
+    Object o = k.newInstance();
+    Method m = k.getDeclaredMethod("run");
+    try {
+      m.invoke(o);
+    } catch (InvocationTargetException e) {
+      Throwable actual = e.getTargetException();
+      if (!(actual instanceof IncompatibleClassChangeError)) {
+        throw new AssertionError("Expected IncompatibleClassChangeError", actual);
+      }
+    }
+    System.out.println("testB18485243 PASS");
+  }
 }
diff --git a/test/122-npe/src/Main.java b/test/122-npe/src/Main.java
index 2fdcb9c..8f68205 100644
--- a/test/122-npe/src/Main.java
+++ b/test/122-npe/src/Main.java
@@ -191,6 +191,132 @@
     check(npe, thisLine += 7);
 
     try {
+      ((Value) null).volatileObjectField.toString();
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileObjectField = "Fisk";
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useInt(((Value) null).volatileIntField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileIntField = 42;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useFloat(((Value) null).volatileFloatField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileFloatField = 42.0F;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useLong(((Value) null).volatileLongField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileLongField = 42L;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useDouble(((Value) null).volatileDoubleField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileDoubleField = 42.0d;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useInt(((Value) null).volatileByteField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileByteField = 42;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      if (((Value) null).volatileBooleanField) { }
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileBooleanField = true;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useInt(((Value) null).volatileCharField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileCharField = '\u0042';
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      useInt(((Value) null).volatileShortField);
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
+      ((Value) null).volatileShortField = 42;
+    } catch (NullPointerException e) {
+      npe = e;
+    }
+    check(npe, thisLine += 7);
+
+    try {
       ((Object[]) null)[0].toString();
     } catch (NullPointerException e) {
       npe = e;
@@ -477,11 +603,22 @@
   static class Value {
     Object objectField;
     int intField;
-    float floatField; long longField;
+    float floatField;
+    long longField;
     double doubleField;
     byte byteField;
     boolean booleanField;
     char charField;
     short shortField;
+
+    volatile Object volatileObjectField;
+    volatile int volatileIntField;
+    volatile float volatileFloatField;
+    volatile long volatileLongField;
+    volatile double volatileDoubleField;
+    volatile byte volatileByteField;
+    volatile boolean volatileBooleanField;
+    volatile char volatileCharField;
+    volatile short volatileShortField;
   }
 }
diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build
new file mode 100644
index 0000000..62e57c8
--- /dev/null
+++ b/test/124-missing-classes/build
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# 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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+
+# Some classes are available at compile time...
+${JAVAC} -d classes `find src -name '*.java'`
+
+# ...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/test/124-missing-classes/src/MissingClass.java b/test/124-missing-classes/src/MissingClass.java
new file mode 100644
index 0000000..33aaa56
--- /dev/null
+++ b/test/124-missing-classes/src/MissingClass.java
@@ -0,0 +1,20 @@
+/*
+ * 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 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/126-miranda-multidex/build b/test/126-miranda-multidex/build
new file mode 100644
index 0000000..4c30f3f
--- /dev/null
+++ b/test/126-miranda-multidex/build
@@ -0,0 +1,32 @@
+#!/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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+
+# All except Main
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/MirandaInterface.class
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+# Only Main
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/Main.class classes/MirandaAbstract.class classes/MirandaClass*.class classes/MirandaInterface2*.class
+${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+
+zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/126-miranda-multidex/expected.txt b/test/126-miranda-multidex/expected.txt
new file mode 100644
index 0000000..dbe3717
--- /dev/null
+++ b/test/126-miranda-multidex/expected.txt
@@ -0,0 +1,32 @@
+MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+MirandaAbstract / MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+true 27
+MirandaAbstract / MirandaClass2:
+  inInterface:  true
+  inInterface2: 28
+  inAbstract:   true
+true 28
+Test getting miranda method via reflection:
+  caught expected NoSuchMethodException
+MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+MirandaAbstract / MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+true 27
+MirandaAbstract / MirandaClass2:
+  inInterface:  true
+  inInterface2: 28
+  inAbstract:   true
+true 28
+Test getting miranda method via reflection:
+  caught expected NoSuchMethodException
diff --git a/test/126-miranda-multidex/info.txt b/test/126-miranda-multidex/info.txt
new file mode 100644
index 0000000..ac50e2e
--- /dev/null
+++ b/test/126-miranda-multidex/info.txt
@@ -0,0 +1,2 @@
+This test ensures that cross-dex-file Miranda methods are correctly resolved.
+See b/18193682 for details.
diff --git a/test/126-miranda-multidex/run b/test/126-miranda-multidex/run
new file mode 100755
index 0000000..23c9935
--- /dev/null
+++ b/test/126-miranda-multidex/run
@@ -0,0 +1,21 @@
+#!/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.
+
+${RUN} $@
+
+# The problem was first exposed in a no-verify setting, as that changes the resolution path
+# taken. Make sure we also test in that environment.
+${RUN} --no-verify ${@}
diff --git a/test/126-miranda-multidex/src/Main.java b/test/126-miranda-multidex/src/Main.java
new file mode 100644
index 0000000..8624378
--- /dev/null
+++ b/test/126-miranda-multidex/src/Main.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006 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.Method;
+
+/**
+ * Miranda testing.
+ */
+public class Main {
+    public static void main(String[] args) {
+        MirandaClass mir = new MirandaClass();
+        System.out.println("MirandaClass:");
+        System.out.println("  inInterface:  " + mir.inInterface());
+        System.out.println("  inInterface2: " + mir.inInterface2());
+        System.out.println("  inAbstract:   " + mir.inAbstract());
+
+        /* try again through abstract class; results should be identical */
+        MirandaAbstract mira = mir;
+        System.out.println("MirandaAbstract / MirandaClass:");
+        System.out.println("  inInterface:  " + mira.inInterface());
+        System.out.println("  inInterface2: " + mira.inInterface2());
+        System.out.println("  inAbstract:   " + mira.inAbstract());
+        mira.callMiranda();
+
+        MirandaAbstract mira2 = new MirandaClass2();
+        System.out.println("MirandaAbstract / MirandaClass2:");
+        System.out.println("  inInterface:  " + mira2.inInterface());
+        System.out.println("  inInterface2: " + mira2.inInterface2());
+        System.out.println("  inAbstract:   " + mira2.inAbstract());
+        mira2.callMiranda();
+
+        System.out.println("Test getting miranda method via reflection:");
+        try {
+          Class<?> mirandaClass = Class.forName("MirandaAbstract");
+          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface");
+          System.out.println("  did not expect to find miranda method");
+        } catch (NoSuchMethodException nsme) {
+          System.out.println("  caught expected NoSuchMethodException");
+        } catch (Exception e) {
+          System.out.println("  caught unexpected exception " + e);
+        }
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaAbstract.java b/test/126-miranda-multidex/src/MirandaAbstract.java
new file mode 100644
index 0000000..c09a61f
--- /dev/null
+++ b/test/126-miranda-multidex/src/MirandaAbstract.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public abstract class MirandaAbstract implements MirandaInterface, MirandaInterface2
+{
+    protected MirandaAbstract() { }
+
+    // These will be miranda methods, as the interfaces define them, but they are not
+    // implemented in this abstract class:
+    //public abstract boolean inInterface();
+    //public abstract int inInterface2();
+
+    public boolean inAbstract() {
+        return true;
+    }
+
+    public void callMiranda() {
+        System.out.println(inInterface() + " " + inInterface2());
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaClass.java b/test/126-miranda-multidex/src/MirandaClass.java
new file mode 100644
index 0000000..7bb37e7
--- /dev/null
+++ b/test/126-miranda-multidex/src/MirandaClass.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public class MirandaClass extends MirandaAbstract {
+
+    public MirandaClass() {}
+
+    public boolean inInterface() {
+        return true;
+    }
+
+    public int inInterface2() {
+        return 27;
+    }
+
+    public boolean inAbstract() {
+        return false;
+    }
+
+    // Better not hit any of these...
+    public void inInterfaceDummy1() {
+        System.out.println("inInterfaceDummy1");
+    }
+    public void inInterfaceDummy2() {
+        System.out.println("inInterfaceDummy2");
+    }
+    public void inInterfaceDummy3() {
+        System.out.println("inInterfaceDummy3");
+    }
+    public void inInterfaceDummy4() {
+        System.out.println("inInterfaceDummy4");
+    }
+    public void inInterfaceDummy5() {
+        System.out.println("inInterfaceDummy5");
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaClass2.java b/test/126-miranda-multidex/src/MirandaClass2.java
new file mode 100644
index 0000000..797ead2
--- /dev/null
+++ b/test/126-miranda-multidex/src/MirandaClass2.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+class MirandaClass2 extends MirandaAbstract {
+    public boolean inInterface() {
+        return true;
+    }
+
+    public int inInterface2() {
+        return 28;
+    }
+
+    // Better not hit any of these...
+    public void inInterfaceDummy1() {
+        System.out.println("inInterfaceDummy1");
+    }
+    public void inInterfaceDummy2() {
+        System.out.println("inInterfaceDummy2");
+    }
+    public void inInterfaceDummy3() {
+        System.out.println("inInterfaceDummy3");
+    }
+    public void inInterfaceDummy4() {
+        System.out.println("inInterfaceDummy4");
+    }
+    public void inInterfaceDummy5() {
+        System.out.println("inInterfaceDummy5");
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaInterface.java b/test/126-miranda-multidex/src/MirandaInterface.java
new file mode 100644
index 0000000..df12fcc
--- /dev/null
+++ b/test/126-miranda-multidex/src/MirandaInterface.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public interface MirandaInterface {
+
+    public boolean inInterface();
+
+    // A couple of dummy methods to fill the method table.
+    public void inInterfaceDummy1();
+    public void inInterfaceDummy2();
+    public void inInterfaceDummy3();
+    public void inInterfaceDummy4();
+    public void inInterfaceDummy5();
+
+}
diff --git a/test/126-miranda-multidex/src/MirandaInterface2.java b/test/126-miranda-multidex/src/MirandaInterface2.java
new file mode 100644
index 0000000..7c93fd0
--- /dev/null
+++ b/test/126-miranda-multidex/src/MirandaInterface2.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public interface MirandaInterface2 {
+
+    public boolean inInterface();
+
+    public int inInterface2();
+
+}
diff --git a/test/127-secondarydex/build b/test/127-secondarydex/build
new file mode 100755
index 0000000..712774f
--- /dev/null
+++ b/test/127-secondarydex/build
@@ -0,0 +1,31 @@
+#!/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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+
+mkdir classes-ex
+mv classes/Super.class classes-ex
+
+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
+  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  zip ${TEST_NAME}-ex.jar classes.dex
+fi
diff --git a/test/127-secondarydex/expected.txt b/test/127-secondarydex/expected.txt
new file mode 100644
index 0000000..29a1411
--- /dev/null
+++ b/test/127-secondarydex/expected.txt
@@ -0,0 +1,3 @@
+testSlowPathDirectInvoke
+Test
+Got null pointer exception
diff --git a/test/127-secondarydex/info.txt b/test/127-secondarydex/info.txt
new file mode 100644
index 0000000..0479d1a
--- /dev/null
+++ b/test/127-secondarydex/info.txt
@@ -0,0 +1,3 @@
+Test features with a secondary dex file.
+
+- Regression test to ensure slow path of direct invoke does null check.
diff --git a/test/127-secondarydex/run b/test/127-secondarydex/run
new file mode 100755
index 0000000..d8c3c79
--- /dev/null
+++ b/test/127-secondarydex/run
@@ -0,0 +1,18 @@
+#!/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.
+
+# Use secondary switch to add secondary dex file to class path.
+exec ${RUN} "${@}" --secondary
diff --git a/test/127-secondarydex/src/Main.java b/test/127-secondarydex/src/Main.java
new file mode 100644
index 0000000..c921c5b
--- /dev/null
+++ b/test/127-secondarydex/src/Main.java
@@ -0,0 +1,43 @@
+/*
+ * 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.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Secondary dex file test.
+ */
+public class Main {
+    public static void main(String[] args) {
+        testSlowPathDirectInvoke();
+    }
+
+    public static void testSlowPathDirectInvoke() {
+        System.out.println("testSlowPathDirectInvoke");
+        try {
+            Test t1 = new Test();
+            Test t2 = new Test();
+            Test t3 = null;
+            t1.test(t2);
+            t1.test(t3);
+        } catch (NullPointerException npe) {
+            System.out.println("Got null pointer exception");
+        } catch (Exception e) {
+            System.out.println("Got unexpected exception " + e);
+        }
+    }
+}
diff --git a/test/127-secondarydex/src/Super.java b/test/127-secondarydex/src/Super.java
new file mode 100644
index 0000000..7608d4a
--- /dev/null
+++ b/test/127-secondarydex/src/Super.java
@@ -0,0 +1,21 @@
+/*
+ * 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 Super {
+    private void print() {
+        System.out.println("Super");
+    }
+}
diff --git a/test/127-secondarydex/src/Test.java b/test/127-secondarydex/src/Test.java
new file mode 100644
index 0000000..82cb901
--- /dev/null
+++ b/test/127-secondarydex/src/Test.java
@@ -0,0 +1,25 @@
+/*
+ * 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 Test extends Super {
+    public void test(Test t) {
+        t.print();
+    }
+
+    private void print() {
+        System.out.println("Test");
+    }
+}
diff --git a/test/128-reg-spilling-on-implicit-nullcheck/expected.txt b/test/128-reg-spilling-on-implicit-nullcheck/expected.txt
new file mode 100644
index 0000000..9bdf658
--- /dev/null
+++ b/test/128-reg-spilling-on-implicit-nullcheck/expected.txt
@@ -0,0 +1 @@
+t7q = 2
diff --git a/test/128-reg-spilling-on-implicit-nullcheck/info.txt b/test/128-reg-spilling-on-implicit-nullcheck/info.txt
new file mode 100644
index 0000000..18b2112
--- /dev/null
+++ b/test/128-reg-spilling-on-implicit-nullcheck/info.txt
@@ -0,0 +1 @@
+This is a compiler reggression test for missing reg spilling on implicit nullcheck.
diff --git a/test/128-reg-spilling-on-implicit-nullcheck/src/Main.java b/test/128-reg-spilling-on-implicit-nullcheck/src/Main.java
new file mode 100644
index 0000000..48276bf
--- /dev/null
+++ b/test/128-reg-spilling-on-implicit-nullcheck/src/Main.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 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 {
+
+    public static void main(String[] args) {
+        int t7q = 0;
+        long q = 1L;
+
+        try {
+            for (int i = 1; i < 8; i++) {
+                t7q = (--t7q);
+                TestClass f = null;
+                t7q = f.field;
+            }
+        }
+        catch (NullPointerException wpw) {
+            q++;
+        }
+        finally {
+            t7q += (int)(1 - ((q - q) - 2));
+        }
+
+        System.out.println("t7q = " + t7q);
+    }
+}
+
+class TestClass {
+    public int field;
+    public void meth() {field = 1;}
+}
diff --git a/test/129-ThreadGetId/expected.txt b/test/129-ThreadGetId/expected.txt
new file mode 100644
index 0000000..134d8d0
--- /dev/null
+++ b/test/129-ThreadGetId/expected.txt
@@ -0,0 +1 @@
+Finishing
diff --git a/test/129-ThreadGetId/info.txt b/test/129-ThreadGetId/info.txt
new file mode 100644
index 0000000..443062d
--- /dev/null
+++ b/test/129-ThreadGetId/info.txt
@@ -0,0 +1 @@
+Regression test for b/18661622
diff --git a/test/129-ThreadGetId/src/Main.java b/test/129-ThreadGetId/src/Main.java
new file mode 100644
index 0000000..9934bba
--- /dev/null
+++ b/test/129-ThreadGetId/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * 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.Map;
+
+public class Main implements Runnable {
+    static final int numberOfThreads = 5;
+    static final int totalOperations = 1000;
+
+    public static void main(String[] args) throws Exception {
+        final Thread[] threads = new Thread[numberOfThreads];
+        for (int t = 0; t < threads.length; t++) {
+            threads[t] = new Thread(new Main());
+            threads[t].start();
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+        System.out.println("Finishing");
+    }
+
+    public void test_getId() {
+        if (Thread.currentThread().getId() <= 0) {
+            System.out.println("current thread's ID is not positive");
+        }
+        // Check all the current threads for positive IDs.
+        Map<Thread, StackTraceElement[]> stMap = Thread.getAllStackTraces();
+        for (Thread thread : stMap.keySet()) {
+            if (thread.getId() <= 0) {
+                System.out.println("thread's ID is not positive: " + thread.getName());
+            }
+        }
+    }
+
+    public void run() {
+        for (int i = 0; i < totalOperations; ++i) {
+            test_getId();
+        }
+    }
+}
diff --git a/test/130-hprof/expected.txt b/test/130-hprof/expected.txt
new file mode 100644
index 0000000..cc3d9f2
--- /dev/null
+++ b/test/130-hprof/expected.txt
@@ -0,0 +1 @@
+Generated data.
diff --git a/test/130-hprof/info.txt b/test/130-hprof/info.txt
new file mode 100644
index 0000000..64475ef
--- /dev/null
+++ b/test/130-hprof/info.txt
@@ -0,0 +1 @@
+Dump the heap for this test.
diff --git a/test/130-hprof/src/Main.java b/test/130-hprof/src/Main.java
new file mode 100644
index 0000000..67e5232
--- /dev/null
+++ b/test/130-hprof/src/Main.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 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.io.File;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+public class Main {
+    private static final int TEST_LENGTH = 100;
+
+    private static boolean makeArray(int i) {
+        return i % 10 == 0;
+    }
+
+    private static void fillArray(Object global[], Object local[], int i) {
+        // Very stupid linking.
+        local[0] = global;
+        for (int j = 1; j < local.length; j++) {
+            local[j] = global[j];
+        }
+    }
+
+    public static void main(String[] args) {
+        // Create some data.
+        Object data[] = new Object[TEST_LENGTH];
+        for (int i = 0; i < data.length; i++) {
+            if (makeArray(i)) {
+                data[i] = new Object[TEST_LENGTH];
+            } else {
+                data[i] = String.valueOf(i);
+            }
+        }
+        for (int i = 0; i < data.length; i++) {
+            if (makeArray(i)) {
+                Object data2[] = (Object[]) data[i];
+                fillArray(data, data2, i);
+            }
+        }
+        System.out.println("Generated data.");
+
+        File dumpFile = null;
+        File convFile = null;
+
+        try {
+            // Now dump the heap.
+            dumpFile = createDump();
+
+            // Run hprof-conv on it.
+            convFile = getConvFile();
+
+            File hprof_conv = getHprofConf();
+            try {
+                ProcessBuilder pb = new ProcessBuilder(
+                        hprof_conv.getAbsoluteFile().toString(),
+                        dumpFile.getAbsoluteFile().toString(),
+                        convFile.getAbsoluteFile().toString());
+                pb.redirectErrorStream(true);
+                Process process = pb.start();
+                int ret = process.waitFor();
+                if (ret != 0) {
+                    throw new RuntimeException("Exited abnormally with " + ret);
+                }
+            } catch (Exception exc) {
+                throw new RuntimeException(exc);
+            }
+        } finally {
+            // Delete the files.
+            if (dumpFile != null) {
+                dumpFile.delete();
+            }
+            if (convFile != null) {
+                convFile.delete();
+            }
+        }
+    }
+
+    private static File getHprofConf() {
+        // Use the java.library.path. It points to the lib directory.
+        File libDir = new File(System.getProperty("java.library.path"));
+        return new File(new File(libDir.getParentFile(), "bin"), "hprof-conv");
+    }
+
+    private static File createDump() {
+        java.lang.reflect.Method dumpHprofDataMethod = getDumpHprofDataMethod();
+        if (dumpHprofDataMethod != null) {
+            File f = getDumpFile();
+            try {
+                dumpHprofDataMethod.invoke(null, f.getAbsoluteFile().toString());
+                return f;
+            } catch (Exception exc) {
+                exc.printStackTrace(System.out);
+            }
+        } else {
+            System.out.println("Could not find dump method!");
+        }
+        return null;
+    }
+
+    /**
+     * Finds VMDebug.dumpHprofData() through reflection.  In the reference
+     * implementation this will not be available.
+     *
+     * @return the reflection object, or null if the method can't be found
+     */
+    private static Method getDumpHprofDataMethod() {
+        ClassLoader myLoader = Main.class.getClassLoader();
+        Class vmdClass;
+        try {
+            vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
+        } catch (ClassNotFoundException cnfe) {
+            return null;
+        }
+
+        Method meth;
+        try {
+            meth = vmdClass.getMethod("dumpHprofData",
+                    new Class[] { String.class });
+        } catch (NoSuchMethodException nsme) {
+            System.err.println("Found VMDebug but not dumpHprofData method");
+            return null;
+        }
+
+        return meth;
+    }
+
+    private static File getDumpFile() {
+        try {
+            return File.createTempFile("test-130-hprof", "dump");
+        } catch (Exception exc) {
+            return null;
+        }
+    }
+
+    private static File getConvFile() {
+        try {
+            return File.createTempFile("test-130-hprof", "conv");
+        } catch (Exception exc) {
+            return null;
+        }
+    }
+}
diff --git a/test/131-structural-change/build b/test/131-structural-change/build
new file mode 100755
index 0000000..7ddc81d
--- /dev/null
+++ b/test/131-structural-change/build
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+
+mkdir classes-ex
+${JAVAC} -d classes-ex `find src-ex -name '*.java'`
+
+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
+  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  zip ${TEST_NAME}-ex.jar classes.dex
+fi
diff --git a/test/131-structural-change/expected.txt b/test/131-structural-change/expected.txt
new file mode 100644
index 0000000..cc7713d
--- /dev/null
+++ b/test/131-structural-change/expected.txt
@@ -0,0 +1,2 @@
+Should really reach here.
+Done.
diff --git a/test/131-structural-change/info.txt b/test/131-structural-change/info.txt
new file mode 100644
index 0000000..6d5817b
--- /dev/null
+++ b/test/131-structural-change/info.txt
@@ -0,0 +1 @@
+Check whether a structural change in a (non-native) multi-dex scenario is detected.
diff --git a/test/131-structural-change/run b/test/131-structural-change/run
new file mode 100755
index 0000000..63fdb8c
--- /dev/null
+++ b/test/131-structural-change/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Use secondary switch to add secondary dex file to class path.
+exec ${RUN} "${@}" --secondary
diff --git a/test/131-structural-change/src-ex/A.java b/test/131-structural-change/src-ex/A.java
new file mode 100644
index 0000000..800347b
--- /dev/null
+++ b/test/131-structural-change/src-ex/A.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 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 A {
+    public void bar() {
+    }
+}
diff --git a/test/131-structural-change/src-ex/B.java b/test/131-structural-change/src-ex/B.java
new file mode 100644
index 0000000..61369db
--- /dev/null
+++ b/test/131-structural-change/src-ex/B.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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 B extends A {
+    public void test() {
+        System.out.println("Should not reach this!");
+    }
+}
diff --git a/test/131-structural-change/src/A.java b/test/131-structural-change/src/A.java
new file mode 100644
index 0000000..b07de58
--- /dev/null
+++ b/test/131-structural-change/src/A.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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 A {
+    public void foo() {
+    }
+
+    public void bar() {
+    }
+
+    public void baz() {
+    }
+}
diff --git a/test/131-structural-change/src/Main.java b/test/131-structural-change/src/Main.java
new file mode 100644
index 0000000..8dfa280
--- /dev/null
+++ b/test/131-structural-change/src/Main.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 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.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Structural hazard test.
+ */
+public class Main {
+    public static void main(String[] args) {
+        new Main().run();
+    }
+
+    private void run() {
+        try {
+            Class<?> bClass = getClass().getClassLoader().loadClass("A");
+            System.out.println("Should really reach here.");
+        } catch (Exception e) {
+            e.printStackTrace(System.out);
+        }
+
+        boolean haveOatFile = hasOat();
+        boolean gotError = false;
+        try {
+            Class<?> bClass = getClass().getClassLoader().loadClass("B");
+        } catch (IncompatibleClassChangeError icce) {
+            gotError = true;
+        } catch (Exception e) {
+            e.printStackTrace(System.out);
+        }
+        if (haveOatFile ^ gotError) {
+            System.out.println("Did not get expected error.");
+        }
+        System.out.println("Done.");
+    }
+
+    static {
+        System.loadLibrary("arttest");
+    }
+
+    private native static boolean hasOat();
+}
diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build
index c1935d2..789d38e 100644
--- a/test/303-verification-stress/build
+++ b/test/303-verification-stress/build
@@ -18,7 +18,7 @@
 set -e
 
 # Write out a bunch of source files.
-gcc -o classes-gen classes-gen.c
+gcc -Wall -Werror -o classes-gen classes-gen.c
 ./classes-gen
 
 mkdir classes
diff --git a/test/303-verification-stress/classes-gen.c b/test/303-verification-stress/classes-gen.c
index be6cfa7..1f2fe3b 100644
--- a/test/303-verification-stress/classes-gen.c
+++ b/test/303-verification-stress/classes-gen.c
@@ -26,11 +26,11 @@
 
         fprintf(fp, "public class Test%03d {\n", i);
         fprintf(fp, "    static String[] array = new String[%d];\n", array_size);
-        fprintf(fp, "    static {\n", array_size);
+        fprintf(fp, "    static {\n");
         for (k = 0; k < array_size; k++) {
             fprintf(fp, "        array[%d] = \"string_%04d\";\n", k, k);
         }
-        fprintf(fp, "    }\n", array_size);
+        fprintf(fp, "    }\n");
         fprintf(fp, "}\n");
         fclose(fp);
     }
diff --git a/test/401-optimizing-compiler/src/Main.java b/test/401-optimizing-compiler/src/Main.java
index 07c407b..7c3fd25 100644
--- a/test/401-optimizing-compiler/src/Main.java
+++ b/test/401-optimizing-compiler/src/Main.java
@@ -94,6 +94,14 @@
       exception = e;
     }
 
+    // Test that we do NPE checks on array length.
+    exception = null;
+    try {
+      $opt$ArrayLengthOfNull(null);
+    } catch (NullPointerException e) {
+      exception = e;
+    }
+
     if (exception == null) {
       throw new Error("Missing NullPointerException");
     }
@@ -218,5 +226,9 @@
     return 42;
   }
 
+  public static int $opt$ArrayLengthOfNull(int[] array) {
+    return array.length;
+  }
+
   Object o;
 }
diff --git a/test/406-fields/src/Main.java b/test/406-fields/src/Main.java
index 3e94e42..768a784 100644
--- a/test/406-fields/src/Main.java
+++ b/test/406-fields/src/Main.java
@@ -30,6 +30,8 @@
     assertEquals(0, fields.iI);
     assertEquals(0, fields.iJ);
     assertEquals(0, fields.iS);
+    assertEquals(0.0f, fields.iF);
+    assertEquals(0.0, fields.iD);
     assertNull(fields.iObject);
 
     long longValue = -1122198787987987987L;
@@ -40,6 +42,8 @@
     fields.iJ = longValue;
     fields.iS = 68;
     fields.iObject = fields;
+    fields.iF = 2.3f;
+    fields.iD = 5.3;
 
     assertEquals(true, fields.iZ);
     assertEquals(-2, fields.iB);
@@ -48,6 +52,8 @@
     assertEquals(longValue, fields.iJ);
     assertEquals(68, fields.iS);
     assertEquals(fields, fields.iObject);
+    assertEquals(2.3f, fields.iF);
+    assertEquals(5.3, fields.iD);
   }
 
   static class AllFields {
diff --git a/test/407-arrays/src/Main.java b/test/407-arrays/src/Main.java
index b5e95b0..d5c5604 100644
--- a/test/407-arrays/src/Main.java
+++ b/test/407-arrays/src/Main.java
@@ -70,6 +70,15 @@
     chars[index] = 'd';
     assertEquals('d', chars[index]);
 
+    chars[0] = 65535;
+    assertEquals(65535, chars[0]);
+    // Do an update between the two max value updates, to avoid
+    // optimizing the second away.
+    chars[index] = 0;
+    assertEquals(0, chars[index]);
+    chars[index] = 65535;
+    assertEquals(65535, chars[index]);
+
     shorts[0] = -42;
     assertEquals(-42, shorts[0]);
     shorts[index] = -84;
@@ -86,7 +95,13 @@
     Object o2 = new Object();
     objects[index] = o2;
     assertEquals(o2, objects[index]);
+    // Longs are initially not supported in the linear scan register allocator
+    // on 32bits. So we call out a long helper to ensure this method gets
+    // optimized.
+    $opt$testLongWrites(longs, index);
+  }
 
+  public static void $opt$testLongWrites(long[] longs, int index) {
     long l = -21876876876876876L;
     longs[0] = l;
     assertEquals(l, longs[0]);
diff --git a/test/410-floats/expected.txt b/test/410-floats/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/410-floats/expected.txt
diff --git a/test/410-floats/info.txt b/test/410-floats/info.txt
new file mode 100644
index 0000000..5332704
--- /dev/null
+++ b/test/410-floats/info.txt
@@ -0,0 +1 @@
+Small tests involving floats and doubles.
diff --git a/test/410-floats/src/Main.java b/test/410-floats/src/Main.java
new file mode 100644
index 0000000..2300457
--- /dev/null
+++ b/test/410-floats/src/Main.java
@@ -0,0 +1,140 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    assertEquals(4.2f, returnFloat());
+    float[] a = new float[2];
+    a[0] = 42.2f;
+    a[1] = 3.2f;
+    assertEquals(45.4f, returnFloat(a));
+
+    assertEquals(4.4, returnDouble());
+    double[] b = new double[1];
+    b[0] = 42.4;
+    assertEquals(42.4, returnDouble(b));
+
+    assertEquals(4.2f, invokeReturnFloat());
+    assertEquals(4.4, invokeReturnDouble());
+    assertEquals(4.2f, takeAFloat(4.2f));
+    assertEquals(3.1, takeADouble(3.1));
+    assertEquals(12.7, takeThreeDouble(3.1, 4.4, 5.2));
+    assertEquals(12.7f, takeThreeFloat(3.1f, 4.4f, 5.2f));
+    assertEquals(4.2f, invokeTakeAFloat(4.2f));
+    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() {
+    return returnFloat();
+  }
+
+  public static double invokeReturnDouble() {
+    return returnDouble();
+  }
+
+  public static float returnFloat() {
+    return 4.2f;
+  }
+
+  public static float returnFloat(float[] a) {
+    return a[0] + a[1];
+  }
+
+  public static double returnDouble() {
+    return 4.4;
+  }
+
+  public static double returnDouble(double[] a) {
+    return a[0];
+  }
+
+  public static float takeAFloat(float a) {
+    return a;
+  }
+
+  public static double takeADouble(double a) {
+    return a;
+  }
+
+  public static double takeThreeDouble(double a, double b, double c) {
+    return a + b + c;
+  }
+
+  public static float takeThreeFloat(float a, float b, float c) {
+    return a + b + c;
+  }
+
+  public static float invokeTakeAFloat(float a) {
+    return takeAFloat(a);
+  }
+
+  public static double invokeTakeADouble(double a) {
+    return takeADouble(a);
+  }
+
+  public static double invokeTakeThreeDouble(double a, double b, double c) {
+    return takeThreeDouble(a, b, c);
+  }
+
+  public static float invokeTakeThreeFloat(float a, float b, float c) {
+    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);
+    }
+  }
+
+  public static void assertEquals(double expected, double 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..3a5d7c0
--- /dev/null
+++ b/test/411-optimizing-arith/src/Main.java
@@ -0,0 +1,181 @@
+/*
+ * 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();
+  }
+
+  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) * 11L);
+    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));
+  }
+
+  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;
+  }
+}
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..168420c
--- /dev/null
+++ b/test/412-new-array/src/Main.java
@@ -0,0 +1,438 @@
+/*
+ * 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();
+    $opt$TestNegativeValueNewByteArray();
+    $opt$TestNegativeValueNewCharArray();
+    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]);
+  }
+
+  static void $opt$TestNegativeValueNewByteArray() {
+    // Use an array initializer to hint the use of filled-new-array.
+    byte[] a = { (byte)0xa0, (byte)0xa1, (byte)0xa2, (byte)0xa3,
+                 (byte)0xa4, (byte)0xa5, (byte)0xa6, (byte)0xa7 };
+    for (int i = 0; i < a.length; i++) {
+      assertEquals((byte)0xa0 + i, a[i]);
+    }
+  }
+
+  static void $opt$TestNegativeValueNewCharArray() {
+    // Use an array initializer to hint the use of filled-new-array.
+    char[] a = { (char)0xa000, (char)0xa001, (char)0xa002, (char)0xa003,
+                 (char)0xa004, (char)0xa005, (char)0xa006, (char)0xa007 };
+    for (int i = 0; i < a.length; i++) {
+      assertEquals((char)0xa000 + i, a[i]);
+    }
+  }
+
+  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/414-static-fields/expected.txt b/test/414-static-fields/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/414-static-fields/expected.txt
diff --git a/test/414-static-fields/info.txt b/test/414-static-fields/info.txt
new file mode 100644
index 0000000..1cdd3c7
--- /dev/null
+++ b/test/414-static-fields/info.txt
@@ -0,0 +1 @@
+Simple test for static field access.
diff --git a/test/414-static-fields/src/Main.java b/test/414-static-fields/src/Main.java
new file mode 100644
index 0000000..3403772
--- /dev/null
+++ b/test/414-static-fields/src/Main.java
@@ -0,0 +1,98 @@
+/*
+ * 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 extends TestCase {
+  public static void main(String[] args) {
+    $opt$TestThisClassStaticField();
+    $opt$TestOtherClassStaticField();
+    $opt$TestAddThisClassStaticField();
+    $opt$TestAddOtherClassStaticField();
+    $opt$TestOtherClassWithClinitStaticField();
+    $opt$TestAccess();
+  }
+
+  static int staticField = 42;
+
+  static int getInt() {
+    return 33;
+  }
+
+  static void $opt$TestThisClassStaticField() {
+    assertEquals(42, staticField);
+  }
+
+  static void $opt$TestOtherClassStaticField() {
+    assertEquals(41, Other.staticField);
+  }
+
+  static void $opt$TestAddThisClassStaticField() {
+    int a = getInt();
+    assertEquals(a + 42, a + staticField);
+  }
+
+  static void $opt$TestAddOtherClassStaticField() {
+    int a = getInt();
+    assertEquals(a + 41, a + Other.staticField);
+  }
+
+  static void $opt$TestOtherClassWithClinitStaticField() {
+    assertEquals(40, OtherWithClinit.staticField);
+  }
+
+  static void $opt$TestAccess() {
+    assertEquals(false, sZ);
+    assertEquals(0, sB);
+    assertEquals(0, sC);
+    assertEquals(0, sI);
+    assertEquals(0, sJ);
+    assertEquals(0, sS);
+    assertEquals(0.0f, sF);
+    assertEquals(0.0, sD);
+    assertNull(sObject);
+
+    long longValue = -1122198787987987987L;
+    Object o = new Object();
+    sZ = true;
+    sB = -2;
+    sC = 'c';
+    sI = 42;
+    sJ = longValue;
+    sS = 68;
+    sObject = o;
+    sF = 2.3f;
+    sD = 5.3;
+
+    assertEquals(true, sZ);
+    assertEquals(-2, sB);
+    assertEquals('c', sC);
+    assertEquals(42, sI);
+    assertEquals(longValue, sJ);
+    assertEquals(68, sS);
+    assertEquals(o, sObject);
+    assertEquals(2.3f, sF);
+    assertEquals(5.3, sD);
+  }
+
+  static boolean sZ;
+  static byte sB;
+  static char sC;
+  static double sD;
+  static float sF;
+  static int sI;
+  static long sJ;
+  static short sS;
+  static Object sObject;
+}
diff --git a/test/414-static-fields/src/Other.java b/test/414-static-fields/src/Other.java
new file mode 100644
index 0000000..aede930
--- /dev/null
+++ b/test/414-static-fields/src/Other.java
@@ -0,0 +1,19 @@
+/*
+ * 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 Other {
+  static int staticField = 41;
+}
diff --git a/test/414-static-fields/src/OtherWithClinit.java b/test/414-static-fields/src/OtherWithClinit.java
new file mode 100644
index 0000000..eafbd2b
--- /dev/null
+++ b/test/414-static-fields/src/OtherWithClinit.java
@@ -0,0 +1,23 @@
+/*
+ * 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 OtherWithClinit {
+  static int staticField = 39;
+
+  static {
+    staticField = 40;
+  }
+}
diff --git a/test/414-static-fields/src/TestCase.java b/test/414-static-fields/src/TestCase.java
new file mode 100644
index 0000000..ef77f71
--- /dev/null
+++ b/test/414-static-fields/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/415-optimizing-arith-neg/expected.txt b/test/415-optimizing-arith-neg/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/415-optimizing-arith-neg/expected.txt
diff --git a/test/415-optimizing-arith-neg/info.txt b/test/415-optimizing-arith-neg/info.txt
new file mode 100644
index 0000000..8494aad
--- /dev/null
+++ b/test/415-optimizing-arith-neg/info.txt
@@ -0,0 +1 @@
+Tests for arithmetic negation operations.
diff --git a/test/415-optimizing-arith-neg/src/Main.java b/test/415-optimizing-arith-neg/src/Main.java
new file mode 100644
index 0000000..bd8a158
--- /dev/null
+++ b/test/415-optimizing-arith-neg/src/Main.java
@@ -0,0 +1,195 @@
+/*
+ * 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 assertEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertEquals(String expected, float result) {
+    if (!expected.equals(new Float(result).toString())) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertEquals(String expected, double result) {
+    if (!expected.equals(new Double(result).toString())) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertIsNaN(float result) {
+    if (!Float.isNaN(result)) {
+      throw new Error("Expected NaN: " + result);
+    }
+  }
+
+  public static void assertIsNaN(double result) {
+    if (!Double.isNaN(result)) {
+      throw new Error("Expected NaN: " + result);
+    }
+  }
+
+  public static void main(String[] args) {
+    negInt();
+    $opt$InplaceNegOneInt(1);
+
+    negLong();
+    $opt$InplaceNegOneLong(1L);
+
+    negFloat();
+    negDouble();
+  }
+
+  private static void negInt() {
+    assertEquals(-1, $opt$NegInt(1));
+    assertEquals(1, $opt$NegInt(-1));
+    assertEquals(0, $opt$NegInt(0));
+    assertEquals(51, $opt$NegInt(-51));
+    assertEquals(-51, $opt$NegInt(51));
+    assertEquals(2147483647, $opt$NegInt(-2147483647));  // -(2^31 - 1)
+    assertEquals(-2147483647, $opt$NegInt(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.''
+    assertEquals(-2147483648, $opt$NegInt(-2147483648)); // -(2^31)
+  }
+
+  private static void $opt$InplaceNegOneInt(int a) {
+    a = -a;
+    assertEquals(-1, a);
+  }
+
+  private static void negLong() {
+    assertEquals(-1L, $opt$NegLong(1L));
+    assertEquals(1L, $opt$NegLong(-1L));
+    assertEquals(0L, $opt$NegLong(0L));
+    assertEquals(51L, $opt$NegLong(-51L));
+    assertEquals(-51L, $opt$NegLong(51L));
+
+    assertEquals(2147483647L, $opt$NegLong(-2147483647L));  // -(2^31 - 1)
+    assertEquals(-2147483647L, $opt$NegLong(2147483647L));  // (2^31 - 1)
+    assertEquals(2147483648L, $opt$NegLong(-2147483648L));  // -(2^31)
+    assertEquals(-2147483648L, $opt$NegLong(2147483648L));  // 2^31
+
+    assertEquals(9223372036854775807L, $opt$NegLong(-9223372036854775807L));  // -(2^63 - 1)
+    assertEquals(-9223372036854775807L, $opt$NegLong(9223372036854775807L));  // 2^63 - 1
+    // See remark regarding the negation of the maximum negative
+    // (long) value in negInt().
+    assertEquals(-9223372036854775808L, $opt$NegLong(-9223372036854775808L)); // -(2^63)
+  }
+
+  private static void $opt$InplaceNegOneLong(long a) {
+    a = -a;
+    assertEquals(-1L, a);
+  }
+
+  private static void negFloat() {
+     assertEquals("-0.0", $opt$NegFloat(0F));
+     assertEquals("0.0", $opt$NegFloat(-0F));
+     assertEquals(-1F, $opt$NegFloat(1F));
+     assertEquals(1F, $opt$NegFloat(-1F));
+     assertEquals(51F, $opt$NegFloat(-51F));
+     assertEquals(-51F, $opt$NegFloat(51F));
+
+     assertEquals(-0.1F, $opt$NegFloat(0.1F));
+     assertEquals(0.1F, $opt$NegFloat(-0.1F));
+     assertEquals(343597.38362F, $opt$NegFloat(-343597.38362F));
+     assertEquals(-343597.38362F, $opt$NegFloat(343597.38362F));
+
+     assertEquals(-Float.MIN_NORMAL, $opt$NegFloat(Float.MIN_NORMAL));
+     assertEquals(Float.MIN_NORMAL, $opt$NegFloat(-Float.MIN_NORMAL));
+     assertEquals(-Float.MIN_VALUE, $opt$NegFloat(Float.MIN_VALUE));
+     assertEquals(Float.MIN_VALUE, $opt$NegFloat(-Float.MIN_VALUE));
+     assertEquals(-Float.MAX_VALUE, $opt$NegFloat(Float.MAX_VALUE));
+     assertEquals(Float.MAX_VALUE, $opt$NegFloat(-Float.MAX_VALUE));
+
+     assertEquals(Float.NEGATIVE_INFINITY, $opt$NegFloat(Float.POSITIVE_INFINITY));
+     assertEquals(Float.POSITIVE_INFINITY, $opt$NegFloat(Float.NEGATIVE_INFINITY));
+     assertIsNaN($opt$NegFloat(Float.NaN));
+  }
+
+  private static void negDouble() {
+     assertEquals("-0.0", $opt$NegDouble(0D));
+     assertEquals("0.0", $opt$NegDouble(-0D));
+     assertEquals(-1D, $opt$NegDouble(1D));
+     assertEquals(1D, $opt$NegDouble(-1D));
+     assertEquals(51D, $opt$NegDouble(-51D));
+     assertEquals(-51D, $opt$NegDouble(51D));
+
+     assertEquals(-0.1D, $opt$NegDouble(0.1D));
+     assertEquals(0.1D, $opt$NegDouble(-0.1D));
+     assertEquals(343597.38362D, $opt$NegDouble(-343597.38362D));
+     assertEquals(-343597.38362D, $opt$NegDouble(343597.38362D));
+
+     assertEquals(-Double.MIN_NORMAL, $opt$NegDouble(Double.MIN_NORMAL));
+     assertEquals(Double.MIN_NORMAL, $opt$NegDouble(-Double.MIN_NORMAL));
+     assertEquals(-Double.MIN_VALUE, $opt$NegDouble(Double.MIN_VALUE));
+     assertEquals(Double.MIN_VALUE, $opt$NegDouble(-Double.MIN_VALUE));
+     assertEquals(-Double.MAX_VALUE, $opt$NegDouble(Double.MAX_VALUE));
+     assertEquals(Double.MAX_VALUE, $opt$NegDouble(-Double.MAX_VALUE));
+
+     assertEquals(Double.NEGATIVE_INFINITY, $opt$NegDouble(Double.POSITIVE_INFINITY));
+     assertEquals(Double.POSITIVE_INFINITY, $opt$NegDouble(Double.NEGATIVE_INFINITY));
+     assertIsNaN($opt$NegDouble(Double.NaN));
+  }
+
+  static int $opt$NegInt(int a){
+    return -a;
+  }
+
+  static long $opt$NegLong(long a){
+    return -a;
+  }
+
+  static float $opt$NegFloat(float a){
+    return -a;
+  }
+
+  static double $opt$NegDouble(double a){
+    return -a;
+  }
+}
diff --git a/test/416-optimizing-arith-not/expected.txt b/test/416-optimizing-arith-not/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/416-optimizing-arith-not/expected.txt
diff --git a/test/416-optimizing-arith-not/info.txt b/test/416-optimizing-arith-not/info.txt
new file mode 100644
index 0000000..e9418fd
--- /dev/null
+++ b/test/416-optimizing-arith-not/info.txt
@@ -0,0 +1 @@
+Tests for bitwise not operations.
diff --git a/test/416-optimizing-arith-not/smali/not.smali b/test/416-optimizing-arith-not/smali/not.smali
new file mode 100644
index 0000000..6dea3b6
--- /dev/null
+++ b/test/416-optimizing-arith-not/smali/not.smali
@@ -0,0 +1,15 @@
+.class public LTestNot;
+
+.super Ljava/lang/Object;
+
+.method public static $opt$NotInt(I)I
+   .registers 2
+   not-int v0, v1
+   return v0
+.end method
+
+.method public static $opt$NotLong(J)J
+   .registers 4
+   not-long v0, v2
+   return-wide v0
+.end method
diff --git a/test/416-optimizing-arith-not/src/Main.java b/test/416-optimizing-arith-not/src/Main.java
new file mode 100644
index 0000000..44c7d3c
--- /dev/null
+++ b/test/416-optimizing-arith-not/src/Main.java
@@ -0,0 +1,79 @@
+/*
+ * 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.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 main(String[] args) throws Exception {
+    notInt();
+    notLong();
+  }
+
+  private static void notInt() throws Exception {
+    expectEquals(1, smaliNotInt(-2));
+    expectEquals(0, smaliNotInt(-1));
+    expectEquals(-1, smaliNotInt(0));
+    expectEquals(-2, smaliNotInt(1));
+    expectEquals(2147483647, smaliNotInt(-2147483648));  // -(2^31)
+    expectEquals(2147483646, smaliNotInt(-2147483647));  // -(2^31 - 1)
+    expectEquals(-2147483647, smaliNotInt(2147483646));  // 2^31 - 2
+    expectEquals(-2147483648, smaliNotInt(2147483647));  // 2^31 - 1
+  }
+
+  private static void notLong() throws Exception {
+    expectEquals(1L, smaliNotLong(-2L));
+    expectEquals(0L, smaliNotLong(-1L));
+    expectEquals(-1L, smaliNotLong(0L));
+    expectEquals(-2L, smaliNotLong(1L));
+    expectEquals(2147483647L, smaliNotLong(-2147483648L));  // -(2^31)
+    expectEquals(2147483646L, smaliNotLong(-2147483647L));  // -(2^31 - 1)
+    expectEquals(-2147483647L, smaliNotLong(2147483646L));  // 2^31 - 2
+    expectEquals(-2147483648L, smaliNotLong(2147483647L));  // 2^31 - 1
+    expectEquals(9223372036854775807L, smaliNotLong(-9223372036854775808L));  // -(2^63)
+    expectEquals(9223372036854775806L, smaliNotLong(-9223372036854775807L));  // -(2^63 - 1)
+    expectEquals(-9223372036854775807L, smaliNotLong(9223372036854775806L));  // 2^63 - 2
+    expectEquals(-9223372036854775808L, smaliNotLong(9223372036854775807L));  // 2^63 - 1
+  }
+
+  // Wrappers around methods located in file not.smali.
+
+  private static int smaliNotInt(int a) throws Exception {
+    Class<?> c = Class.forName("TestNot");
+    Method m = c.getMethod("$opt$NotInt", int.class);
+    int result = (Integer)m.invoke(null, a);
+    return result;
+  }
+
+  private static long smaliNotLong(long a) throws Exception {
+    Class<?> c = Class.forName("TestNot");
+    Method m = c.getMethod("$opt$NotLong", long.class);
+    long result = (Long)m.invoke(null, a);
+    return result;
+  }
+}
diff --git a/test/417-optimizing-arith-div/expected.txt b/test/417-optimizing-arith-div/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/417-optimizing-arith-div/expected.txt
diff --git a/test/417-optimizing-arith-div/info.txt b/test/417-optimizing-arith-div/info.txt
new file mode 100644
index 0000000..1374b0f
--- /dev/null
+++ b/test/417-optimizing-arith-div/info.txt
@@ -0,0 +1 @@
+Tests for division operation.
diff --git a/test/417-optimizing-arith-div/src/Main.java b/test/417-optimizing-arith-div/src/Main.java
new file mode 100644
index 0000000..909ceb4
--- /dev/null
+++ b/test/417-optimizing-arith-div/src/Main.java
@@ -0,0 +1,254 @@
+/*
+ * 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.00001F;
+    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 expectDivisionByZero(int value) {
+    try {
+      $opt$Div(value, 0);
+      throw new Error("Expected RuntimeException when dividing by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+    try {
+      $opt$DivZero(value);
+      throw new Error("Expected RuntimeException when dividing by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+  }
+
+  public static void expectDivisionByZero(long value) {
+    try {
+      $opt$Div(value, 0L);
+      throw new Error("Expected RuntimeException when dividing by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+    try {
+      $opt$DivZero(value);
+      throw new Error("Expected RuntimeException when dividing by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+  }
+
+  public static void main(String[] args) {
+    div();
+  }
+
+  public static void div() {
+    divInt();
+    divLong();
+    divFloat();
+    divDouble();
+  }
+
+  private static void divInt() {
+    expectEquals(2, $opt$DivConst(6));
+    expectEquals(2, $opt$Div(6, 3));
+    expectEquals(6, $opt$Div(6, 1));
+    expectEquals(-2, $opt$Div(6, -3));
+    expectEquals(1, $opt$Div(4, 3));
+    expectEquals(-1, $opt$Div(4, -3));
+    expectEquals(5, $opt$Div(23, 4));
+    expectEquals(-5, $opt$Div(-23, 4));
+
+    expectEquals(-Integer.MAX_VALUE, $opt$Div(Integer.MAX_VALUE, -1));
+    expectEquals(Integer.MIN_VALUE, $opt$Div(Integer.MIN_VALUE, -1)); // overflow
+    expectEquals(-1073741824, $opt$Div(Integer.MIN_VALUE, 2));
+
+    expectEquals(0, $opt$Div(0, Integer.MAX_VALUE));
+    expectEquals(0, $opt$Div(0, Integer.MIN_VALUE));
+
+    expectDivisionByZero(0);
+    expectDivisionByZero(1);
+    expectDivisionByZero(Integer.MAX_VALUE);
+    expectDivisionByZero(Integer.MIN_VALUE);
+  }
+
+  private static void divLong() {
+    expectEquals(2L, $opt$DivConst(6L));
+    expectEquals(2L, $opt$Div(6L, 3L));
+    expectEquals(6L, $opt$Div(6L, 1L));
+    expectEquals(-2L, $opt$Div(6L, -3L));
+    expectEquals(1L, $opt$Div(4L, 3L));
+    expectEquals(-1L, $opt$Div(4L, -3L));
+    expectEquals(5L, $opt$Div(23L, 4L));
+    expectEquals(-5L, $opt$Div(-23L, 4L));
+
+    expectEquals(-Integer.MAX_VALUE, $opt$Div(Integer.MAX_VALUE, -1L));
+    expectEquals(2147483648L, $opt$Div(Integer.MIN_VALUE, -1L));
+    expectEquals(-1073741824L, $opt$Div(Integer.MIN_VALUE, 2L));
+
+    expectEquals(-Long.MAX_VALUE, $opt$Div(Long.MAX_VALUE, -1L));
+    expectEquals(Long.MIN_VALUE, $opt$Div(Long.MIN_VALUE, -1L)); // overflow
+
+    expectEquals(11111111111111L, $opt$Div(33333333333333L, 3L));
+    expectEquals(3L, $opt$Div(33333333333333L, 11111111111111L));
+
+    expectEquals(0L, $opt$Div(0L, Long.MAX_VALUE));
+    expectEquals(0L, $opt$Div(0L, Long.MIN_VALUE));
+
+    expectDivisionByZero(0L);
+    expectDivisionByZero(1L);
+    expectDivisionByZero(Long.MAX_VALUE);
+    expectDivisionByZero(Long.MIN_VALUE);
+  }
+
+  private static void divFloat() {
+    expectApproxEquals(1.6666666F, $opt$Div(5F, 3F));
+    expectApproxEquals(0F, $opt$Div(0F, 3F));
+    expectApproxEquals(-0.3333333F, $opt$Div(1F, -3F));
+    expectApproxEquals(4F, $opt$Div(-12F, -3F));
+    expectApproxEquals(0.5, $opt$Div(0.1F, 0.2F));
+    expectApproxEquals(-2.5F, $opt$Div(-0.5F, 0.2F));
+
+    expectEquals(0F, $opt$Div(0F, Float.POSITIVE_INFINITY));
+    expectEquals(0F, $opt$Div(11F, Float.POSITIVE_INFINITY));
+    expectEquals(0F, $opt$Div(0F, Float.NEGATIVE_INFINITY));
+    expectEquals(0F, $opt$Div(11F, Float.NEGATIVE_INFINITY));
+
+    expectNaN($opt$Div(0F, 0F));
+    expectNaN($opt$Div(Float.NaN, 11F));
+    expectNaN($opt$Div(-11F, Float.NaN));
+    expectNaN($opt$Div(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Div(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Div(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Div(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Div(Float.NaN, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Div(Float.POSITIVE_INFINITY, Float.NaN));
+
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Div(3F, 0F));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Div(-3F, 0F));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Div(Float.MAX_VALUE, Float.MIN_VALUE));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Div(-Float.MAX_VALUE, Float.MIN_VALUE));
+  }
+
+  private static void divDouble() {
+    expectApproxEquals(1.6666666D, $opt$Div(5D, 3D));
+    expectApproxEquals(0D, $opt$Div(0D, 3D));
+    expectApproxEquals(-0.3333333D, $opt$Div(1D, -3D));
+    expectApproxEquals(4D, $opt$Div(-12D, -3D));
+    expectApproxEquals(0.5, $opt$Div(0.1D, 0.2D));
+    expectApproxEquals(-2.5D, $opt$Div(-0.5D, 0.2D));
+
+    expectEquals(0D, $opt$Div(0D, Float.POSITIVE_INFINITY));
+    expectEquals(0D, $opt$Div(11D, Float.POSITIVE_INFINITY));
+    expectEquals(0D, $opt$Div(0D, Float.NEGATIVE_INFINITY));
+    expectEquals(0D, $opt$Div(11D, Float.NEGATIVE_INFINITY));
+
+    expectNaN($opt$Div(0D, 0D));
+    expectNaN($opt$Div(Float.NaN, 11D));
+    expectNaN($opt$Div(-11D, Float.NaN));
+    expectNaN($opt$Div(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Div(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Div(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Div(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Div(Float.NaN, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Div(Float.POSITIVE_INFINITY, Float.NaN));
+
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Div(3D, 0D));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Div(-3D, 0D));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Div(Float.MAX_VALUE, Float.MIN_VALUE));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Div(-Float.MAX_VALUE, Float.MIN_VALUE));
+  }
+
+  static int $opt$Div(int a, int b) {
+    return a / b;
+  }
+
+  static int $opt$DivZero(int a) {
+    return a / 0;
+  }
+
+  // Division by literals != 0 should not generate checks.
+  static int $opt$DivConst(int a) {
+    return a / 3;
+  }
+
+  static long $opt$DivConst(long a) {
+    return a / 3L;
+  }
+
+  static long $opt$Div(long a, long b) {
+    return a / b;
+  }
+
+  static long $opt$DivZero(long a) {
+    return a / 0L;
+  }
+
+  static float $opt$Div(float a, float b) {
+    return a / b;
+  }
+
+  static double $opt$Div(double a, double b) {
+    return a / b;
+  }
+}
diff --git a/test/418-const-string/expected.txt b/test/418-const-string/expected.txt
new file mode 100644
index 0000000..8254f87
--- /dev/null
+++ b/test/418-const-string/expected.txt
@@ -0,0 +1,2 @@
+Hello World
+Hello World
diff --git a/test/418-const-string/info.txt b/test/418-const-string/info.txt
new file mode 100644
index 0000000..b7a468f
--- /dev/null
+++ b/test/418-const-string/info.txt
@@ -0,0 +1 @@
+Small test case for testing CONST_STRING.
diff --git a/test/418-const-string/src/Main.java b/test/418-const-string/src/Main.java
new file mode 100644
index 0000000..7c1ffec
--- /dev/null
+++ b/test/418-const-string/src/Main.java
@@ -0,0 +1,28 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    // First call: may go in slow path.
+    System.out.println($opt$ReturnHelloWorld());
+    // Second call: no slow path.
+    System.out.println($opt$ReturnHelloWorld());
+  }
+
+  public static String $opt$ReturnHelloWorld() {
+    return "Hello World";
+  }
+}
diff --git a/test/419-long-parameter/expected.txt b/test/419-long-parameter/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/419-long-parameter/expected.txt
diff --git a/test/419-long-parameter/info.txt b/test/419-long-parameter/info.txt
new file mode 100644
index 0000000..5eac977
--- /dev/null
+++ b/test/419-long-parameter/info.txt
@@ -0,0 +1,3 @@
+Regression test for the long parameter passed both in stack and register
+on 32bits architectures. The move to hard float ABI makes it so that the
+register index does not necessarily match the stack index anymore.
diff --git a/test/419-long-parameter/src/Main.java b/test/419-long-parameter/src/Main.java
new file mode 100644
index 0000000..808b7f6
--- /dev/null
+++ b/test/419-long-parameter/src/Main.java
@@ -0,0 +1,34 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    if ($opt$TestCallee(1.0, 2.0, 1L, 2L) != 1L) {
+      throw new Error("Unexpected result");
+    }
+    if ($opt$TestCaller() != 1L) {
+      throw new Error("Unexpected result");
+    }
+  }
+
+  public static long $opt$TestCallee(double a, double b, long c, long d) {
+    return d - c;
+  }
+
+  public static long $opt$TestCaller() {
+    return $opt$TestCallee(1.0, 2.0, 1L, 2L);
+  }
+}
diff --git a/test/420-const-class/expected.txt b/test/420-const-class/expected.txt
new file mode 100644
index 0000000..3213026
--- /dev/null
+++ b/test/420-const-class/expected.txt
@@ -0,0 +1,16 @@
+class Main
+class Main
+class Main$Other
+class Main$Other
+class java.lang.System
+class java.lang.System
+Hello from OtherWithClinit
+42
+class Main$OtherWithClinit
+42
+class Main$OtherWithClinit
+class Main$OtherWithClinit2
+Hello from OtherWithClinit2
+43
+class Main$OtherWithClinit2
+43
diff --git a/test/420-const-class/info.txt b/test/420-const-class/info.txt
new file mode 100644
index 0000000..81cbac7
--- /dev/null
+++ b/test/420-const-class/info.txt
@@ -0,0 +1 @@
+Test for the CONST_CLASS opcode.
diff --git a/test/420-const-class/src/Main.java b/test/420-const-class/src/Main.java
new file mode 100644
index 0000000..44a7436
--- /dev/null
+++ b/test/420-const-class/src/Main.java
@@ -0,0 +1,77 @@
+/*
+ * 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 {
+  static class Other {
+  }
+
+  static class OtherWithClinit {
+    static int a;
+    static {
+      System.out.println("Hello from OtherWithClinit");
+      a = 42;
+    }
+  }
+
+  static class OtherWithClinit2 {
+    static int a;
+    static {
+      System.out.println("Hello from OtherWithClinit2");
+      a = 43;
+    }
+  }
+
+  public static void main(String[] args) {
+    // Call methods twice in case they have a slow path.
+
+    System.out.println($opt$LoadThisClass());
+    System.out.println($opt$LoadThisClass());
+
+    System.out.println($opt$LoadOtherClass());
+    System.out.println($opt$LoadOtherClass());
+
+    System.out.println($opt$LoadSystemClass());
+    System.out.println($opt$LoadSystemClass());
+
+    $opt$ClinitCheckAndLoad();
+    $opt$ClinitCheckAndLoad();
+
+    $opt$LoadAndClinitCheck();
+    $opt$LoadAndClinitCheck();
+  }
+
+  public static Class $opt$LoadThisClass() {
+    return Main.class;
+  }
+
+  public static Class $opt$LoadOtherClass() {
+    return Other.class;
+  }
+
+  public static Class $opt$LoadSystemClass() {
+    return System.class;
+  }
+
+  public static void $opt$ClinitCheckAndLoad() {
+    System.out.println(OtherWithClinit.a);
+    System.out.println(OtherWithClinit.class);
+  }
+
+  public static void $opt$LoadAndClinitCheck() {
+    System.out.println(OtherWithClinit2.class);
+    System.out.println(OtherWithClinit2.a);
+  }
+}
diff --git a/test/421-exceptions/expected.txt b/test/421-exceptions/expected.txt
new file mode 100644
index 0000000..94db350
--- /dev/null
+++ b/test/421-exceptions/expected.txt
@@ -0,0 +1,20 @@
+1
+3
+4
+1
+4
+1
+4
+1
+4
+Caught class java.lang.RuntimeException
+1
+2
+4
+1
+4
+1
+4
+1
+4
+Caught class java.lang.NullPointerException
diff --git a/test/421-exceptions/info.txt b/test/421-exceptions/info.txt
new file mode 100644
index 0000000..bdec67e
--- /dev/null
+++ b/test/421-exceptions/info.txt
@@ -0,0 +1 @@
+Simple test for try/catch/throw.
diff --git a/test/421-exceptions/src/Main.java b/test/421-exceptions/src/Main.java
new file mode 100644
index 0000000..6bf2377
--- /dev/null
+++ b/test/421-exceptions/src/Main.java
@@ -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.
+ */
+
+public class Main {
+  public static void $opt$bar() {
+    try {
+      $opt$foo(1);
+    } catch (NullPointerException e) {
+      $opt$foo(2);
+    } catch (RuntimeException e) {
+      $opt$foo(3);
+    } finally {
+      $opt$foo(4);
+    }
+  }
+
+  static int barState;
+  static int fooState;
+
+  public static void main(String[] args) {
+    fooState = 0;
+    $opt$runTest();
+    fooState = 1;
+    $opt$runTest();
+  }
+
+  public static void $opt$runTest() {
+    barState = 1;
+    $opt$bar();
+    barState = 2;
+    $opt$bar();
+    barState = 3;
+    $opt$bar();
+    barState = 4;
+    try {
+      $opt$bar();
+    } catch (RuntimeException e) {
+      System.out.println("Caught " + e.getClass());
+    }
+  }
+
+  public static void $opt$foo(int value) {
+    System.out.println(value);
+    if (value == barState) {
+      if (fooState == 0) {
+        throw new RuntimeException();
+      } else {
+        throw new NullPointerException();
+      }
+    }
+  }
+}
diff --git a/test/421-large-frame/expected.txt b/test/421-large-frame/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/421-large-frame/expected.txt
diff --git a/test/421-large-frame/info.txt b/test/421-large-frame/info.txt
new file mode 100644
index 0000000..d71e7ee
--- /dev/null
+++ b/test/421-large-frame/info.txt
@@ -0,0 +1 @@
+Tests for large stack frames.
diff --git a/test/421-large-frame/src/Main.java b/test/421-large-frame/src/Main.java
new file mode 100644
index 0000000..dae72fb
--- /dev/null
+++ b/test/421-large-frame/src/Main.java
@@ -0,0 +1,2039 @@
+/*
+ * 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 assertEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void main(String[] args) {
+    // Sum[i = 0..999](i) = 999 * 1000 / 2 = 499500L.
+    assertEquals(499500L, $opt$LargeFrame());
+  }
+
+  static long $opt$LargeFrame() {
+    long l0 = 0L;
+    long l1 = 1L;
+    long l2 = 2L;
+    long l3 = 3L;
+    long l4 = 4L;
+    long l5 = 5L;
+    long l6 = 6L;
+    long l7 = 7L;
+    long l8 = 8L;
+    long l9 = 9L;
+    long l10 = 10L;
+    long l11 = 11L;
+    long l12 = 12L;
+    long l13 = 13L;
+    long l14 = 14L;
+    long l15 = 15L;
+    long l16 = 16L;
+    long l17 = 17L;
+    long l18 = 18L;
+    long l19 = 19L;
+    long l20 = 20L;
+    long l21 = 21L;
+    long l22 = 22L;
+    long l23 = 23L;
+    long l24 = 24L;
+    long l25 = 25L;
+    long l26 = 26L;
+    long l27 = 27L;
+    long l28 = 28L;
+    long l29 = 29L;
+    long l30 = 30L;
+    long l31 = 31L;
+    long l32 = 32L;
+    long l33 = 33L;
+    long l34 = 34L;
+    long l35 = 35L;
+    long l36 = 36L;
+    long l37 = 37L;
+    long l38 = 38L;
+    long l39 = 39L;
+    long l40 = 40L;
+    long l41 = 41L;
+    long l42 = 42L;
+    long l43 = 43L;
+    long l44 = 44L;
+    long l45 = 45L;
+    long l46 = 46L;
+    long l47 = 47L;
+    long l48 = 48L;
+    long l49 = 49L;
+    long l50 = 50L;
+    long l51 = 51L;
+    long l52 = 52L;
+    long l53 = 53L;
+    long l54 = 54L;
+    long l55 = 55L;
+    long l56 = 56L;
+    long l57 = 57L;
+    long l58 = 58L;
+    long l59 = 59L;
+    long l60 = 60L;
+    long l61 = 61L;
+    long l62 = 62L;
+    long l63 = 63L;
+    long l64 = 64L;
+    long l65 = 65L;
+    long l66 = 66L;
+    long l67 = 67L;
+    long l68 = 68L;
+    long l69 = 69L;
+    long l70 = 70L;
+    long l71 = 71L;
+    long l72 = 72L;
+    long l73 = 73L;
+    long l74 = 74L;
+    long l75 = 75L;
+    long l76 = 76L;
+    long l77 = 77L;
+    long l78 = 78L;
+    long l79 = 79L;
+    long l80 = 80L;
+    long l81 = 81L;
+    long l82 = 82L;
+    long l83 = 83L;
+    long l84 = 84L;
+    long l85 = 85L;
+    long l86 = 86L;
+    long l87 = 87L;
+    long l88 = 88L;
+    long l89 = 89L;
+    long l90 = 90L;
+    long l91 = 91L;
+    long l92 = 92L;
+    long l93 = 93L;
+    long l94 = 94L;
+    long l95 = 95L;
+    long l96 = 96L;
+    long l97 = 97L;
+    long l98 = 98L;
+    long l99 = 99L;
+    long l100 = 100L;
+    long l101 = 101L;
+    long l102 = 102L;
+    long l103 = 103L;
+    long l104 = 104L;
+    long l105 = 105L;
+    long l106 = 106L;
+    long l107 = 107L;
+    long l108 = 108L;
+    long l109 = 109L;
+    long l110 = 110L;
+    long l111 = 111L;
+    long l112 = 112L;
+    long l113 = 113L;
+    long l114 = 114L;
+    long l115 = 115L;
+    long l116 = 116L;
+    long l117 = 117L;
+    long l118 = 118L;
+    long l119 = 119L;
+    long l120 = 120L;
+    long l121 = 121L;
+    long l122 = 122L;
+    long l123 = 123L;
+    long l124 = 124L;
+    long l125 = 125L;
+    long l126 = 126L;
+    long l127 = 127L;
+    long l128 = 128L;
+    long l129 = 129L;
+    long l130 = 130L;
+    long l131 = 131L;
+    long l132 = 132L;
+    long l133 = 133L;
+    long l134 = 134L;
+    long l135 = 135L;
+    long l136 = 136L;
+    long l137 = 137L;
+    long l138 = 138L;
+    long l139 = 139L;
+    long l140 = 140L;
+    long l141 = 141L;
+    long l142 = 142L;
+    long l143 = 143L;
+    long l144 = 144L;
+    long l145 = 145L;
+    long l146 = 146L;
+    long l147 = 147L;
+    long l148 = 148L;
+    long l149 = 149L;
+    long l150 = 150L;
+    long l151 = 151L;
+    long l152 = 152L;
+    long l153 = 153L;
+    long l154 = 154L;
+    long l155 = 155L;
+    long l156 = 156L;
+    long l157 = 157L;
+    long l158 = 158L;
+    long l159 = 159L;
+    long l160 = 160L;
+    long l161 = 161L;
+    long l162 = 162L;
+    long l163 = 163L;
+    long l164 = 164L;
+    long l165 = 165L;
+    long l166 = 166L;
+    long l167 = 167L;
+    long l168 = 168L;
+    long l169 = 169L;
+    long l170 = 170L;
+    long l171 = 171L;
+    long l172 = 172L;
+    long l173 = 173L;
+    long l174 = 174L;
+    long l175 = 175L;
+    long l176 = 176L;
+    long l177 = 177L;
+    long l178 = 178L;
+    long l179 = 179L;
+    long l180 = 180L;
+    long l181 = 181L;
+    long l182 = 182L;
+    long l183 = 183L;
+    long l184 = 184L;
+    long l185 = 185L;
+    long l186 = 186L;
+    long l187 = 187L;
+    long l188 = 188L;
+    long l189 = 189L;
+    long l190 = 190L;
+    long l191 = 191L;
+    long l192 = 192L;
+    long l193 = 193L;
+    long l194 = 194L;
+    long l195 = 195L;
+    long l196 = 196L;
+    long l197 = 197L;
+    long l198 = 198L;
+    long l199 = 199L;
+    long l200 = 200L;
+    long l201 = 201L;
+    long l202 = 202L;
+    long l203 = 203L;
+    long l204 = 204L;
+    long l205 = 205L;
+    long l206 = 206L;
+    long l207 = 207L;
+    long l208 = 208L;
+    long l209 = 209L;
+    long l210 = 210L;
+    long l211 = 211L;
+    long l212 = 212L;
+    long l213 = 213L;
+    long l214 = 214L;
+    long l215 = 215L;
+    long l216 = 216L;
+    long l217 = 217L;
+    long l218 = 218L;
+    long l219 = 219L;
+    long l220 = 220L;
+    long l221 = 221L;
+    long l222 = 222L;
+    long l223 = 223L;
+    long l224 = 224L;
+    long l225 = 225L;
+    long l226 = 226L;
+    long l227 = 227L;
+    long l228 = 228L;
+    long l229 = 229L;
+    long l230 = 230L;
+    long l231 = 231L;
+    long l232 = 232L;
+    long l233 = 233L;
+    long l234 = 234L;
+    long l235 = 235L;
+    long l236 = 236L;
+    long l237 = 237L;
+    long l238 = 238L;
+    long l239 = 239L;
+    long l240 = 240L;
+    long l241 = 241L;
+    long l242 = 242L;
+    long l243 = 243L;
+    long l244 = 244L;
+    long l245 = 245L;
+    long l246 = 246L;
+    long l247 = 247L;
+    long l248 = 248L;
+    long l249 = 249L;
+    long l250 = 250L;
+    long l251 = 251L;
+    long l252 = 252L;
+    long l253 = 253L;
+    long l254 = 254L;
+    long l255 = 255L;
+    long l256 = 256L;
+    long l257 = 257L;
+    long l258 = 258L;
+    long l259 = 259L;
+    long l260 = 260L;
+    long l261 = 261L;
+    long l262 = 262L;
+    long l263 = 263L;
+    long l264 = 264L;
+    long l265 = 265L;
+    long l266 = 266L;
+    long l267 = 267L;
+    long l268 = 268L;
+    long l269 = 269L;
+    long l270 = 270L;
+    long l271 = 271L;
+    long l272 = 272L;
+    long l273 = 273L;
+    long l274 = 274L;
+    long l275 = 275L;
+    long l276 = 276L;
+    long l277 = 277L;
+    long l278 = 278L;
+    long l279 = 279L;
+    long l280 = 280L;
+    long l281 = 281L;
+    long l282 = 282L;
+    long l283 = 283L;
+    long l284 = 284L;
+    long l285 = 285L;
+    long l286 = 286L;
+    long l287 = 287L;
+    long l288 = 288L;
+    long l289 = 289L;
+    long l290 = 290L;
+    long l291 = 291L;
+    long l292 = 292L;
+    long l293 = 293L;
+    long l294 = 294L;
+    long l295 = 295L;
+    long l296 = 296L;
+    long l297 = 297L;
+    long l298 = 298L;
+    long l299 = 299L;
+    long l300 = 300L;
+    long l301 = 301L;
+    long l302 = 302L;
+    long l303 = 303L;
+    long l304 = 304L;
+    long l305 = 305L;
+    long l306 = 306L;
+    long l307 = 307L;
+    long l308 = 308L;
+    long l309 = 309L;
+    long l310 = 310L;
+    long l311 = 311L;
+    long l312 = 312L;
+    long l313 = 313L;
+    long l314 = 314L;
+    long l315 = 315L;
+    long l316 = 316L;
+    long l317 = 317L;
+    long l318 = 318L;
+    long l319 = 319L;
+    long l320 = 320L;
+    long l321 = 321L;
+    long l322 = 322L;
+    long l323 = 323L;
+    long l324 = 324L;
+    long l325 = 325L;
+    long l326 = 326L;
+    long l327 = 327L;
+    long l328 = 328L;
+    long l329 = 329L;
+    long l330 = 330L;
+    long l331 = 331L;
+    long l332 = 332L;
+    long l333 = 333L;
+    long l334 = 334L;
+    long l335 = 335L;
+    long l336 = 336L;
+    long l337 = 337L;
+    long l338 = 338L;
+    long l339 = 339L;
+    long l340 = 340L;
+    long l341 = 341L;
+    long l342 = 342L;
+    long l343 = 343L;
+    long l344 = 344L;
+    long l345 = 345L;
+    long l346 = 346L;
+    long l347 = 347L;
+    long l348 = 348L;
+    long l349 = 349L;
+    long l350 = 350L;
+    long l351 = 351L;
+    long l352 = 352L;
+    long l353 = 353L;
+    long l354 = 354L;
+    long l355 = 355L;
+    long l356 = 356L;
+    long l357 = 357L;
+    long l358 = 358L;
+    long l359 = 359L;
+    long l360 = 360L;
+    long l361 = 361L;
+    long l362 = 362L;
+    long l363 = 363L;
+    long l364 = 364L;
+    long l365 = 365L;
+    long l366 = 366L;
+    long l367 = 367L;
+    long l368 = 368L;
+    long l369 = 369L;
+    long l370 = 370L;
+    long l371 = 371L;
+    long l372 = 372L;
+    long l373 = 373L;
+    long l374 = 374L;
+    long l375 = 375L;
+    long l376 = 376L;
+    long l377 = 377L;
+    long l378 = 378L;
+    long l379 = 379L;
+    long l380 = 380L;
+    long l381 = 381L;
+    long l382 = 382L;
+    long l383 = 383L;
+    long l384 = 384L;
+    long l385 = 385L;
+    long l386 = 386L;
+    long l387 = 387L;
+    long l388 = 388L;
+    long l389 = 389L;
+    long l390 = 390L;
+    long l391 = 391L;
+    long l392 = 392L;
+    long l393 = 393L;
+    long l394 = 394L;
+    long l395 = 395L;
+    long l396 = 396L;
+    long l397 = 397L;
+    long l398 = 398L;
+    long l399 = 399L;
+    long l400 = 400L;
+    long l401 = 401L;
+    long l402 = 402L;
+    long l403 = 403L;
+    long l404 = 404L;
+    long l405 = 405L;
+    long l406 = 406L;
+    long l407 = 407L;
+    long l408 = 408L;
+    long l409 = 409L;
+    long l410 = 410L;
+    long l411 = 411L;
+    long l412 = 412L;
+    long l413 = 413L;
+    long l414 = 414L;
+    long l415 = 415L;
+    long l416 = 416L;
+    long l417 = 417L;
+    long l418 = 418L;
+    long l419 = 419L;
+    long l420 = 420L;
+    long l421 = 421L;
+    long l422 = 422L;
+    long l423 = 423L;
+    long l424 = 424L;
+    long l425 = 425L;
+    long l426 = 426L;
+    long l427 = 427L;
+    long l428 = 428L;
+    long l429 = 429L;
+    long l430 = 430L;
+    long l431 = 431L;
+    long l432 = 432L;
+    long l433 = 433L;
+    long l434 = 434L;
+    long l435 = 435L;
+    long l436 = 436L;
+    long l437 = 437L;
+    long l438 = 438L;
+    long l439 = 439L;
+    long l440 = 440L;
+    long l441 = 441L;
+    long l442 = 442L;
+    long l443 = 443L;
+    long l444 = 444L;
+    long l445 = 445L;
+    long l446 = 446L;
+    long l447 = 447L;
+    long l448 = 448L;
+    long l449 = 449L;
+    long l450 = 450L;
+    long l451 = 451L;
+    long l452 = 452L;
+    long l453 = 453L;
+    long l454 = 454L;
+    long l455 = 455L;
+    long l456 = 456L;
+    long l457 = 457L;
+    long l458 = 458L;
+    long l459 = 459L;
+    long l460 = 460L;
+    long l461 = 461L;
+    long l462 = 462L;
+    long l463 = 463L;
+    long l464 = 464L;
+    long l465 = 465L;
+    long l466 = 466L;
+    long l467 = 467L;
+    long l468 = 468L;
+    long l469 = 469L;
+    long l470 = 470L;
+    long l471 = 471L;
+    long l472 = 472L;
+    long l473 = 473L;
+    long l474 = 474L;
+    long l475 = 475L;
+    long l476 = 476L;
+    long l477 = 477L;
+    long l478 = 478L;
+    long l479 = 479L;
+    long l480 = 480L;
+    long l481 = 481L;
+    long l482 = 482L;
+    long l483 = 483L;
+    long l484 = 484L;
+    long l485 = 485L;
+    long l486 = 486L;
+    long l487 = 487L;
+    long l488 = 488L;
+    long l489 = 489L;
+    long l490 = 490L;
+    long l491 = 491L;
+    long l492 = 492L;
+    long l493 = 493L;
+    long l494 = 494L;
+    long l495 = 495L;
+    long l496 = 496L;
+    long l497 = 497L;
+    long l498 = 498L;
+    long l499 = 499L;
+    long l500 = 500L;
+    long l501 = 501L;
+    long l502 = 502L;
+    long l503 = 503L;
+    long l504 = 504L;
+    long l505 = 505L;
+    long l506 = 506L;
+    long l507 = 507L;
+    long l508 = 508L;
+    long l509 = 509L;
+    long l510 = 510L;
+    long l511 = 511L;
+    long l512 = 512L;
+    long l513 = 513L;
+    long l514 = 514L;
+    long l515 = 515L;
+    long l516 = 516L;
+    long l517 = 517L;
+    long l518 = 518L;
+    long l519 = 519L;
+    long l520 = 520L;
+    long l521 = 521L;
+    long l522 = 522L;
+    long l523 = 523L;
+    long l524 = 524L;
+    long l525 = 525L;
+    long l526 = 526L;
+    long l527 = 527L;
+    long l528 = 528L;
+    long l529 = 529L;
+    long l530 = 530L;
+    long l531 = 531L;
+    long l532 = 532L;
+    long l533 = 533L;
+    long l534 = 534L;
+    long l535 = 535L;
+    long l536 = 536L;
+    long l537 = 537L;
+    long l538 = 538L;
+    long l539 = 539L;
+    long l540 = 540L;
+    long l541 = 541L;
+    long l542 = 542L;
+    long l543 = 543L;
+    long l544 = 544L;
+    long l545 = 545L;
+    long l546 = 546L;
+    long l547 = 547L;
+    long l548 = 548L;
+    long l549 = 549L;
+    long l550 = 550L;
+    long l551 = 551L;
+    long l552 = 552L;
+    long l553 = 553L;
+    long l554 = 554L;
+    long l555 = 555L;
+    long l556 = 556L;
+    long l557 = 557L;
+    long l558 = 558L;
+    long l559 = 559L;
+    long l560 = 560L;
+    long l561 = 561L;
+    long l562 = 562L;
+    long l563 = 563L;
+    long l564 = 564L;
+    long l565 = 565L;
+    long l566 = 566L;
+    long l567 = 567L;
+    long l568 = 568L;
+    long l569 = 569L;
+    long l570 = 570L;
+    long l571 = 571L;
+    long l572 = 572L;
+    long l573 = 573L;
+    long l574 = 574L;
+    long l575 = 575L;
+    long l576 = 576L;
+    long l577 = 577L;
+    long l578 = 578L;
+    long l579 = 579L;
+    long l580 = 580L;
+    long l581 = 581L;
+    long l582 = 582L;
+    long l583 = 583L;
+    long l584 = 584L;
+    long l585 = 585L;
+    long l586 = 586L;
+    long l587 = 587L;
+    long l588 = 588L;
+    long l589 = 589L;
+    long l590 = 590L;
+    long l591 = 591L;
+    long l592 = 592L;
+    long l593 = 593L;
+    long l594 = 594L;
+    long l595 = 595L;
+    long l596 = 596L;
+    long l597 = 597L;
+    long l598 = 598L;
+    long l599 = 599L;
+    long l600 = 600L;
+    long l601 = 601L;
+    long l602 = 602L;
+    long l603 = 603L;
+    long l604 = 604L;
+    long l605 = 605L;
+    long l606 = 606L;
+    long l607 = 607L;
+    long l608 = 608L;
+    long l609 = 609L;
+    long l610 = 610L;
+    long l611 = 611L;
+    long l612 = 612L;
+    long l613 = 613L;
+    long l614 = 614L;
+    long l615 = 615L;
+    long l616 = 616L;
+    long l617 = 617L;
+    long l618 = 618L;
+    long l619 = 619L;
+    long l620 = 620L;
+    long l621 = 621L;
+    long l622 = 622L;
+    long l623 = 623L;
+    long l624 = 624L;
+    long l625 = 625L;
+    long l626 = 626L;
+    long l627 = 627L;
+    long l628 = 628L;
+    long l629 = 629L;
+    long l630 = 630L;
+    long l631 = 631L;
+    long l632 = 632L;
+    long l633 = 633L;
+    long l634 = 634L;
+    long l635 = 635L;
+    long l636 = 636L;
+    long l637 = 637L;
+    long l638 = 638L;
+    long l639 = 639L;
+    long l640 = 640L;
+    long l641 = 641L;
+    long l642 = 642L;
+    long l643 = 643L;
+    long l644 = 644L;
+    long l645 = 645L;
+    long l646 = 646L;
+    long l647 = 647L;
+    long l648 = 648L;
+    long l649 = 649L;
+    long l650 = 650L;
+    long l651 = 651L;
+    long l652 = 652L;
+    long l653 = 653L;
+    long l654 = 654L;
+    long l655 = 655L;
+    long l656 = 656L;
+    long l657 = 657L;
+    long l658 = 658L;
+    long l659 = 659L;
+    long l660 = 660L;
+    long l661 = 661L;
+    long l662 = 662L;
+    long l663 = 663L;
+    long l664 = 664L;
+    long l665 = 665L;
+    long l666 = 666L;
+    long l667 = 667L;
+    long l668 = 668L;
+    long l669 = 669L;
+    long l670 = 670L;
+    long l671 = 671L;
+    long l672 = 672L;
+    long l673 = 673L;
+    long l674 = 674L;
+    long l675 = 675L;
+    long l676 = 676L;
+    long l677 = 677L;
+    long l678 = 678L;
+    long l679 = 679L;
+    long l680 = 680L;
+    long l681 = 681L;
+    long l682 = 682L;
+    long l683 = 683L;
+    long l684 = 684L;
+    long l685 = 685L;
+    long l686 = 686L;
+    long l687 = 687L;
+    long l688 = 688L;
+    long l689 = 689L;
+    long l690 = 690L;
+    long l691 = 691L;
+    long l692 = 692L;
+    long l693 = 693L;
+    long l694 = 694L;
+    long l695 = 695L;
+    long l696 = 696L;
+    long l697 = 697L;
+    long l698 = 698L;
+    long l699 = 699L;
+    long l700 = 700L;
+    long l701 = 701L;
+    long l702 = 702L;
+    long l703 = 703L;
+    long l704 = 704L;
+    long l705 = 705L;
+    long l706 = 706L;
+    long l707 = 707L;
+    long l708 = 708L;
+    long l709 = 709L;
+    long l710 = 710L;
+    long l711 = 711L;
+    long l712 = 712L;
+    long l713 = 713L;
+    long l714 = 714L;
+    long l715 = 715L;
+    long l716 = 716L;
+    long l717 = 717L;
+    long l718 = 718L;
+    long l719 = 719L;
+    long l720 = 720L;
+    long l721 = 721L;
+    long l722 = 722L;
+    long l723 = 723L;
+    long l724 = 724L;
+    long l725 = 725L;
+    long l726 = 726L;
+    long l727 = 727L;
+    long l728 = 728L;
+    long l729 = 729L;
+    long l730 = 730L;
+    long l731 = 731L;
+    long l732 = 732L;
+    long l733 = 733L;
+    long l734 = 734L;
+    long l735 = 735L;
+    long l736 = 736L;
+    long l737 = 737L;
+    long l738 = 738L;
+    long l739 = 739L;
+    long l740 = 740L;
+    long l741 = 741L;
+    long l742 = 742L;
+    long l743 = 743L;
+    long l744 = 744L;
+    long l745 = 745L;
+    long l746 = 746L;
+    long l747 = 747L;
+    long l748 = 748L;
+    long l749 = 749L;
+    long l750 = 750L;
+    long l751 = 751L;
+    long l752 = 752L;
+    long l753 = 753L;
+    long l754 = 754L;
+    long l755 = 755L;
+    long l756 = 756L;
+    long l757 = 757L;
+    long l758 = 758L;
+    long l759 = 759L;
+    long l760 = 760L;
+    long l761 = 761L;
+    long l762 = 762L;
+    long l763 = 763L;
+    long l764 = 764L;
+    long l765 = 765L;
+    long l766 = 766L;
+    long l767 = 767L;
+    long l768 = 768L;
+    long l769 = 769L;
+    long l770 = 770L;
+    long l771 = 771L;
+    long l772 = 772L;
+    long l773 = 773L;
+    long l774 = 774L;
+    long l775 = 775L;
+    long l776 = 776L;
+    long l777 = 777L;
+    long l778 = 778L;
+    long l779 = 779L;
+    long l780 = 780L;
+    long l781 = 781L;
+    long l782 = 782L;
+    long l783 = 783L;
+    long l784 = 784L;
+    long l785 = 785L;
+    long l786 = 786L;
+    long l787 = 787L;
+    long l788 = 788L;
+    long l789 = 789L;
+    long l790 = 790L;
+    long l791 = 791L;
+    long l792 = 792L;
+    long l793 = 793L;
+    long l794 = 794L;
+    long l795 = 795L;
+    long l796 = 796L;
+    long l797 = 797L;
+    long l798 = 798L;
+    long l799 = 799L;
+    long l800 = 800L;
+    long l801 = 801L;
+    long l802 = 802L;
+    long l803 = 803L;
+    long l804 = 804L;
+    long l805 = 805L;
+    long l806 = 806L;
+    long l807 = 807L;
+    long l808 = 808L;
+    long l809 = 809L;
+    long l810 = 810L;
+    long l811 = 811L;
+    long l812 = 812L;
+    long l813 = 813L;
+    long l814 = 814L;
+    long l815 = 815L;
+    long l816 = 816L;
+    long l817 = 817L;
+    long l818 = 818L;
+    long l819 = 819L;
+    long l820 = 820L;
+    long l821 = 821L;
+    long l822 = 822L;
+    long l823 = 823L;
+    long l824 = 824L;
+    long l825 = 825L;
+    long l826 = 826L;
+    long l827 = 827L;
+    long l828 = 828L;
+    long l829 = 829L;
+    long l830 = 830L;
+    long l831 = 831L;
+    long l832 = 832L;
+    long l833 = 833L;
+    long l834 = 834L;
+    long l835 = 835L;
+    long l836 = 836L;
+    long l837 = 837L;
+    long l838 = 838L;
+    long l839 = 839L;
+    long l840 = 840L;
+    long l841 = 841L;
+    long l842 = 842L;
+    long l843 = 843L;
+    long l844 = 844L;
+    long l845 = 845L;
+    long l846 = 846L;
+    long l847 = 847L;
+    long l848 = 848L;
+    long l849 = 849L;
+    long l850 = 850L;
+    long l851 = 851L;
+    long l852 = 852L;
+    long l853 = 853L;
+    long l854 = 854L;
+    long l855 = 855L;
+    long l856 = 856L;
+    long l857 = 857L;
+    long l858 = 858L;
+    long l859 = 859L;
+    long l860 = 860L;
+    long l861 = 861L;
+    long l862 = 862L;
+    long l863 = 863L;
+    long l864 = 864L;
+    long l865 = 865L;
+    long l866 = 866L;
+    long l867 = 867L;
+    long l868 = 868L;
+    long l869 = 869L;
+    long l870 = 870L;
+    long l871 = 871L;
+    long l872 = 872L;
+    long l873 = 873L;
+    long l874 = 874L;
+    long l875 = 875L;
+    long l876 = 876L;
+    long l877 = 877L;
+    long l878 = 878L;
+    long l879 = 879L;
+    long l880 = 880L;
+    long l881 = 881L;
+    long l882 = 882L;
+    long l883 = 883L;
+    long l884 = 884L;
+    long l885 = 885L;
+    long l886 = 886L;
+    long l887 = 887L;
+    long l888 = 888L;
+    long l889 = 889L;
+    long l890 = 890L;
+    long l891 = 891L;
+    long l892 = 892L;
+    long l893 = 893L;
+    long l894 = 894L;
+    long l895 = 895L;
+    long l896 = 896L;
+    long l897 = 897L;
+    long l898 = 898L;
+    long l899 = 899L;
+    long l900 = 900L;
+    long l901 = 901L;
+    long l902 = 902L;
+    long l903 = 903L;
+    long l904 = 904L;
+    long l905 = 905L;
+    long l906 = 906L;
+    long l907 = 907L;
+    long l908 = 908L;
+    long l909 = 909L;
+    long l910 = 910L;
+    long l911 = 911L;
+    long l912 = 912L;
+    long l913 = 913L;
+    long l914 = 914L;
+    long l915 = 915L;
+    long l916 = 916L;
+    long l917 = 917L;
+    long l918 = 918L;
+    long l919 = 919L;
+    long l920 = 920L;
+    long l921 = 921L;
+    long l922 = 922L;
+    long l923 = 923L;
+    long l924 = 924L;
+    long l925 = 925L;
+    long l926 = 926L;
+    long l927 = 927L;
+    long l928 = 928L;
+    long l929 = 929L;
+    long l930 = 930L;
+    long l931 = 931L;
+    long l932 = 932L;
+    long l933 = 933L;
+    long l934 = 934L;
+    long l935 = 935L;
+    long l936 = 936L;
+    long l937 = 937L;
+    long l938 = 938L;
+    long l939 = 939L;
+    long l940 = 940L;
+    long l941 = 941L;
+    long l942 = 942L;
+    long l943 = 943L;
+    long l944 = 944L;
+    long l945 = 945L;
+    long l946 = 946L;
+    long l947 = 947L;
+    long l948 = 948L;
+    long l949 = 949L;
+    long l950 = 950L;
+    long l951 = 951L;
+    long l952 = 952L;
+    long l953 = 953L;
+    long l954 = 954L;
+    long l955 = 955L;
+    long l956 = 956L;
+    long l957 = 957L;
+    long l958 = 958L;
+    long l959 = 959L;
+    long l960 = 960L;
+    long l961 = 961L;
+    long l962 = 962L;
+    long l963 = 963L;
+    long l964 = 964L;
+    long l965 = 965L;
+    long l966 = 966L;
+    long l967 = 967L;
+    long l968 = 968L;
+    long l969 = 969L;
+    long l970 = 970L;
+    long l971 = 971L;
+    long l972 = 972L;
+    long l973 = 973L;
+    long l974 = 974L;
+    long l975 = 975L;
+    long l976 = 976L;
+    long l977 = 977L;
+    long l978 = 978L;
+    long l979 = 979L;
+    long l980 = 980L;
+    long l981 = 981L;
+    long l982 = 982L;
+    long l983 = 983L;
+    long l984 = 984L;
+    long l985 = 985L;
+    long l986 = 986L;
+    long l987 = 987L;
+    long l988 = 988L;
+    long l989 = 989L;
+    long l990 = 990L;
+    long l991 = 991L;
+    long l992 = 992L;
+    long l993 = 993L;
+    long l994 = 994L;
+    long l995 = 995L;
+    long l996 = 996L;
+    long l997 = 997L;
+    long l998 = 998L;
+    long l999 = 999L;
+    l1 += l0;
+    l2 += l1;
+    l3 += l2;
+    l4 += l3;
+    l5 += l4;
+    l6 += l5;
+    l7 += l6;
+    l8 += l7;
+    l9 += l8;
+    l10 += l9;
+    l11 += l10;
+    l12 += l11;
+    l13 += l12;
+    l14 += l13;
+    l15 += l14;
+    l16 += l15;
+    l17 += l16;
+    l18 += l17;
+    l19 += l18;
+    l20 += l19;
+    l21 += l20;
+    l22 += l21;
+    l23 += l22;
+    l24 += l23;
+    l25 += l24;
+    l26 += l25;
+    l27 += l26;
+    l28 += l27;
+    l29 += l28;
+    l30 += l29;
+    l31 += l30;
+    l32 += l31;
+    l33 += l32;
+    l34 += l33;
+    l35 += l34;
+    l36 += l35;
+    l37 += l36;
+    l38 += l37;
+    l39 += l38;
+    l40 += l39;
+    l41 += l40;
+    l42 += l41;
+    l43 += l42;
+    l44 += l43;
+    l45 += l44;
+    l46 += l45;
+    l47 += l46;
+    l48 += l47;
+    l49 += l48;
+    l50 += l49;
+    l51 += l50;
+    l52 += l51;
+    l53 += l52;
+    l54 += l53;
+    l55 += l54;
+    l56 += l55;
+    l57 += l56;
+    l58 += l57;
+    l59 += l58;
+    l60 += l59;
+    l61 += l60;
+    l62 += l61;
+    l63 += l62;
+    l64 += l63;
+    l65 += l64;
+    l66 += l65;
+    l67 += l66;
+    l68 += l67;
+    l69 += l68;
+    l70 += l69;
+    l71 += l70;
+    l72 += l71;
+    l73 += l72;
+    l74 += l73;
+    l75 += l74;
+    l76 += l75;
+    l77 += l76;
+    l78 += l77;
+    l79 += l78;
+    l80 += l79;
+    l81 += l80;
+    l82 += l81;
+    l83 += l82;
+    l84 += l83;
+    l85 += l84;
+    l86 += l85;
+    l87 += l86;
+    l88 += l87;
+    l89 += l88;
+    l90 += l89;
+    l91 += l90;
+    l92 += l91;
+    l93 += l92;
+    l94 += l93;
+    l95 += l94;
+    l96 += l95;
+    l97 += l96;
+    l98 += l97;
+    l99 += l98;
+    l100 += l99;
+    l101 += l100;
+    l102 += l101;
+    l103 += l102;
+    l104 += l103;
+    l105 += l104;
+    l106 += l105;
+    l107 += l106;
+    l108 += l107;
+    l109 += l108;
+    l110 += l109;
+    l111 += l110;
+    l112 += l111;
+    l113 += l112;
+    l114 += l113;
+    l115 += l114;
+    l116 += l115;
+    l117 += l116;
+    l118 += l117;
+    l119 += l118;
+    l120 += l119;
+    l121 += l120;
+    l122 += l121;
+    l123 += l122;
+    l124 += l123;
+    l125 += l124;
+    l126 += l125;
+    l127 += l126;
+    l128 += l127;
+    l129 += l128;
+    l130 += l129;
+    l131 += l130;
+    l132 += l131;
+    l133 += l132;
+    l134 += l133;
+    l135 += l134;
+    l136 += l135;
+    l137 += l136;
+    l138 += l137;
+    l139 += l138;
+    l140 += l139;
+    l141 += l140;
+    l142 += l141;
+    l143 += l142;
+    l144 += l143;
+    l145 += l144;
+    l146 += l145;
+    l147 += l146;
+    l148 += l147;
+    l149 += l148;
+    l150 += l149;
+    l151 += l150;
+    l152 += l151;
+    l153 += l152;
+    l154 += l153;
+    l155 += l154;
+    l156 += l155;
+    l157 += l156;
+    l158 += l157;
+    l159 += l158;
+    l160 += l159;
+    l161 += l160;
+    l162 += l161;
+    l163 += l162;
+    l164 += l163;
+    l165 += l164;
+    l166 += l165;
+    l167 += l166;
+    l168 += l167;
+    l169 += l168;
+    l170 += l169;
+    l171 += l170;
+    l172 += l171;
+    l173 += l172;
+    l174 += l173;
+    l175 += l174;
+    l176 += l175;
+    l177 += l176;
+    l178 += l177;
+    l179 += l178;
+    l180 += l179;
+    l181 += l180;
+    l182 += l181;
+    l183 += l182;
+    l184 += l183;
+    l185 += l184;
+    l186 += l185;
+    l187 += l186;
+    l188 += l187;
+    l189 += l188;
+    l190 += l189;
+    l191 += l190;
+    l192 += l191;
+    l193 += l192;
+    l194 += l193;
+    l195 += l194;
+    l196 += l195;
+    l197 += l196;
+    l198 += l197;
+    l199 += l198;
+    l200 += l199;
+    l201 += l200;
+    l202 += l201;
+    l203 += l202;
+    l204 += l203;
+    l205 += l204;
+    l206 += l205;
+    l207 += l206;
+    l208 += l207;
+    l209 += l208;
+    l210 += l209;
+    l211 += l210;
+    l212 += l211;
+    l213 += l212;
+    l214 += l213;
+    l215 += l214;
+    l216 += l215;
+    l217 += l216;
+    l218 += l217;
+    l219 += l218;
+    l220 += l219;
+    l221 += l220;
+    l222 += l221;
+    l223 += l222;
+    l224 += l223;
+    l225 += l224;
+    l226 += l225;
+    l227 += l226;
+    l228 += l227;
+    l229 += l228;
+    l230 += l229;
+    l231 += l230;
+    l232 += l231;
+    l233 += l232;
+    l234 += l233;
+    l235 += l234;
+    l236 += l235;
+    l237 += l236;
+    l238 += l237;
+    l239 += l238;
+    l240 += l239;
+    l241 += l240;
+    l242 += l241;
+    l243 += l242;
+    l244 += l243;
+    l245 += l244;
+    l246 += l245;
+    l247 += l246;
+    l248 += l247;
+    l249 += l248;
+    l250 += l249;
+    l251 += l250;
+    l252 += l251;
+    l253 += l252;
+    l254 += l253;
+    l255 += l254;
+    l256 += l255;
+    l257 += l256;
+    l258 += l257;
+    l259 += l258;
+    l260 += l259;
+    l261 += l260;
+    l262 += l261;
+    l263 += l262;
+    l264 += l263;
+    l265 += l264;
+    l266 += l265;
+    l267 += l266;
+    l268 += l267;
+    l269 += l268;
+    l270 += l269;
+    l271 += l270;
+    l272 += l271;
+    l273 += l272;
+    l274 += l273;
+    l275 += l274;
+    l276 += l275;
+    l277 += l276;
+    l278 += l277;
+    l279 += l278;
+    l280 += l279;
+    l281 += l280;
+    l282 += l281;
+    l283 += l282;
+    l284 += l283;
+    l285 += l284;
+    l286 += l285;
+    l287 += l286;
+    l288 += l287;
+    l289 += l288;
+    l290 += l289;
+    l291 += l290;
+    l292 += l291;
+    l293 += l292;
+    l294 += l293;
+    l295 += l294;
+    l296 += l295;
+    l297 += l296;
+    l298 += l297;
+    l299 += l298;
+    l300 += l299;
+    l301 += l300;
+    l302 += l301;
+    l303 += l302;
+    l304 += l303;
+    l305 += l304;
+    l306 += l305;
+    l307 += l306;
+    l308 += l307;
+    l309 += l308;
+    l310 += l309;
+    l311 += l310;
+    l312 += l311;
+    l313 += l312;
+    l314 += l313;
+    l315 += l314;
+    l316 += l315;
+    l317 += l316;
+    l318 += l317;
+    l319 += l318;
+    l320 += l319;
+    l321 += l320;
+    l322 += l321;
+    l323 += l322;
+    l324 += l323;
+    l325 += l324;
+    l326 += l325;
+    l327 += l326;
+    l328 += l327;
+    l329 += l328;
+    l330 += l329;
+    l331 += l330;
+    l332 += l331;
+    l333 += l332;
+    l334 += l333;
+    l335 += l334;
+    l336 += l335;
+    l337 += l336;
+    l338 += l337;
+    l339 += l338;
+    l340 += l339;
+    l341 += l340;
+    l342 += l341;
+    l343 += l342;
+    l344 += l343;
+    l345 += l344;
+    l346 += l345;
+    l347 += l346;
+    l348 += l347;
+    l349 += l348;
+    l350 += l349;
+    l351 += l350;
+    l352 += l351;
+    l353 += l352;
+    l354 += l353;
+    l355 += l354;
+    l356 += l355;
+    l357 += l356;
+    l358 += l357;
+    l359 += l358;
+    l360 += l359;
+    l361 += l360;
+    l362 += l361;
+    l363 += l362;
+    l364 += l363;
+    l365 += l364;
+    l366 += l365;
+    l367 += l366;
+    l368 += l367;
+    l369 += l368;
+    l370 += l369;
+    l371 += l370;
+    l372 += l371;
+    l373 += l372;
+    l374 += l373;
+    l375 += l374;
+    l376 += l375;
+    l377 += l376;
+    l378 += l377;
+    l379 += l378;
+    l380 += l379;
+    l381 += l380;
+    l382 += l381;
+    l383 += l382;
+    l384 += l383;
+    l385 += l384;
+    l386 += l385;
+    l387 += l386;
+    l388 += l387;
+    l389 += l388;
+    l390 += l389;
+    l391 += l390;
+    l392 += l391;
+    l393 += l392;
+    l394 += l393;
+    l395 += l394;
+    l396 += l395;
+    l397 += l396;
+    l398 += l397;
+    l399 += l398;
+    l400 += l399;
+    l401 += l400;
+    l402 += l401;
+    l403 += l402;
+    l404 += l403;
+    l405 += l404;
+    l406 += l405;
+    l407 += l406;
+    l408 += l407;
+    l409 += l408;
+    l410 += l409;
+    l411 += l410;
+    l412 += l411;
+    l413 += l412;
+    l414 += l413;
+    l415 += l414;
+    l416 += l415;
+    l417 += l416;
+    l418 += l417;
+    l419 += l418;
+    l420 += l419;
+    l421 += l420;
+    l422 += l421;
+    l423 += l422;
+    l424 += l423;
+    l425 += l424;
+    l426 += l425;
+    l427 += l426;
+    l428 += l427;
+    l429 += l428;
+    l430 += l429;
+    l431 += l430;
+    l432 += l431;
+    l433 += l432;
+    l434 += l433;
+    l435 += l434;
+    l436 += l435;
+    l437 += l436;
+    l438 += l437;
+    l439 += l438;
+    l440 += l439;
+    l441 += l440;
+    l442 += l441;
+    l443 += l442;
+    l444 += l443;
+    l445 += l444;
+    l446 += l445;
+    l447 += l446;
+    l448 += l447;
+    l449 += l448;
+    l450 += l449;
+    l451 += l450;
+    l452 += l451;
+    l453 += l452;
+    l454 += l453;
+    l455 += l454;
+    l456 += l455;
+    l457 += l456;
+    l458 += l457;
+    l459 += l458;
+    l460 += l459;
+    l461 += l460;
+    l462 += l461;
+    l463 += l462;
+    l464 += l463;
+    l465 += l464;
+    l466 += l465;
+    l467 += l466;
+    l468 += l467;
+    l469 += l468;
+    l470 += l469;
+    l471 += l470;
+    l472 += l471;
+    l473 += l472;
+    l474 += l473;
+    l475 += l474;
+    l476 += l475;
+    l477 += l476;
+    l478 += l477;
+    l479 += l478;
+    l480 += l479;
+    l481 += l480;
+    l482 += l481;
+    l483 += l482;
+    l484 += l483;
+    l485 += l484;
+    l486 += l485;
+    l487 += l486;
+    l488 += l487;
+    l489 += l488;
+    l490 += l489;
+    l491 += l490;
+    l492 += l491;
+    l493 += l492;
+    l494 += l493;
+    l495 += l494;
+    l496 += l495;
+    l497 += l496;
+    l498 += l497;
+    l499 += l498;
+    l500 += l499;
+    l501 += l500;
+    l502 += l501;
+    l503 += l502;
+    l504 += l503;
+    l505 += l504;
+    l506 += l505;
+    l507 += l506;
+    l508 += l507;
+    l509 += l508;
+    l510 += l509;
+    l511 += l510;
+    l512 += l511;
+    l513 += l512;
+    l514 += l513;
+    l515 += l514;
+    l516 += l515;
+    l517 += l516;
+    l518 += l517;
+    l519 += l518;
+    l520 += l519;
+    l521 += l520;
+    l522 += l521;
+    l523 += l522;
+    l524 += l523;
+    l525 += l524;
+    l526 += l525;
+    l527 += l526;
+    l528 += l527;
+    l529 += l528;
+    l530 += l529;
+    l531 += l530;
+    l532 += l531;
+    l533 += l532;
+    l534 += l533;
+    l535 += l534;
+    l536 += l535;
+    l537 += l536;
+    l538 += l537;
+    l539 += l538;
+    l540 += l539;
+    l541 += l540;
+    l542 += l541;
+    l543 += l542;
+    l544 += l543;
+    l545 += l544;
+    l546 += l545;
+    l547 += l546;
+    l548 += l547;
+    l549 += l548;
+    l550 += l549;
+    l551 += l550;
+    l552 += l551;
+    l553 += l552;
+    l554 += l553;
+    l555 += l554;
+    l556 += l555;
+    l557 += l556;
+    l558 += l557;
+    l559 += l558;
+    l560 += l559;
+    l561 += l560;
+    l562 += l561;
+    l563 += l562;
+    l564 += l563;
+    l565 += l564;
+    l566 += l565;
+    l567 += l566;
+    l568 += l567;
+    l569 += l568;
+    l570 += l569;
+    l571 += l570;
+    l572 += l571;
+    l573 += l572;
+    l574 += l573;
+    l575 += l574;
+    l576 += l575;
+    l577 += l576;
+    l578 += l577;
+    l579 += l578;
+    l580 += l579;
+    l581 += l580;
+    l582 += l581;
+    l583 += l582;
+    l584 += l583;
+    l585 += l584;
+    l586 += l585;
+    l587 += l586;
+    l588 += l587;
+    l589 += l588;
+    l590 += l589;
+    l591 += l590;
+    l592 += l591;
+    l593 += l592;
+    l594 += l593;
+    l595 += l594;
+    l596 += l595;
+    l597 += l596;
+    l598 += l597;
+    l599 += l598;
+    l600 += l599;
+    l601 += l600;
+    l602 += l601;
+    l603 += l602;
+    l604 += l603;
+    l605 += l604;
+    l606 += l605;
+    l607 += l606;
+    l608 += l607;
+    l609 += l608;
+    l610 += l609;
+    l611 += l610;
+    l612 += l611;
+    l613 += l612;
+    l614 += l613;
+    l615 += l614;
+    l616 += l615;
+    l617 += l616;
+    l618 += l617;
+    l619 += l618;
+    l620 += l619;
+    l621 += l620;
+    l622 += l621;
+    l623 += l622;
+    l624 += l623;
+    l625 += l624;
+    l626 += l625;
+    l627 += l626;
+    l628 += l627;
+    l629 += l628;
+    l630 += l629;
+    l631 += l630;
+    l632 += l631;
+    l633 += l632;
+    l634 += l633;
+    l635 += l634;
+    l636 += l635;
+    l637 += l636;
+    l638 += l637;
+    l639 += l638;
+    l640 += l639;
+    l641 += l640;
+    l642 += l641;
+    l643 += l642;
+    l644 += l643;
+    l645 += l644;
+    l646 += l645;
+    l647 += l646;
+    l648 += l647;
+    l649 += l648;
+    l650 += l649;
+    l651 += l650;
+    l652 += l651;
+    l653 += l652;
+    l654 += l653;
+    l655 += l654;
+    l656 += l655;
+    l657 += l656;
+    l658 += l657;
+    l659 += l658;
+    l660 += l659;
+    l661 += l660;
+    l662 += l661;
+    l663 += l662;
+    l664 += l663;
+    l665 += l664;
+    l666 += l665;
+    l667 += l666;
+    l668 += l667;
+    l669 += l668;
+    l670 += l669;
+    l671 += l670;
+    l672 += l671;
+    l673 += l672;
+    l674 += l673;
+    l675 += l674;
+    l676 += l675;
+    l677 += l676;
+    l678 += l677;
+    l679 += l678;
+    l680 += l679;
+    l681 += l680;
+    l682 += l681;
+    l683 += l682;
+    l684 += l683;
+    l685 += l684;
+    l686 += l685;
+    l687 += l686;
+    l688 += l687;
+    l689 += l688;
+    l690 += l689;
+    l691 += l690;
+    l692 += l691;
+    l693 += l692;
+    l694 += l693;
+    l695 += l694;
+    l696 += l695;
+    l697 += l696;
+    l698 += l697;
+    l699 += l698;
+    l700 += l699;
+    l701 += l700;
+    l702 += l701;
+    l703 += l702;
+    l704 += l703;
+    l705 += l704;
+    l706 += l705;
+    l707 += l706;
+    l708 += l707;
+    l709 += l708;
+    l710 += l709;
+    l711 += l710;
+    l712 += l711;
+    l713 += l712;
+    l714 += l713;
+    l715 += l714;
+    l716 += l715;
+    l717 += l716;
+    l718 += l717;
+    l719 += l718;
+    l720 += l719;
+    l721 += l720;
+    l722 += l721;
+    l723 += l722;
+    l724 += l723;
+    l725 += l724;
+    l726 += l725;
+    l727 += l726;
+    l728 += l727;
+    l729 += l728;
+    l730 += l729;
+    l731 += l730;
+    l732 += l731;
+    l733 += l732;
+    l734 += l733;
+    l735 += l734;
+    l736 += l735;
+    l737 += l736;
+    l738 += l737;
+    l739 += l738;
+    l740 += l739;
+    l741 += l740;
+    l742 += l741;
+    l743 += l742;
+    l744 += l743;
+    l745 += l744;
+    l746 += l745;
+    l747 += l746;
+    l748 += l747;
+    l749 += l748;
+    l750 += l749;
+    l751 += l750;
+    l752 += l751;
+    l753 += l752;
+    l754 += l753;
+    l755 += l754;
+    l756 += l755;
+    l757 += l756;
+    l758 += l757;
+    l759 += l758;
+    l760 += l759;
+    l761 += l760;
+    l762 += l761;
+    l763 += l762;
+    l764 += l763;
+    l765 += l764;
+    l766 += l765;
+    l767 += l766;
+    l768 += l767;
+    l769 += l768;
+    l770 += l769;
+    l771 += l770;
+    l772 += l771;
+    l773 += l772;
+    l774 += l773;
+    l775 += l774;
+    l776 += l775;
+    l777 += l776;
+    l778 += l777;
+    l779 += l778;
+    l780 += l779;
+    l781 += l780;
+    l782 += l781;
+    l783 += l782;
+    l784 += l783;
+    l785 += l784;
+    l786 += l785;
+    l787 += l786;
+    l788 += l787;
+    l789 += l788;
+    l790 += l789;
+    l791 += l790;
+    l792 += l791;
+    l793 += l792;
+    l794 += l793;
+    l795 += l794;
+    l796 += l795;
+    l797 += l796;
+    l798 += l797;
+    l799 += l798;
+    l800 += l799;
+    l801 += l800;
+    l802 += l801;
+    l803 += l802;
+    l804 += l803;
+    l805 += l804;
+    l806 += l805;
+    l807 += l806;
+    l808 += l807;
+    l809 += l808;
+    l810 += l809;
+    l811 += l810;
+    l812 += l811;
+    l813 += l812;
+    l814 += l813;
+    l815 += l814;
+    l816 += l815;
+    l817 += l816;
+    l818 += l817;
+    l819 += l818;
+    l820 += l819;
+    l821 += l820;
+    l822 += l821;
+    l823 += l822;
+    l824 += l823;
+    l825 += l824;
+    l826 += l825;
+    l827 += l826;
+    l828 += l827;
+    l829 += l828;
+    l830 += l829;
+    l831 += l830;
+    l832 += l831;
+    l833 += l832;
+    l834 += l833;
+    l835 += l834;
+    l836 += l835;
+    l837 += l836;
+    l838 += l837;
+    l839 += l838;
+    l840 += l839;
+    l841 += l840;
+    l842 += l841;
+    l843 += l842;
+    l844 += l843;
+    l845 += l844;
+    l846 += l845;
+    l847 += l846;
+    l848 += l847;
+    l849 += l848;
+    l850 += l849;
+    l851 += l850;
+    l852 += l851;
+    l853 += l852;
+    l854 += l853;
+    l855 += l854;
+    l856 += l855;
+    l857 += l856;
+    l858 += l857;
+    l859 += l858;
+    l860 += l859;
+    l861 += l860;
+    l862 += l861;
+    l863 += l862;
+    l864 += l863;
+    l865 += l864;
+    l866 += l865;
+    l867 += l866;
+    l868 += l867;
+    l869 += l868;
+    l870 += l869;
+    l871 += l870;
+    l872 += l871;
+    l873 += l872;
+    l874 += l873;
+    l875 += l874;
+    l876 += l875;
+    l877 += l876;
+    l878 += l877;
+    l879 += l878;
+    l880 += l879;
+    l881 += l880;
+    l882 += l881;
+    l883 += l882;
+    l884 += l883;
+    l885 += l884;
+    l886 += l885;
+    l887 += l886;
+    l888 += l887;
+    l889 += l888;
+    l890 += l889;
+    l891 += l890;
+    l892 += l891;
+    l893 += l892;
+    l894 += l893;
+    l895 += l894;
+    l896 += l895;
+    l897 += l896;
+    l898 += l897;
+    l899 += l898;
+    l900 += l899;
+    l901 += l900;
+    l902 += l901;
+    l903 += l902;
+    l904 += l903;
+    l905 += l904;
+    l906 += l905;
+    l907 += l906;
+    l908 += l907;
+    l909 += l908;
+    l910 += l909;
+    l911 += l910;
+    l912 += l911;
+    l913 += l912;
+    l914 += l913;
+    l915 += l914;
+    l916 += l915;
+    l917 += l916;
+    l918 += l917;
+    l919 += l918;
+    l920 += l919;
+    l921 += l920;
+    l922 += l921;
+    l923 += l922;
+    l924 += l923;
+    l925 += l924;
+    l926 += l925;
+    l927 += l926;
+    l928 += l927;
+    l929 += l928;
+    l930 += l929;
+    l931 += l930;
+    l932 += l931;
+    l933 += l932;
+    l934 += l933;
+    l935 += l934;
+    l936 += l935;
+    l937 += l936;
+    l938 += l937;
+    l939 += l938;
+    l940 += l939;
+    l941 += l940;
+    l942 += l941;
+    l943 += l942;
+    l944 += l943;
+    l945 += l944;
+    l946 += l945;
+    l947 += l946;
+    l948 += l947;
+    l949 += l948;
+    l950 += l949;
+    l951 += l950;
+    l952 += l951;
+    l953 += l952;
+    l954 += l953;
+    l955 += l954;
+    l956 += l955;
+    l957 += l956;
+    l958 += l957;
+    l959 += l958;
+    l960 += l959;
+    l961 += l960;
+    l962 += l961;
+    l963 += l962;
+    l964 += l963;
+    l965 += l964;
+    l966 += l965;
+    l967 += l966;
+    l968 += l967;
+    l969 += l968;
+    l970 += l969;
+    l971 += l970;
+    l972 += l971;
+    l973 += l972;
+    l974 += l973;
+    l975 += l974;
+    l976 += l975;
+    l977 += l976;
+    l978 += l977;
+    l979 += l978;
+    l980 += l979;
+    l981 += l980;
+    l982 += l981;
+    l983 += l982;
+    l984 += l983;
+    l985 += l984;
+    l986 += l985;
+    l987 += l986;
+    l988 += l987;
+    l989 += l988;
+    l990 += l989;
+    l991 += l990;
+    l992 += l991;
+    l993 += l992;
+    l994 += l993;
+    l995 += l994;
+    l996 += l995;
+    l997 += l996;
+    l998 += l997;
+    l999 += l998;
+    // Create a branch to beat the large method check.
+    if (l998 == l999) {
+      return l998;
+    } else {
+      return l999;
+    }
+  }
+}
diff --git a/test/422-instanceof/expected.txt b/test/422-instanceof/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/422-instanceof/expected.txt
diff --git a/test/422-instanceof/info.txt b/test/422-instanceof/info.txt
new file mode 100644
index 0000000..b2f7ff1
--- /dev/null
+++ b/test/422-instanceof/info.txt
@@ -0,0 +1 @@
+Tests for instanceof bytecode.
diff --git a/test/422-instanceof/src/Main.java b/test/422-instanceof/src/Main.java
new file mode 100644
index 0000000..307c987
--- /dev/null
+++ b/test/422-instanceof/src/Main.java
@@ -0,0 +1,70 @@
+/*
+ * 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 {
+  public static Object a;
+
+  public static void assertTrue(boolean value) {
+    if (!value) {
+      throw new Error("Wrong result");
+    }
+  }
+
+  public static void assertFalse(boolean value) {
+    if (value) {
+      throw new Error("Wrong result");
+    }
+  }
+
+  public static boolean $opt$InstanceOfMain() {
+    return a instanceof Main;
+  }
+
+  public static boolean $opt$InstanceOfFinalClass() {
+    return a instanceof FinalClass;
+  }
+
+  public static void main(String[] args) {
+    $opt$TestMain();
+    $opt$TestFinalClass();
+  }
+
+  public static void $opt$TestMain() {
+    a = new Main();
+    assertTrue($opt$InstanceOfMain());
+    a = null;
+    assertFalse($opt$InstanceOfMain());
+    a = new MainChild();
+    assertTrue($opt$InstanceOfMain());
+    a = new Object();
+    assertFalse($opt$InstanceOfMain());
+  }
+
+  public static void $opt$TestFinalClass() {
+    a = new FinalClass();
+    assertTrue($opt$InstanceOfFinalClass());
+    a = null;
+    assertFalse($opt$InstanceOfFinalClass());
+    a = new Main();
+    assertFalse($opt$InstanceOfFinalClass());
+    a = new Object();
+    assertFalse($opt$InstanceOfFinalClass());
+  }
+
+  static class MainChild extends Main {}
+
+  static final class FinalClass {}
+}
diff --git a/test/422-type-conversion/expected.txt b/test/422-type-conversion/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/422-type-conversion/expected.txt
diff --git a/test/422-type-conversion/info.txt b/test/422-type-conversion/info.txt
new file mode 100644
index 0000000..e734f32
--- /dev/null
+++ b/test/422-type-conversion/info.txt
@@ -0,0 +1 @@
+Tests for type conversions.
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
new file mode 100644
index 0000000..7ce2868
--- /dev/null
+++ b/test/422-type-conversion/src/Main.java
@@ -0,0 +1,689 @@
+/*
+ * 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 assertByteEquals(byte expected, byte result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertShortEquals(short expected, short result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertIntEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertLongEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertCharEquals(char expected, char result) {
+    if (expected != result) {
+      // Values are cast to int to display numeric values instead of
+      // (UTF-16 encoded) characters.
+      throw new Error("Expected: " + (int)expected + ", found: " + (int)result);
+    }
+  }
+
+  public static void assertFloatEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertDoubleEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertFloatIsNaN(float result) {
+    if (!Float.isNaN(result)) {
+      throw new Error("Expected: NaN, found: " + result);
+    }
+  }
+
+  public static void assertDoubleIsNaN(double result) {
+    if (!Double.isNaN(result)) {
+      throw new Error("Expected: NaN, found: " + result);
+    }
+  }
+
+
+  public static void main(String[] args) {
+    // Generate, compile and check int-to-long Dex instructions.
+    byteToLong();
+    shortToLong();
+    intToLong();
+    charToLong();
+
+    // Generate, compile and check int-to-float Dex instructions.
+    byteToFloat();
+    shortToFloat();
+    intToFloat();
+    charToFloat();
+
+    // Generate, compile and check int-to-double Dex instructions.
+    byteToDouble();
+    shortToDouble();
+    intToDouble();
+    charToDouble();
+
+    // Generate, compile and check long-to-int Dex instructions.
+    longToInt();
+
+    // Generate, compile and check long-to-float Dex instructions.
+    longToFloat();
+
+    // Generate, compile and check long-to-double Dex instructions.
+    longToDouble();
+
+    // Generate, compile and check float-to-int Dex instructions.
+    floatToInt();
+
+    // Generate, compile and check float-to-long Dex instructions.
+    floatToLong();
+
+    // Generate, compile and check float-to-double Dex instructions.
+    floatToDouble();
+
+    // Generate, compile and check double-to-int Dex instructions.
+    doubleToInt();
+
+    // Generate, compile and check double-to-long Dex instructions.
+    doubleToLong();
+
+    // Generate, compile and check double-to-float Dex instructions.
+    doubleToFloat();
+
+    // Generate, compile and check int-to-byte Dex instructions.
+    shortToByte();
+    intToByte();
+    charToByte();
+
+    // Generate, compile and check int-to-short Dex instructions.
+    byteToShort();
+    intToShort();
+    charToShort();
+
+    // Generate, compile and check int-to-char Dex instructions.
+    byteToChar();
+    shortToChar();
+    intToChar();
+  }
+
+  private static void byteToLong() {
+    assertLongEquals(1L, $opt$ByteToLong((byte)1));
+    assertLongEquals(0L, $opt$ByteToLong((byte)0));
+    assertLongEquals(-1L, $opt$ByteToLong((byte)-1));
+    assertLongEquals(51L, $opt$ByteToLong((byte)51));
+    assertLongEquals(-51L, $opt$ByteToLong((byte)-51));
+    assertLongEquals(127L, $opt$ByteToLong((byte)127));  // 2^7 - 1
+    assertLongEquals(-127L, $opt$ByteToLong((byte)-127));  // -(2^7 - 1)
+    assertLongEquals(-128L, $opt$ByteToLong((byte)-128));  // -(2^7)
+  }
+
+  private static void shortToLong() {
+    assertLongEquals(1L, $opt$ShortToLong((short)1));
+    assertLongEquals(0L, $opt$ShortToLong((short)0));
+    assertLongEquals(-1L, $opt$ShortToLong((short)-1));
+    assertLongEquals(51L, $opt$ShortToLong((short)51));
+    assertLongEquals(-51L, $opt$ShortToLong((short)-51));
+    assertLongEquals(32767L, $opt$ShortToLong((short)32767));  // 2^15 - 1
+    assertLongEquals(-32767L, $opt$ShortToLong((short)-32767));  // -(2^15 - 1)
+    assertLongEquals(-32768L, $opt$ShortToLong((short)-32768));  // -(2^15)
+  }
+
+  private static void intToLong() {
+    assertLongEquals(1L, $opt$IntToLong(1));
+    assertLongEquals(0L, $opt$IntToLong(0));
+    assertLongEquals(-1L, $opt$IntToLong(-1));
+    assertLongEquals(51L, $opt$IntToLong(51));
+    assertLongEquals(-51L, $opt$IntToLong(-51));
+    assertLongEquals(2147483647L, $opt$IntToLong(2147483647));  // 2^31 - 1
+    assertLongEquals(-2147483647L, $opt$IntToLong(-2147483647));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$IntToLong(-2147483648));  // -(2^31)
+  }
+
+  private static void charToLong() {
+    assertLongEquals(1L, $opt$CharToLong((char)1));
+    assertLongEquals(0L, $opt$CharToLong((char)0));
+    assertLongEquals(51L, $opt$CharToLong((char)51));
+    assertLongEquals(32767L, $opt$CharToLong((char)32767));  // 2^15 - 1
+    assertLongEquals(65535L, $opt$CharToLong((char)65535));  // 2^16 - 1
+    assertLongEquals(65535L, $opt$CharToLong((char)-1));
+    assertLongEquals(65485L, $opt$CharToLong((char)-51));
+    assertLongEquals(32769L, $opt$CharToLong((char)-32767));  // -(2^15 - 1)
+    assertLongEquals(32768L, $opt$CharToLong((char)-32768));  // -(2^15)
+  }
+
+  private static void byteToFloat() {
+    assertFloatEquals(1F, $opt$ByteToFloat((byte)1));
+    assertFloatEquals(0F, $opt$ByteToFloat((byte)0));
+    assertFloatEquals(-1F, $opt$ByteToFloat((byte)-1));
+    assertFloatEquals(51F, $opt$ByteToFloat((byte)51));
+    assertFloatEquals(-51F, $opt$ByteToFloat((byte)-51));
+    assertFloatEquals(127F, $opt$ByteToFloat((byte)127));  // 2^7 - 1
+    assertFloatEquals(-127F, $opt$ByteToFloat((byte)-127));  // -(2^7 - 1)
+    assertFloatEquals(-128F, $opt$ByteToFloat((byte)-128));  // -(2^7)
+  }
+
+  private static void shortToFloat() {
+    assertFloatEquals(1F, $opt$ShortToFloat((short)1));
+    assertFloatEquals(0F, $opt$ShortToFloat((short)0));
+    assertFloatEquals(-1F, $opt$ShortToFloat((short)-1));
+    assertFloatEquals(51F, $opt$ShortToFloat((short)51));
+    assertFloatEquals(-51F, $opt$ShortToFloat((short)-51));
+    assertFloatEquals(32767F, $opt$ShortToFloat((short)32767));  // 2^15 - 1
+    assertFloatEquals(-32767F, $opt$ShortToFloat((short)-32767));  // -(2^15 - 1)
+    assertFloatEquals(-32768F, $opt$ShortToFloat((short)-32768));  // -(2^15)
+  }
+
+  private static void intToFloat() {
+    assertFloatEquals(1F, $opt$IntToFloat(1));
+    assertFloatEquals(0F, $opt$IntToFloat(0));
+    assertFloatEquals(-1F, $opt$IntToFloat(-1));
+    assertFloatEquals(51F, $opt$IntToFloat(51));
+    assertFloatEquals(-51F, $opt$IntToFloat(-51));
+    assertFloatEquals(16777215F, $opt$IntToFloat(16777215));  // 2^24 - 1
+    assertFloatEquals(-16777215F, $opt$IntToFloat(-16777215));  // -(2^24 - 1)
+    assertFloatEquals(16777216F, $opt$IntToFloat(16777216));  // 2^24
+    assertFloatEquals(-16777216F, $opt$IntToFloat(-16777216));  // -(2^24)
+    assertFloatEquals(2147483647F, $opt$IntToFloat(2147483647));  // 2^31 - 1
+    assertFloatEquals(-2147483648F, $opt$IntToFloat(-2147483648));  // -(2^31)
+  }
+
+  private static void charToFloat() {
+    assertFloatEquals(1F, $opt$CharToFloat((char)1));
+    assertFloatEquals(0F, $opt$CharToFloat((char)0));
+    assertFloatEquals(51F, $opt$CharToFloat((char)51));
+    assertFloatEquals(32767F, $opt$CharToFloat((char)32767));  // 2^15 - 1
+    assertFloatEquals(65535F, $opt$CharToFloat((char)65535));  // 2^16 - 1
+    assertFloatEquals(65535F, $opt$CharToFloat((char)-1));
+    assertFloatEquals(65485F, $opt$CharToFloat((char)-51));
+    assertFloatEquals(32769F, $opt$CharToFloat((char)-32767));  // -(2^15 - 1)
+    assertFloatEquals(32768F, $opt$CharToFloat((char)-32768));  // -(2^15)
+  }
+
+  private static void byteToDouble() {
+    assertDoubleEquals(1D, $opt$ByteToDouble((byte)1));
+    assertDoubleEquals(0D, $opt$ByteToDouble((byte)0));
+    assertDoubleEquals(-1D, $opt$ByteToDouble((byte)-1));
+    assertDoubleEquals(51D, $opt$ByteToDouble((byte)51));
+    assertDoubleEquals(-51D, $opt$ByteToDouble((byte)-51));
+    assertDoubleEquals(127D, $opt$ByteToDouble((byte)127));  // 2^7 - 1
+    assertDoubleEquals(-127D, $opt$ByteToDouble((byte)-127));  // -(2^7 - 1)
+    assertDoubleEquals(-128D, $opt$ByteToDouble((byte)-128));  // -(2^7)
+  }
+
+  private static void shortToDouble() {
+    assertDoubleEquals(1D, $opt$ShortToDouble((short)1));
+    assertDoubleEquals(0D, $opt$ShortToDouble((short)0));
+    assertDoubleEquals(-1D, $opt$ShortToDouble((short)-1));
+    assertDoubleEquals(51D, $opt$ShortToDouble((short)51));
+    assertDoubleEquals(-51D, $opt$ShortToDouble((short)-51));
+    assertDoubleEquals(32767D, $opt$ShortToDouble((short)32767));  // 2^15 - 1
+    assertDoubleEquals(-32767D, $opt$ShortToDouble((short)-32767));  // -(2^15 - 1)
+    assertDoubleEquals(-32768D, $opt$ShortToDouble((short)-32768));  // -(2^15)
+  }
+
+  private static void intToDouble() {
+    assertDoubleEquals(1D, $opt$IntToDouble(1));
+    assertDoubleEquals(0D, $opt$IntToDouble(0));
+    assertDoubleEquals(-1D, $opt$IntToDouble(-1));
+    assertDoubleEquals(51D, $opt$IntToDouble(51));
+    assertDoubleEquals(-51D, $opt$IntToDouble(-51));
+    assertDoubleEquals(16777216D, $opt$IntToDouble(16777216));  // 2^24
+    assertDoubleEquals(-16777216D, $opt$IntToDouble(-16777216));  // -(2^24)
+    assertDoubleEquals(2147483647D, $opt$IntToDouble(2147483647));  // 2^31 - 1
+    assertDoubleEquals(-2147483648D, $opt$IntToDouble(-2147483648));  // -(2^31)
+  }
+
+  private static void charToDouble() {
+    assertDoubleEquals(1D, $opt$CharToDouble((char)1));
+    assertDoubleEquals(0D, $opt$CharToDouble((char)0));
+    assertDoubleEquals(51D, $opt$CharToDouble((char)51));
+    assertDoubleEquals(32767D, $opt$CharToDouble((char)32767));  // 2^15 - 1
+    assertDoubleEquals(65535D, $opt$CharToDouble((char)65535));  // 2^16 - 1
+    assertDoubleEquals(65535D, $opt$CharToDouble((char)-1));
+    assertDoubleEquals(65485D, $opt$CharToDouble((char)-51));
+    assertDoubleEquals(32769D, $opt$CharToDouble((char)-32767));  // -(2^15 - 1)
+    assertDoubleEquals(32768D, $opt$CharToDouble((char)-32768));  // -(2^15)
+  }
+
+  private static void longToInt() {
+    assertIntEquals(1, $opt$LongToInt(1L));
+    assertIntEquals(0, $opt$LongToInt(0L));
+    assertIntEquals(-1, $opt$LongToInt(-1L));
+    assertIntEquals(51, $opt$LongToInt(51L));
+    assertIntEquals(-51, $opt$LongToInt(-51L));
+    assertIntEquals(2147483647, $opt$LongToInt(2147483647L));  // 2^31 - 1
+    assertIntEquals(-2147483647, $opt$LongToInt(-2147483647L));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$LongToInt(-2147483648L));  // -(2^31)
+    assertIntEquals(-2147483648, $opt$LongToInt(2147483648L));  // (2^31)
+    assertIntEquals(2147483647, $opt$LongToInt(-2147483649L));  // -(2^31 + 1)
+    assertIntEquals(-1, $opt$LongToInt(9223372036854775807L));  // 2^63 - 1
+    assertIntEquals(1, $opt$LongToInt(-9223372036854775807L));  // -(2^63 - 1)
+    assertIntEquals(0, $opt$LongToInt(-9223372036854775808L));  // -(2^63)
+
+    assertIntEquals(42, $opt$LongLiteralToInt());
+
+    // Ensure long-to-int conversions truncates values as expected.
+    assertLongEquals(1L, $opt$IntToLong($opt$LongToInt(4294967297L)));  // 2^32 + 1
+    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(4294967296L)));  // 2^32
+    assertLongEquals(-1L, $opt$IntToLong($opt$LongToInt(4294967295L)));  // 2^32 - 1
+    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(0L)));
+    assertLongEquals(1L, $opt$IntToLong($opt$LongToInt(-4294967295L)));  // -(2^32 - 1)
+    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(-4294967296L)));  // -(2^32)
+    assertLongEquals(-1, $opt$IntToLong($opt$LongToInt(-4294967297L)));  // -(2^32 + 1)
+  }
+
+  private static void longToFloat() {
+    assertFloatEquals(1F, $opt$LongToFloat(1L));
+    assertFloatEquals(0F, $opt$LongToFloat(0L));
+    assertFloatEquals(-1F, $opt$LongToFloat(-1L));
+    assertFloatEquals(51F, $opt$LongToFloat(51L));
+    assertFloatEquals(-51F, $opt$LongToFloat(-51L));
+    assertFloatEquals(2147483647F, $opt$LongToFloat(2147483647L));  // 2^31 - 1
+    assertFloatEquals(-2147483647F, $opt$LongToFloat(-2147483647L));  // -(2^31 - 1)
+    assertFloatEquals(-2147483648F, $opt$LongToFloat(-2147483648L));  // -(2^31)
+    assertFloatEquals(2147483648F, $opt$LongToFloat(2147483648L));  // (2^31)
+    assertFloatEquals(-2147483649F, $opt$LongToFloat(-2147483649L));  // -(2^31 + 1)
+    assertFloatEquals(4294967296F, $opt$LongToFloat(4294967296L));  // (2^32)
+    assertFloatEquals(-4294967296F, $opt$LongToFloat(-4294967296L));  // -(2^32)
+    assertFloatEquals(140739635871745F, $opt$LongToFloat(140739635871745L));  // 1 + 2^15 + 2^31 + 2^47
+    assertFloatEquals(-140739635871745F, $opt$LongToFloat(-140739635871745L));  // -(1 + 2^15 + 2^31 + 2^47)
+    assertFloatEquals(9223372036854775807F, $opt$LongToFloat(9223372036854775807L));  // 2^63 - 1
+    assertFloatEquals(-9223372036854775807F, $opt$LongToFloat(-9223372036854775807L));  // -(2^63 - 1)
+    assertFloatEquals(-9223372036854775808F, $opt$LongToFloat(-9223372036854775808L));  // -(2^63)
+  }
+
+  private static void longToDouble() {
+    assertDoubleEquals(1D, $opt$LongToDouble(1L));
+    assertDoubleEquals(0D, $opt$LongToDouble(0L));
+    assertDoubleEquals(-1D, $opt$LongToDouble(-1L));
+    assertDoubleEquals(51D, $opt$LongToDouble(51L));
+    assertDoubleEquals(-51D, $opt$LongToDouble(-51L));
+    assertDoubleEquals(2147483647D, $opt$LongToDouble(2147483647L));  // 2^31 - 1
+    assertDoubleEquals(-2147483647D, $opt$LongToDouble(-2147483647L));  // -(2^31 - 1)
+    assertDoubleEquals(-2147483648D, $opt$LongToDouble(-2147483648L));  // -(2^31)
+    assertDoubleEquals(2147483648D, $opt$LongToDouble(2147483648L));  // (2^31)
+    assertDoubleEquals(-2147483649D, $opt$LongToDouble(-2147483649L));  // -(2^31 + 1)
+    assertDoubleEquals(4294967296D, $opt$LongToDouble(4294967296L));  // (2^32)
+    assertDoubleEquals(-4294967296D, $opt$LongToDouble(-4294967296L));  // -(2^32)
+    assertDoubleEquals(140739635871745D, $opt$LongToDouble(140739635871745L));  // 1 + 2^15 + 2^31 + 2^47
+    assertDoubleEquals(-140739635871745D, $opt$LongToDouble(-140739635871745L));  // -(1 + 2^15 + 2^31 + 2^47)
+    assertDoubleEquals(9223372036854775807D, $opt$LongToDouble(9223372036854775807L));  // 2^63 - 1
+    assertDoubleEquals(-9223372036854775807D, $opt$LongToDouble(-9223372036854775807L));  // -(2^63 - 1)
+    assertDoubleEquals(-9223372036854775808D, $opt$LongToDouble(-9223372036854775808L));  // -(2^63)
+  }
+
+  private static void floatToInt() {
+    assertIntEquals(1, $opt$FloatToInt(1F));
+    assertIntEquals(0, $opt$FloatToInt(0F));
+    assertIntEquals(0, $opt$FloatToInt(-0F));
+    assertIntEquals(-1, $opt$FloatToInt(-1F));
+    assertIntEquals(51, $opt$FloatToInt(51F));
+    assertIntEquals(-51, $opt$FloatToInt(-51F));
+    assertIntEquals(0, $opt$FloatToInt(0.5F));
+    assertIntEquals(0, $opt$FloatToInt(0.4999999F));
+    assertIntEquals(0, $opt$FloatToInt(-0.4999999F));
+    assertIntEquals(0, $opt$FloatToInt(-0.5F));
+    assertIntEquals(42, $opt$FloatToInt(42.199F));
+    assertIntEquals(-42, $opt$FloatToInt(-42.199F));
+    assertIntEquals(2147483647, $opt$FloatToInt(2147483647F));  // 2^31 - 1
+    assertIntEquals(-2147483648, $opt$FloatToInt(-2147483647F));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$FloatToInt(-2147483648F));  // -(2^31)
+    assertIntEquals(2147483647, $opt$FloatToInt(2147483648F));  // (2^31)
+    assertIntEquals(-2147483648, $opt$FloatToInt(-2147483649F));  // -(2^31 + 1)
+    assertIntEquals(2147483647, $opt$FloatToInt(9223372036854775807F));  // 2^63 - 1
+    assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775807F));  // -(2^63 - 1)
+    assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775808F));  // -(2^63)
+    assertIntEquals(0, $opt$FloatToInt(Float.NaN));
+    assertIntEquals(2147483647, $opt$FloatToInt(Float.POSITIVE_INFINITY));
+    assertIntEquals(-2147483648, $opt$FloatToInt(Float.NEGATIVE_INFINITY));
+  }
+
+  private static void floatToLong() {
+    assertLongEquals(1L, $opt$FloatToLong(1F));
+    assertLongEquals(0L, $opt$FloatToLong(0F));
+    assertLongEquals(0L, $opt$FloatToLong(-0F));
+    assertLongEquals(-1L, $opt$FloatToLong(-1F));
+    assertLongEquals(51L, $opt$FloatToLong(51F));
+    assertLongEquals(-51L, $opt$FloatToLong(-51F));
+    assertLongEquals(0L, $opt$FloatToLong(0.5F));
+    assertLongEquals(0L, $opt$FloatToLong(0.4999999F));
+    assertLongEquals(0L, $opt$FloatToLong(-0.4999999F));
+    assertLongEquals(0L, $opt$FloatToLong(-0.5F));
+    assertLongEquals(42L, $opt$FloatToLong(42.199F));
+    assertLongEquals(-42L, $opt$FloatToLong(-42.199F));
+    assertLongEquals(2147483648L, $opt$FloatToLong(2147483647F));  // 2^31 - 1
+    assertLongEquals(-2147483648L, $opt$FloatToLong(-2147483647F));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$FloatToLong(-2147483648F));  // -(2^31)
+    assertLongEquals(2147483648L, $opt$FloatToLong(2147483648F));  // (2^31)
+    assertLongEquals(-2147483648L, $opt$FloatToLong(-2147483649F));  // -(2^31 + 1)
+    assertLongEquals(9223372036854775807L, $opt$FloatToLong(9223372036854775807F));  // 2^63 - 1
+    assertLongEquals(-9223372036854775808L, $opt$FloatToLong(-9223372036854775807F));  // -(2^63 - 1)
+    assertLongEquals(-9223372036854775808L, $opt$FloatToLong(-9223372036854775808F));  // -(2^63)
+    assertLongEquals(0L, $opt$FloatToLong(Float.NaN));
+    assertLongEquals(9223372036854775807L, $opt$FloatToLong(Float.POSITIVE_INFINITY));
+    assertLongEquals(-9223372036854775808L, $opt$FloatToLong(Float.NEGATIVE_INFINITY));
+  }
+
+  private static void floatToDouble() {
+    assertDoubleEquals(1D, $opt$FloatToDouble(1F));
+    assertDoubleEquals(0D, $opt$FloatToDouble(0F));
+    assertDoubleEquals(0D, $opt$FloatToDouble(-0F));
+    assertDoubleEquals(-1D, $opt$FloatToDouble(-1F));
+    assertDoubleEquals(51D, $opt$FloatToDouble(51F));
+    assertDoubleEquals(-51D, $opt$FloatToDouble(-51F));
+    assertDoubleEquals(0.5D, $opt$FloatToDouble(0.5F));
+    assertDoubleEquals(0.49999991059303284D, $opt$FloatToDouble(0.4999999F));
+    assertDoubleEquals(-0.49999991059303284D, $opt$FloatToDouble(-0.4999999F));
+    assertDoubleEquals(-0.5D, $opt$FloatToDouble(-0.5F));
+    assertDoubleEquals(42.19900131225586D, $opt$FloatToDouble(42.199F));
+    assertDoubleEquals(-42.19900131225586D, $opt$FloatToDouble(-42.199F));
+    assertDoubleEquals(2147483648D, $opt$FloatToDouble(2147483647F));  // 2^31 - 1
+    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483647F));  // -(2^31 - 1)
+    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483648F));  // -(2^31)
+    assertDoubleEquals(2147483648D, $opt$FloatToDouble(2147483648F));  // (2^31)
+    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483649F));  // -(2^31 + 1)
+    assertDoubleEquals(9223372036854775807D, $opt$FloatToDouble(9223372036854775807F));  // 2^63 - 1
+    assertDoubleEquals(-9223372036854775807D, $opt$FloatToDouble(-9223372036854775807F));  // -(2^63 - 1)
+    assertDoubleEquals(-9223372036854775808D, $opt$FloatToDouble(-9223372036854775808F));  // -(2^63)
+    assertDoubleIsNaN($opt$FloatToDouble(Float.NaN));
+    assertDoubleEquals(Double.POSITIVE_INFINITY, $opt$FloatToDouble(Float.POSITIVE_INFINITY));
+    assertDoubleEquals(Double.NEGATIVE_INFINITY, $opt$FloatToDouble(Float.NEGATIVE_INFINITY));
+  }
+
+  private static void doubleToInt() {
+    assertIntEquals(1, $opt$DoubleToInt(1D));
+    assertIntEquals(0, $opt$DoubleToInt(0D));
+    assertIntEquals(0, $opt$DoubleToInt(-0D));
+    assertIntEquals(-1, $opt$DoubleToInt(-1D));
+    assertIntEquals(51, $opt$DoubleToInt(51D));
+    assertIntEquals(-51, $opt$DoubleToInt(-51D));
+    assertIntEquals(0, $opt$DoubleToInt(0.5D));
+    assertIntEquals(0, $opt$DoubleToInt(0.4999999D));
+    assertIntEquals(0, $opt$DoubleToInt(-0.4999999D));
+    assertIntEquals(0, $opt$DoubleToInt(-0.5D));
+    assertIntEquals(42, $opt$DoubleToInt(42.199D));
+    assertIntEquals(-42, $opt$DoubleToInt(-42.199D));
+    assertIntEquals(2147483647, $opt$DoubleToInt(2147483647D));  // 2^31 - 1
+    assertIntEquals(-2147483647, $opt$DoubleToInt(-2147483647D));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$DoubleToInt(-2147483648D));  // -(2^31)
+    assertIntEquals(2147483647, $opt$DoubleToInt(2147483648D));  // (2^31)
+    assertIntEquals(-2147483648, $opt$DoubleToInt(-2147483649D));  // -(2^31 + 1)
+    assertIntEquals(2147483647, $opt$DoubleToInt(9223372036854775807D));  // 2^63 - 1
+    assertIntEquals(-2147483648, $opt$DoubleToInt(-9223372036854775807D));  // -(2^63 - 1)
+    assertIntEquals(-2147483648, $opt$DoubleToInt(-9223372036854775808D));  // -(2^63)
+    assertIntEquals(0, $opt$DoubleToInt(Double.NaN));
+    assertIntEquals(2147483647, $opt$DoubleToInt(Double.POSITIVE_INFINITY));
+    assertIntEquals(-2147483648, $opt$DoubleToInt(Double.NEGATIVE_INFINITY));
+  }
+
+  private static void doubleToLong() {
+    assertLongEquals(1L, $opt$DoubleToLong(1D));
+    assertLongEquals(0L, $opt$DoubleToLong(0D));
+    assertLongEquals(0L, $opt$DoubleToLong(-0D));
+    assertLongEquals(-1L, $opt$DoubleToLong(-1D));
+    assertLongEquals(51L, $opt$DoubleToLong(51D));
+    assertLongEquals(-51L, $opt$DoubleToLong(-51D));
+    assertLongEquals(0L, $opt$DoubleToLong(0.5D));
+    assertLongEquals(0L, $opt$DoubleToLong(0.4999999D));
+    assertLongEquals(0L, $opt$DoubleToLong(-0.4999999D));
+    assertLongEquals(0L, $opt$DoubleToLong(-0.5D));
+    assertLongEquals(42L, $opt$DoubleToLong(42.199D));
+    assertLongEquals(-42L, $opt$DoubleToLong(-42.199D));
+    assertLongEquals(2147483647L, $opt$DoubleToLong(2147483647D));  // 2^31 - 1
+    assertLongEquals(-2147483647L, $opt$DoubleToLong(-2147483647D));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$DoubleToLong(-2147483648D));  // -(2^31)
+    assertLongEquals(2147483648L, $opt$DoubleToLong(2147483648D));  // (2^31)
+    assertLongEquals(-2147483649L, $opt$DoubleToLong(-2147483649D));  // -(2^31 + 1)
+    assertLongEquals(9223372036854775807L, $opt$DoubleToLong(9223372036854775807D));  // 2^63 - 1
+    assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(-9223372036854775807D));  // -(2^63 - 1)
+    assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(-9223372036854775808D));  // -(2^63)
+    assertLongEquals(0L, $opt$DoubleToLong(Double.NaN));
+    assertLongEquals(9223372036854775807L, $opt$DoubleToLong(Double.POSITIVE_INFINITY));
+    assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(Double.NEGATIVE_INFINITY));
+  }
+
+  private static void doubleToFloat() {
+    assertFloatEquals(1F, $opt$DoubleToFloat(1D));
+    assertFloatEquals(0F, $opt$DoubleToFloat(0D));
+    assertFloatEquals(0F, $opt$DoubleToFloat(-0D));
+    assertFloatEquals(-1F, $opt$DoubleToFloat(-1D));
+    assertFloatEquals(51F, $opt$DoubleToFloat(51D));
+    assertFloatEquals(-51F, $opt$DoubleToFloat(-51D));
+    assertFloatEquals(0.5F, $opt$DoubleToFloat(0.5D));
+    assertFloatEquals(0.4999999F, $opt$DoubleToFloat(0.4999999D));
+    assertFloatEquals(-0.4999999F, $opt$DoubleToFloat(-0.4999999D));
+    assertFloatEquals(-0.5F, $opt$DoubleToFloat(-0.5D));
+    assertFloatEquals(42.199F, $opt$DoubleToFloat(42.199D));
+    assertFloatEquals(-42.199F, $opt$DoubleToFloat(-42.199D));
+    assertFloatEquals(2147483648F, $opt$DoubleToFloat(2147483647D));  // 2^31 - 1
+    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483647D));  // -(2^31 - 1)
+    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483648D));  // -(2^31)
+    assertFloatEquals(2147483648F, $opt$DoubleToFloat(2147483648D));  // (2^31)
+    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483649D));  // -(2^31 + 1)
+    assertFloatEquals(9223372036854775807F, $opt$DoubleToFloat(9223372036854775807D));  // 2^63 - 1
+    assertFloatEquals(-9223372036854775807F, $opt$DoubleToFloat(-9223372036854775807D));  // -(2^63 - 1)
+    assertFloatEquals(-9223372036854775808F, $opt$DoubleToFloat(-9223372036854775808D));  // -(2^63)
+    assertFloatIsNaN($opt$DoubleToFloat(Float.NaN));
+    assertFloatEquals(Float.POSITIVE_INFINITY, $opt$DoubleToFloat(Double.POSITIVE_INFINITY));
+    assertFloatEquals(Float.NEGATIVE_INFINITY, $opt$DoubleToFloat(Double.NEGATIVE_INFINITY));
+  }
+
+  private static void shortToByte() {
+    assertByteEquals((byte)1, $opt$ShortToByte((short)1));
+    assertByteEquals((byte)0, $opt$ShortToByte((short)0));
+    assertByteEquals((byte)-1, $opt$ShortToByte((short)-1));
+    assertByteEquals((byte)51, $opt$ShortToByte((short)51));
+    assertByteEquals((byte)-51, $opt$ShortToByte((short)-51));
+    assertByteEquals((byte)127, $opt$ShortToByte((short)127));  // 2^7 - 1
+    assertByteEquals((byte)-127, $opt$ShortToByte((short)-127));  // -(2^7 - 1)
+    assertByteEquals((byte)-128, $opt$ShortToByte((short)-128));  // -(2^7)
+    assertByteEquals((byte)-128, $opt$ShortToByte((short)128));  // 2^7
+    assertByteEquals((byte)127, $opt$ShortToByte((short)-129));  // -(2^7 + 1)
+    assertByteEquals((byte)-1, $opt$ShortToByte((short)32767));  // 2^15 - 1
+    assertByteEquals((byte)0, $opt$ShortToByte((short)-32768));  // -(2^15)
+  }
+
+  private static void intToByte() {
+    assertByteEquals((byte)1, $opt$IntToByte(1));
+    assertByteEquals((byte)0, $opt$IntToByte(0));
+    assertByteEquals((byte)-1, $opt$IntToByte(-1));
+    assertByteEquals((byte)51, $opt$IntToByte(51));
+    assertByteEquals((byte)-51, $opt$IntToByte(-51));
+    assertByteEquals((byte)127, $opt$IntToByte(127));  // 2^7 - 1
+    assertByteEquals((byte)-127, $opt$IntToByte(-127));  // -(2^7 - 1)
+    assertByteEquals((byte)-128, $opt$IntToByte(-128));  // -(2^7)
+    assertByteEquals((byte)-128, $opt$IntToByte(128));  // 2^7
+    assertByteEquals((byte)127, $opt$IntToByte(-129));  // -(2^7 + 1)
+    assertByteEquals((byte)-1, $opt$IntToByte(2147483647));  // 2^31 - 1
+    assertByteEquals((byte)0, $opt$IntToByte(-2147483648));  // -(2^31)
+  }
+
+  private static void charToByte() {
+    assertByteEquals((byte)1, $opt$CharToByte((char)1));
+    assertByteEquals((byte)0, $opt$CharToByte((char)0));
+    assertByteEquals((byte)51, $opt$CharToByte((char)51));
+    assertByteEquals((byte)127, $opt$CharToByte((char)127));  // 2^7 - 1
+    assertByteEquals((byte)-128, $opt$CharToByte((char)128));  // 2^7
+    assertByteEquals((byte)-1, $opt$CharToByte((char)32767));  // 2^15 - 1
+    assertByteEquals((byte)-1, $opt$CharToByte((char)65535));  // 2^16 - 1
+    assertByteEquals((byte)-1, $opt$CharToByte((char)-1));
+    assertByteEquals((byte)-51, $opt$CharToByte((char)-51));
+    assertByteEquals((byte)-127, $opt$CharToByte((char)-127));  // -(2^7 - 1)
+    assertByteEquals((byte)-128, $opt$CharToByte((char)-128));  // -(2^7)
+    assertByteEquals((byte)127, $opt$CharToByte((char)-129));  // -(2^7 + 1)
+  }
+
+  private static void byteToShort() {
+    assertShortEquals((short)1, $opt$ByteToShort((byte)1));
+    assertShortEquals((short)0, $opt$ByteToShort((byte)0));
+    assertShortEquals((short)-1, $opt$ByteToShort((byte)-1));
+    assertShortEquals((short)51, $opt$ByteToShort((byte)51));
+    assertShortEquals((short)-51, $opt$ByteToShort((byte)-51));
+    assertShortEquals((short)127, $opt$ByteToShort((byte)127));  // 2^7 - 1
+    assertShortEquals((short)-127, $opt$ByteToShort((byte)-127));  // -(2^7 - 1)
+    assertShortEquals((short)-128, $opt$ByteToShort((byte)-128));  // -(2^7)
+  }
+
+  private static void intToShort() {
+    assertShortEquals((short)1, $opt$IntToShort(1));
+    assertShortEquals((short)0, $opt$IntToShort(0));
+    assertShortEquals((short)-1, $opt$IntToShort(-1));
+    assertShortEquals((short)51, $opt$IntToShort(51));
+    assertShortEquals((short)-51, $opt$IntToShort(-51));
+    assertShortEquals((short)32767, $opt$IntToShort(32767));  // 2^15 - 1
+    assertShortEquals((short)-32767, $opt$IntToShort(-32767));  // -(2^15 - 1)
+    assertShortEquals((short)-32768, $opt$IntToShort(-32768));  // -(2^15)
+    assertShortEquals((short)-32768, $opt$IntToShort(32768));  // 2^15
+    assertShortEquals((short)32767, $opt$IntToShort(-32769));  // -(2^15 + 1)
+    assertShortEquals((short)-1, $opt$IntToShort(2147483647));  // 2^31 - 1
+    assertShortEquals((short)0, $opt$IntToShort(-2147483648));  // -(2^31)
+  }
+
+  private static void charToShort() {
+    assertShortEquals((short)1, $opt$CharToShort((char)1));
+    assertShortEquals((short)0, $opt$CharToShort((char)0));
+    assertShortEquals((short)51, $opt$CharToShort((char)51));
+    assertShortEquals((short)32767, $opt$CharToShort((char)32767));  // 2^15 - 1
+    assertShortEquals((short)-32768, $opt$CharToShort((char)32768));  // 2^15
+    assertShortEquals((short)-32767, $opt$CharToShort((char)32769));  // 2^15
+    assertShortEquals((short)-1, $opt$CharToShort((char)65535));  // 2^16 - 1
+    assertShortEquals((short)-1, $opt$CharToShort((char)-1));
+    assertShortEquals((short)-51, $opt$CharToShort((char)-51));
+    assertShortEquals((short)-32767, $opt$CharToShort((char)-32767));  // -(2^15 - 1)
+    assertShortEquals((short)-32768, $opt$CharToShort((char)-32768));  // -(2^15)
+    assertShortEquals((short)32767, $opt$CharToShort((char)-32769));  // -(2^15 + 1)
+  }
+
+  private static void byteToChar() {
+    assertCharEquals((char)1, $opt$ByteToChar((byte)1));
+    assertCharEquals((char)0, $opt$ByteToChar((byte)0));
+    assertCharEquals((char)65535, $opt$ByteToChar((byte)-1));
+    assertCharEquals((char)51, $opt$ByteToChar((byte)51));
+    assertCharEquals((char)65485, $opt$ByteToChar((byte)-51));
+    assertCharEquals((char)127, $opt$ByteToChar((byte)127));  // 2^7 - 1
+    assertCharEquals((char)65409, $opt$ByteToChar((byte)-127));  // -(2^7 - 1)
+    assertCharEquals((char)65408, $opt$ByteToChar((byte)-128));  // -(2^7)
+  }
+
+  private static void shortToChar() {
+    assertCharEquals((char)1, $opt$ShortToChar((short)1));
+    assertCharEquals((char)0, $opt$ShortToChar((short)0));
+    assertCharEquals((char)65535, $opt$ShortToChar((short)-1));
+    assertCharEquals((char)51, $opt$ShortToChar((short)51));
+    assertCharEquals((char)65485, $opt$ShortToChar((short)-51));
+    assertCharEquals((char)32767, $opt$ShortToChar((short)32767));  // 2^15 - 1
+    assertCharEquals((char)32769, $opt$ShortToChar((short)-32767));  // -(2^15 - 1)
+    assertCharEquals((char)32768, $opt$ShortToChar((short)-32768));  // -(2^15)
+  }
+
+  private static void intToChar() {
+    assertCharEquals((char)1, $opt$IntToChar(1));
+    assertCharEquals((char)0, $opt$IntToChar(0));
+    assertCharEquals((char)65535, $opt$IntToChar(-1));
+    assertCharEquals((char)51, $opt$IntToChar(51));
+    assertCharEquals((char)65485, $opt$IntToChar(-51));
+    assertCharEquals((char)32767, $opt$IntToChar(32767));  // 2^15 - 1
+    assertCharEquals((char)32769, $opt$IntToChar(-32767));  // -(2^15 - 1)
+    assertCharEquals((char)32768, $opt$IntToChar(32768));  // 2^15
+    assertCharEquals((char)32768, $opt$IntToChar(-32768));  // -(2^15)
+    assertCharEquals((char)65535, $opt$IntToChar(65535));  // 2^16 - 1
+    assertCharEquals((char)1, $opt$IntToChar(-65535));  // -(2^16 - 1)
+    assertCharEquals((char)0, $opt$IntToChar(65536));  // 2^16
+    assertCharEquals((char)0, $opt$IntToChar(-65536));  // -(2^16)
+    assertCharEquals((char)65535, $opt$IntToChar(2147483647));  // 2^31 - 1
+    assertCharEquals((char)0, $opt$IntToChar(-2147483648));  // -(2^31)
+  }
+
+
+  // These methods produce int-to-long Dex instructions.
+  static long $opt$ByteToLong(byte a) { return (long)a; }
+  static long $opt$ShortToLong(short a) { return (long)a; }
+  static long $opt$IntToLong(int a) { return (long)a; }
+  static long $opt$CharToLong(int a) { return (long)a; }
+
+  // These methods produce int-to-float Dex instructions.
+  static float $opt$ByteToFloat(byte a) { return (float)a; }
+  static float $opt$ShortToFloat(short a) { return (float)a; }
+  static float $opt$IntToFloat(int a) { return (float)a; }
+  static float $opt$CharToFloat(char a) { return (float)a; }
+
+  // These methods produce int-to-double Dex instructions.
+  static double $opt$ByteToDouble(byte a) { return (double)a; }
+  static double $opt$ShortToDouble(short a) { return (double)a; }
+  static double $opt$IntToDouble(int a) { return (double)a; }
+  static double $opt$CharToDouble(int a) { return (double)a; }
+
+  // These methods produce long-to-int Dex instructions.
+  static int $opt$LongToInt(long a) { return (int)a; }
+  static int $opt$LongLiteralToInt() { return (int)42L; }
+
+  // This method produces a long-to-float Dex instruction.
+  static float $opt$LongToFloat(long a) { return (float)a; }
+
+  // This method produces a long-to-double Dex instruction.
+  static double $opt$LongToDouble(long a) { return (double)a; }
+
+  // This method produces a float-to-int Dex instruction.
+  static int $opt$FloatToInt(float a) { return (int)a; }
+
+  // This method produces a float-to-long Dex instruction.
+  static long $opt$FloatToLong(float a){ return (long)a; }
+
+  // This method produces a float-to-double Dex instruction.
+  static double $opt$FloatToDouble(float a) { return (double)a; }
+
+  // This method produces a double-to-int Dex instruction.
+  static int $opt$DoubleToInt(double a){ return (int)a; }
+
+  // This method produces a double-to-long Dex instruction.
+  static long $opt$DoubleToLong(double a){ return (long)a; }
+
+  // This method produces a double-to-float Dex instruction.
+  static float $opt$DoubleToFloat(double a) { return (float)a; }
+
+  // These methods produce int-to-byte Dex instructions.
+  static byte $opt$ShortToByte(short a) { return (byte)a; }
+  static byte $opt$IntToByte(int a) { return (byte)a; }
+  static byte $opt$CharToByte(char a) { return (byte)a; }
+
+  // These methods produce int-to-short Dex instructions.
+  static short $opt$ByteToShort(byte a) { return (short)a; }
+  static short $opt$IntToShort(int a) { return (short)a; }
+  static short $opt$CharToShort(char a) { return (short)a; }
+
+  // These methods produce int-to-char Dex instructions.
+  static char $opt$ByteToChar(byte a) { return (char)a; }
+  static char $opt$ShortToChar(short a) { return (char)a; }
+  static char $opt$IntToChar(int a) { return (char)a; }
+}
diff --git a/test/423-invoke-interface/expected.txt b/test/423-invoke-interface/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/423-invoke-interface/expected.txt
diff --git a/test/423-invoke-interface/info.txt b/test/423-invoke-interface/info.txt
new file mode 100644
index 0000000..a496ffe
--- /dev/null
+++ b/test/423-invoke-interface/info.txt
@@ -0,0 +1,2 @@
+invoke-interface test with hopefully enough interface methods to trigger
+a conflict in our imt table.
diff --git a/test/423-invoke-interface/src/Main.java b/test/423-invoke-interface/src/Main.java
new file mode 100644
index 0000000..fae857a
--- /dev/null
+++ b/test/423-invoke-interface/src/Main.java
@@ -0,0 +1,120 @@
+/*
+ * 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 {
+  static interface Itf {
+    public int return1();
+    public int return2();
+    public int return3();
+    public int return4();
+    public int return5();
+    public int return6();
+    public int return7();
+    public int return8();
+    public int return9();
+    public int return10();
+    public int return11();
+    public int return12();
+    public int return13();
+    public int return14();
+    public int return15();
+    public int return16();
+    public int return17();
+    public int return18();
+    public int return19();
+    public int return20();
+  }
+
+  static class ItfImpl1 implements Itf {
+    public int return1() { return 1; }
+    public int return2() { return 2; }
+    public int return3() { return 3; }
+    public int return4() { return 4; }
+    public int return5() { return 5; }
+    public int return6() { return 6; }
+    public int return7() { return 7; }
+    public int return8() { return 8; }
+    public int return9() { return 9; }
+    public int return10() { return 10; }
+    public int return11() { return 11; }
+    public int return12() { return 12; }
+    public int return13() { return 13; }
+    public int return14() { return 14; }
+    public int return15() { return 15; }
+    public int return16() { return 16; }
+    public int return17() { return 17; }
+    public int return18() { return 18; }
+    public int return19() { return 19; }
+    public int return20() { return 20; }
+  }
+
+  static class ItfImpl2 implements Itf {
+    public int return1() { return -1; }
+    public int return2() { return -2; }
+    public int return3() { return -3; }
+    public int return4() { return -4; }
+    public int return5() { return -5; }
+    public int return6() { return -6; }
+    public int return7() { return -7; }
+    public int return8() { return -8; }
+    public int return9() { return -9; }
+    public int return10() { return -10; }
+    public int return11() { return -11; }
+    public int return12() { return -12; }
+    public int return13() { return -13; }
+    public int return14() { return -14; }
+    public int return15() { return -15; }
+    public int return16() { return -16; }
+    public int return17() { return -17; }
+    public int return18() { return -18; }
+    public int return19() { return -19; }
+    public int return20() { return -20; }
+  }
+
+  public static void main(String[] args) {
+    $opt$InvokeInterface(new ItfImpl1(), 1);
+    $opt$InvokeInterface(new ItfImpl2(), -1);
+  }
+
+  public static void assertEquals(int expected, int value) {
+    if (expected != value) {
+      throw new Error("Expected " + expected +  ", got " + value);
+    }
+  }
+
+  public static void $opt$InvokeInterface(Itf object, int factor) {
+    assertEquals(factor * 1, object.return1());
+    assertEquals(factor * 2, object.return2());
+    assertEquals(factor * 3, object.return3());
+    assertEquals(factor * 4, object.return4());
+    assertEquals(factor * 5, object.return5());
+    assertEquals(factor * 6, object.return6());
+    assertEquals(factor * 7, object.return7());
+    assertEquals(factor * 8, object.return8());
+    assertEquals(factor * 9, object.return9());
+    assertEquals(factor * 10, object.return10());
+    assertEquals(factor * 11, object.return11());
+    assertEquals(factor * 12, object.return12());
+    assertEquals(factor * 13, object.return13());
+    assertEquals(factor * 14, object.return14());
+    assertEquals(factor * 15, object.return15());
+    assertEquals(factor * 16, object.return16());
+    assertEquals(factor * 17, object.return17());
+    assertEquals(factor * 18, object.return18());
+    assertEquals(factor * 19, object.return19());
+    assertEquals(factor * 20, object.return20());
+  }
+}
diff --git a/test/424-checkcast/expected.txt b/test/424-checkcast/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/424-checkcast/expected.txt
diff --git a/test/424-checkcast/info.txt b/test/424-checkcast/info.txt
new file mode 100644
index 0000000..b50b082
--- /dev/null
+++ b/test/424-checkcast/info.txt
@@ -0,0 +1 @@
+Simple tests for the checkcast opcode.
diff --git a/test/424-checkcast/src/Main.java b/test/424-checkcast/src/Main.java
new file mode 100644
index 0000000..791b166
--- /dev/null
+++ b/test/424-checkcast/src/Main.java
@@ -0,0 +1,73 @@
+/*
+ * 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 {
+  public static Object a;
+
+  public static Object $opt$CheckCastMain() {
+    return (Main)a;
+  }
+
+  public static Object $opt$CheckCastFinalClass() {
+    return (FinalClass)a;
+  }
+
+  public static void main(String[] args) {
+    $opt$TestMain();
+    $opt$TestFinalClass();
+  }
+
+  public static void $opt$TestMain() {
+    a = new Main();
+    $opt$CheckCastMain();
+
+    a = null;
+    $opt$CheckCastMain();
+
+    a = new MainChild();
+    $opt$CheckCastMain();
+
+    a = new Object();
+    try {
+      $opt$CheckCastMain();
+      throw new Error("Should have gotten a ClassCastException");
+    } catch (ClassCastException ex) {}
+  }
+
+  public static void $opt$TestFinalClass() {
+    a = new FinalClass();
+    $opt$CheckCastFinalClass();
+
+    a = null;
+    $opt$CheckCastFinalClass();
+
+    a = new Main();
+    try {
+      $opt$CheckCastFinalClass();
+      throw new Error("Should have gotten a ClassCastException");
+    } catch (ClassCastException ex) {}
+
+    a = new Object();
+    try {
+      $opt$CheckCastFinalClass();
+      throw new Error("Should have gotten a ClassCastException");
+    } catch (ClassCastException ex) {}
+  }
+
+  static class MainChild extends Main {}
+
+  static final class FinalClass {}
+}
diff --git a/test/425-invoke-super/expected.txt b/test/425-invoke-super/expected.txt
new file mode 100644
index 0000000..f7f6ae4
--- /dev/null
+++ b/test/425-invoke-super/expected.txt
@@ -0,0 +1 @@
+Test started
diff --git a/test/425-invoke-super/info.txt b/test/425-invoke-super/info.txt
new file mode 100644
index 0000000..ad99030
--- /dev/null
+++ b/test/425-invoke-super/info.txt
@@ -0,0 +1 @@
+Tests the invoke-super opcode.
diff --git a/test/425-invoke-super/smali/invokesuper.smali b/test/425-invoke-super/smali/invokesuper.smali
new file mode 100644
index 0000000..ab13091
--- /dev/null
+++ b/test/425-invoke-super/smali/invokesuper.smali
@@ -0,0 +1,40 @@
+#
+# 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.
+
+
+.class public LInvokeSuper;
+.super LSuperClass;
+
+.method public constructor <init>()V
+.registers 1
+       invoke-direct {v0}, LSuperClass;-><init>()V
+       return-void
+.end method
+
+
+.method public run()I
+.registers 2
+    # Do an invoke super on a non-super class to force slow path.
+    invoke-super {v1}, LInvokeSuper;->returnInt()I
+    move-result v0
+    return v0
+.end method
+
+
+.method public returnInt()I
+.registers 2
+    const v0, 777
+    return v0
+.end method
diff --git a/test/425-invoke-super/smali/subclass.smali b/test/425-invoke-super/smali/subclass.smali
new file mode 100644
index 0000000..54e3474
--- /dev/null
+++ b/test/425-invoke-super/smali/subclass.smali
@@ -0,0 +1,29 @@
+#
+# 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.
+
+.class public LSubClass;
+.super LInvokeSuper;
+
+.method public constructor <init>()V
+.registers 1
+       invoke-direct {v0}, LInvokeSuper;-><init>()V
+       return-void
+.end method
+
+.method public returnInt()I
+.registers 2
+    const v0, 0
+    return v0
+.end method
diff --git a/test/425-invoke-super/smali/superclass.smali b/test/425-invoke-super/smali/superclass.smali
new file mode 100644
index 0000000..b366aa7
--- /dev/null
+++ b/test/425-invoke-super/smali/superclass.smali
@@ -0,0 +1,29 @@
+#
+# 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.
+
+.class public LSuperClass;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+       invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+       return-void
+.end method
+
+.method public returnInt()I
+.registers 2
+    const v0, 42
+    return v0
+.end method
diff --git a/test/425-invoke-super/src/Main.java b/test/425-invoke-super/src/Main.java
new file mode 100644
index 0000000..f3166fd
--- /dev/null
+++ b/test/425-invoke-super/src/Main.java
@@ -0,0 +1,55 @@
+/*
+ * 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.Method;
+
+public class Main {
+  static class A {
+    public int foo() { return 1; }
+  }
+
+  static class B extends A {
+    public int $opt$bar() { return super.foo(); }
+  }
+
+  static class C extends B {
+    public int foo() { return 42; }
+  }
+
+  static class D extends C {
+  }
+
+  static void assertEquals(int expected, int value) {
+    if (expected != value) {
+      throw new Error("Expected " + expected + ", got " + value);
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    // Workaround for b/18051191.
+    System.out.println("Test started");
+    assertEquals(1, new B().$opt$bar());
+    assertEquals(1, new C().$opt$bar());
+    assertEquals(1, new D().$opt$bar());
+
+    Class<?> c = Class.forName("InvokeSuper");
+    Method m = c.getMethod("run");
+    assertEquals(42, ((Integer)m.invoke(c.newInstance(), new Object[0])).intValue());
+
+    c = Class.forName("SubClass");
+    assertEquals(42, ((Integer)m.invoke(c.newInstance(), new Object[0])).intValue());
+  }
+}
diff --git a/test/426-monitor/expected.txt b/test/426-monitor/expected.txt
new file mode 100644
index 0000000..2ffeff4
--- /dev/null
+++ b/test/426-monitor/expected.txt
@@ -0,0 +1,5 @@
+In static method
+In instance method
+In synchronized block
+In second instance method
+In second static method
diff --git a/test/426-monitor/info.txt b/test/426-monitor/info.txt
new file mode 100644
index 0000000..1b093ea
--- /dev/null
+++ b/test/426-monitor/info.txt
@@ -0,0 +1 @@
+Simple tests for monitorenter/monitorexit.
diff --git a/test/426-monitor/src/Main.java b/test/426-monitor/src/Main.java
new file mode 100644
index 0000000..a073a95
--- /dev/null
+++ b/test/426-monitor/src/Main.java
@@ -0,0 +1,52 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    $opt$StaticSynchronizedMethod();
+    new Main().$opt$InstanceSynchronizedMethod();
+    $opt$SynchronizedBlock();
+    new Main().$opt$DoubleInstanceSynchronized();
+    $opt$DoubleStaticSynchronized();
+  }
+
+  public static synchronized void $opt$StaticSynchronizedMethod() {
+    System.out.println("In static method");
+  }
+
+  public synchronized void $opt$InstanceSynchronizedMethod() {
+    System.out.println("In instance method");
+  }
+
+  public static void $opt$SynchronizedBlock() {
+    Object o = new Object();
+    synchronized(o) {
+      System.out.println("In synchronized block");
+    }
+  }
+
+  public synchronized void $opt$DoubleInstanceSynchronized() {
+    synchronized (this) {
+      System.out.println("In second instance method");
+    }
+  }
+
+  public synchronized static void $opt$DoubleStaticSynchronized() {
+    synchronized (Main.class) {
+      System.out.println("In second static method");
+    }
+  }
+}
diff --git a/test/427-bitwise/expected.txt b/test/427-bitwise/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/427-bitwise/expected.txt
diff --git a/test/427-bitwise/info.txt b/test/427-bitwise/info.txt
new file mode 100644
index 0000000..4762847
--- /dev/null
+++ b/test/427-bitwise/info.txt
@@ -0,0 +1 @@
+Tests for the and/or/xor opcodes.
diff --git a/test/427-bitwise/src/Main.java b/test/427-bitwise/src/Main.java
new file mode 100644
index 0000000..e984066
--- /dev/null
+++ b/test/427-bitwise/src/Main.java
@@ -0,0 +1,233 @@
+/*
+ * 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 main(String[] args) {
+    andInt();
+    andLong();
+
+    orInt();
+    orLong();
+
+    xorInt();
+    xorLong();
+  }
+
+  private static void andInt() {
+    expectEquals(1, $opt$And(5, 3));
+    expectEquals(0, $opt$And(0, 0));
+    expectEquals(0, $opt$And(0, 3));
+    expectEquals(0, $opt$And(3, 0));
+    expectEquals(1, $opt$And(1, -3));
+    expectEquals(-12, $opt$And(-12, -3));
+
+    expectEquals(1, $opt$AndLit8(1));
+    expectEquals(0, $opt$AndLit8(0));
+    expectEquals(0, $opt$AndLit8(0));
+    expectEquals(3, $opt$AndLit8(3));
+    expectEquals(4, $opt$AndLit8(-12));
+
+    expectEquals(0, $opt$AndLit16(1));
+    expectEquals(0, $opt$AndLit16(0));
+    expectEquals(0, $opt$AndLit16(0));
+    expectEquals(0, $opt$AndLit16(3));
+    expectEquals(65280, $opt$AndLit16(-12));
+  }
+
+  private static void andLong() {
+    expectEquals(1L, $opt$And(5L, 3L));
+    expectEquals(0L, $opt$And(0L, 0L));
+    expectEquals(0L, $opt$And(0L, 3L));
+    expectEquals(0L, $opt$And(3L, 0L));
+    expectEquals(1L, $opt$And(1L, -3L));
+    expectEquals(-12L, $opt$And(-12L, -3L));
+
+    expectEquals(1L, $opt$AndLit8(1L));
+    expectEquals(0L, $opt$AndLit8(0L));
+    expectEquals(0L, $opt$AndLit8(0L));
+    expectEquals(3L, $opt$AndLit8(3L));
+    expectEquals(4L, $opt$AndLit8(-12L));
+
+    expectEquals(0L, $opt$AndLit16(1L));
+    expectEquals(0L, $opt$AndLit16(0L));
+    expectEquals(0L, $opt$AndLit16(0L));
+    expectEquals(0L, $opt$AndLit16(3L));
+    expectEquals(65280L, $opt$AndLit16(-12L));
+  }
+
+  static int $opt$And(int a, int b) {
+    return a & b;
+  }
+
+  static int $opt$AndLit8(int a) {
+    return a & 0xF;
+  }
+
+  static int $opt$AndLit16(int a) {
+    return a & 0xFF00;
+  }
+
+  static long $opt$And(long a, long b) {
+    return a & b;
+  }
+
+  static long $opt$AndLit8(long a) {
+    return a & 0xF;
+  }
+
+  static long $opt$AndLit16(long a) {
+    return a & 0xFF00;
+  }
+
+  private static void orInt() {
+    expectEquals(7, $opt$Or(5, 3));
+    expectEquals(0, $opt$Or(0, 0));
+    expectEquals(3, $opt$Or(0, 3));
+    expectEquals(3, $opt$Or(3, 0));
+    expectEquals(-3, $opt$Or(1, -3));
+    expectEquals(-3, $opt$Or(-12, -3));
+
+    expectEquals(15, $opt$OrLit8(1));
+    expectEquals(15, $opt$OrLit8(0));
+    expectEquals(15, $opt$OrLit8(3));
+    expectEquals(-1, $opt$OrLit8(-12));
+
+    expectEquals(0xFF01, $opt$OrLit16(1));
+    expectEquals(0xFF00, $opt$OrLit16(0));
+    expectEquals(0xFF03, $opt$OrLit16(3));
+    expectEquals(-12, $opt$OrLit16(-12));
+  }
+
+  private static void orLong() {
+    expectEquals(7L, $opt$Or(5L, 3L));
+    expectEquals(0L, $opt$Or(0L, 0L));
+    expectEquals(3L, $opt$Or(0L, 3L));
+    expectEquals(3L, $opt$Or(3L, 0L));
+    expectEquals(-3L, $opt$Or(1L, -3L));
+    expectEquals(-3L, $opt$Or(-12L, -3L));
+
+    expectEquals(15L, $opt$OrLit8(1L));
+    expectEquals(15L, $opt$OrLit8(0L));
+    expectEquals(15L, $opt$OrLit8(3L));
+    expectEquals(-1L, $opt$OrLit8(-12L));
+
+    expectEquals(0xFF01L, $opt$OrLit16(1L));
+    expectEquals(0xFF00L, $opt$OrLit16(0L));
+    expectEquals(0xFF03L, $opt$OrLit16(3L));
+    expectEquals(-12L, $opt$OrLit16(-12L));
+  }
+
+  static int $opt$Or(int a, int b) {
+    return a | b;
+  }
+
+  static int $opt$OrLit8(int a) {
+    return a | 0xF;
+  }
+
+  static int $opt$OrLit16(int a) {
+    return a | 0xFF00;
+  }
+
+  static long $opt$Or(long a, long b) {
+    return a | b;
+  }
+
+  static long $opt$OrLit8(long a) {
+    return a | 0xF;
+  }
+
+  static long $opt$OrLit16(long a) {
+    return a | 0xFF00;
+  }
+
+  private static void xorInt() {
+    expectEquals(6, $opt$Xor(5, 3));
+    expectEquals(0, $opt$Xor(0, 0));
+    expectEquals(3, $opt$Xor(0, 3));
+    expectEquals(3, $opt$Xor(3, 0));
+    expectEquals(-4, $opt$Xor(1, -3));
+    expectEquals(9, $opt$Xor(-12, -3));
+
+    expectEquals(14, $opt$XorLit8(1));
+    expectEquals(15, $opt$XorLit8(0));
+    expectEquals(12, $opt$XorLit8(3));
+    expectEquals(-5, $opt$XorLit8(-12));
+
+    expectEquals(0xFF01, $opt$XorLit16(1));
+    expectEquals(0xFF00, $opt$XorLit16(0));
+    expectEquals(0xFF03, $opt$XorLit16(3));
+    expectEquals(-0xFF0c, $opt$XorLit16(-12));
+  }
+
+  private static void xorLong() {
+    expectEquals(6L, $opt$Xor(5L, 3L));
+    expectEquals(0L, $opt$Xor(0L, 0L));
+    expectEquals(3L, $opt$Xor(0L, 3L));
+    expectEquals(3L, $opt$Xor(3L, 0L));
+    expectEquals(-4L, $opt$Xor(1L, -3L));
+    expectEquals(9L, $opt$Xor(-12L, -3L));
+
+    expectEquals(14L, $opt$XorLit8(1L));
+    expectEquals(15L, $opt$XorLit8(0L));
+    expectEquals(12L, $opt$XorLit8(3L));
+    expectEquals(-5L, $opt$XorLit8(-12L));
+
+    expectEquals(0xFF01L, $opt$XorLit16(1L));
+    expectEquals(0xFF00L, $opt$XorLit16(0L));
+    expectEquals(0xFF03L, $opt$XorLit16(3L));
+    expectEquals(-0xFF0cL, $opt$XorLit16(-12L));
+  }
+
+  static int $opt$Xor(int a, int b) {
+    return a ^ b;
+  }
+
+  static int $opt$XorLit8(int a) {
+    return a ^ 0xF;
+  }
+
+  static int $opt$XorLit16(int a) {
+    return a ^ 0xFF00;
+  }
+
+  static long $opt$Xor(long a, long b) {
+    return a ^ b;
+  }
+
+  static long $opt$XorLit8(long a) {
+    return a ^ 0xF;
+  }
+
+  static long $opt$XorLit16(long a) {
+    return a ^ 0xFF00;
+  }
+}
diff --git a/test/427-bounds/expected.txt b/test/427-bounds/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/427-bounds/expected.txt
diff --git a/test/427-bounds/info.txt b/test/427-bounds/info.txt
new file mode 100644
index 0000000..8b8b957
--- /dev/null
+++ b/test/427-bounds/info.txt
@@ -0,0 +1,2 @@
+Regression test for the optimizing compiler that used to incorrectly pass
+index and/or length to the pThrowArrayBounds entrypoint.
diff --git a/test/427-bounds/src/Main.java b/test/427-bounds/src/Main.java
new file mode 100644
index 0000000..a2d84d2
--- /dev/null
+++ b/test/427-bounds/src/Main.java
@@ -0,0 +1,51 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    Exception exception = null;
+    try {
+      $opt$Throw(new int[1]);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      exception = e;
+    }
+
+    String exceptionMessage = exception.getMessage();
+
+    // Note that it's ART specific to emit the length.
+    if (exceptionMessage.contains("length")) {
+      if (!exceptionMessage.contains("length=1")) {
+        throw new Error("Wrong length in exception message");
+      }
+    }
+
+    // Note that it's ART specific to emit the index.
+    if (exceptionMessage.contains("index")) {
+      if (!exceptionMessage.contains("index=2")) {
+        throw new Error("Wrong index in exception message");
+      }
+    }
+  }
+
+  static void $opt$Throw(int[] array) {
+    // We fetch the length first, to ensure it is in EAX (on x86).
+    // The pThrowArrayBounds entrypoint expects the index in EAX and the
+    // length in ECX, and the optimizing compiler used to write to EAX
+    // before putting the length in ECX.
+    int length = array.length;
+    array[2] = 42;
+  }
+}
diff --git a/test/428-optimizing-arith-rem/expected.txt b/test/428-optimizing-arith-rem/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/428-optimizing-arith-rem/expected.txt
diff --git a/test/428-optimizing-arith-rem/info.txt b/test/428-optimizing-arith-rem/info.txt
new file mode 100644
index 0000000..3e37ffe
--- /dev/null
+++ b/test/428-optimizing-arith-rem/info.txt
@@ -0,0 +1 @@
+Tests for modulo (rem) operation.
diff --git a/test/428-optimizing-arith-rem/src/Main.java b/test/428-optimizing-arith-rem/src/Main.java
new file mode 100644
index 0000000..3f77318
--- /dev/null
+++ b/test/428-optimizing-arith-rem/src/Main.java
@@ -0,0 +1,157 @@
+/*
+ * 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 {
+
+  public static void main(String[] args) {
+    remInt();
+    remLong();
+  }
+
+  private static void remInt() {
+    expectEquals(2, $opt$RemConst(6));
+    expectEquals(2, $opt$Rem(6, 4));
+    expectEquals(2, $opt$Rem(6, -4));
+    expectEquals(0, $opt$Rem(6, 3));
+    expectEquals(0, $opt$Rem(6, -3));
+    expectEquals(0, $opt$Rem(6, 1));
+    expectEquals(0, $opt$Rem(6, -1));
+    expectEquals(-1, $opt$Rem(-7, 3));
+    expectEquals(-1, $opt$Rem(-7, -3));
+    expectEquals(0, $opt$Rem(6, 6));
+    expectEquals(0, $opt$Rem(-6, -6));
+    expectEquals(7, $opt$Rem(7, 9));
+    expectEquals(7, $opt$Rem(7, -9));
+    expectEquals(-7, $opt$Rem(-7, 9));
+    expectEquals(-7, $opt$Rem(-7, -9));
+
+    expectEquals(0, $opt$Rem(Integer.MAX_VALUE, 1));
+    expectEquals(0, $opt$Rem(Integer.MAX_VALUE, -1));
+    expectEquals(0, $opt$Rem(Integer.MIN_VALUE, 1));
+    expectEquals(0, $opt$Rem(Integer.MIN_VALUE, -1)); // no overflow
+    expectEquals(-1, $opt$Rem(Integer.MIN_VALUE, Integer.MAX_VALUE));
+    expectEquals(Integer.MAX_VALUE, $opt$Rem(Integer.MAX_VALUE, Integer.MIN_VALUE));
+
+    expectEquals(0, $opt$Rem(0, 7));
+    expectEquals(0, $opt$Rem(0, Integer.MAX_VALUE));
+    expectEquals(0, $opt$Rem(0, Integer.MIN_VALUE));
+
+    expectDivisionByZero(0);
+    expectDivisionByZero(1);
+    expectDivisionByZero(5);
+    expectDivisionByZero(Integer.MAX_VALUE);
+    expectDivisionByZero(Integer.MIN_VALUE);
+  }
+
+  private static void remLong() {
+    expectEquals(2L, $opt$RemConst(6L));
+    expectEquals(2L, $opt$Rem(6L, 4L));
+    expectEquals(2L, $opt$Rem(6L, -4L));
+    expectEquals(0L, $opt$Rem(6L, 3L));
+    expectEquals(0L, $opt$Rem(6L, -3L));
+    expectEquals(0L, $opt$Rem(6L, 1L));
+    expectEquals(0L, $opt$Rem(6L, -1L));
+    expectEquals(-1L, $opt$Rem(-7L, 3L));
+    expectEquals(-1L, $opt$Rem(-7L, -3L));
+    expectEquals(0L, $opt$Rem(6L, 6L));
+    expectEquals(0L, $opt$Rem(-6L, -6L));
+    expectEquals(7L, $opt$Rem(7L, 9L));
+    expectEquals(7L, $opt$Rem(7L, -9L));
+    expectEquals(-7L, $opt$Rem(-7L, 9L));
+    expectEquals(-7L, $opt$Rem(-7L, -9L));
+
+    expectEquals(0L, $opt$Rem(Long.MAX_VALUE, 1L));
+    expectEquals(0L, $opt$Rem(Long.MAX_VALUE, -1L));
+    expectEquals(0L, $opt$Rem(Long.MIN_VALUE, 1L));
+    expectEquals(0L, $opt$Rem(Long.MIN_VALUE, -1L)); // no overflow
+    expectEquals(-1L, $opt$Rem(Long.MIN_VALUE, Long.MAX_VALUE));
+    expectEquals(Long.MAX_VALUE, $opt$Rem(Long.MAX_VALUE, Long.MIN_VALUE));
+
+    expectEquals(0L, $opt$Rem(0L, 7L));
+    expectEquals(0L, $opt$Rem(0L, Long.MAX_VALUE));
+    expectEquals(0L, $opt$Rem(0L, Long.MIN_VALUE));
+
+    expectDivisionByZero(0L);
+    expectDivisionByZero(1L);
+    expectDivisionByZero(5L);
+    expectDivisionByZero(Long.MAX_VALUE);
+    expectDivisionByZero(Long.MIN_VALUE);
+  }
+
+  static int $opt$Rem(int a, int b) {
+    return a % b;
+  }
+
+  static int $opt$RemZero(int a) {
+    return a % 0;
+  }
+
+  // Modulo by literals != 0 should not generate checks.
+  static int $opt$RemConst(int a) {
+    return a % 4;
+  }
+
+  static long $opt$RemConst(long a) {
+    return a % 4L;
+  }
+
+  static long $opt$Rem(long a, long b) {
+    return a % b;
+  }
+
+  static long $opt$RemZero(long a) {
+    return a % 0L;
+  }
+
+  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 expectDivisionByZero(int value) {
+    try {
+      $opt$Rem(value, 0);
+      throw new Error("Expected RuntimeException when modulo by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+    try {
+      $opt$RemZero(value);
+      throw new Error("Expected RuntimeException when modulo by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+  }
+
+  public static void expectDivisionByZero(long value) {
+    try {
+      $opt$Rem(value, 0L);
+      throw new Error("Expected RuntimeException when modulo by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+    try {
+      $opt$RemZero(value);
+      throw new Error("Expected RuntimeException when modulo by 0");
+    } catch (java.lang.RuntimeException e) {
+    }
+  }
+
+}
diff --git a/test/429-ssa-builder/expected.txt b/test/429-ssa-builder/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/429-ssa-builder/expected.txt
diff --git a/test/429-ssa-builder/info.txt b/test/429-ssa-builder/info.txt
new file mode 100644
index 0000000..509d00f
--- /dev/null
+++ b/test/429-ssa-builder/info.txt
@@ -0,0 +1,3 @@
+Regression test for the type propagation phase of the optimizing
+compiler, that used to crash when dealing with phi floating-point
+equivalents.
diff --git a/test/429-ssa-builder/src/Main.java b/test/429-ssa-builder/src/Main.java
new file mode 100644
index 0000000..32fcef0
--- /dev/null
+++ b/test/429-ssa-builder/src/Main.java
@@ -0,0 +1,49 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    if (new Main().$opt$TestFloatPhi() != 33.0f) {
+      throw new Error("Unexpected result");
+    }
+  }
+
+  public float $opt$TestFloatPhi() {
+    float a = floatField;
+    float b = 42.0f;
+    if (test1) {
+      // The phi for `a` will be found to be of type float.
+      a = otherFloatField;
+      // The phi for `b` will be found to be of type int (constants in DEX).
+      b = 33.0f;
+    }
+    // Use a different condition to avoid having dx being too clever.
+    if (test2) {
+      // Type propagation now realizes that `b` must be of type float. So
+      // it requests a float equivalent for `b`. Because the phi for `a` is
+      // next to the phi for `b` in the phi list, the compiler used to crash,
+      // assuming that a float phi following a phi *must* be for the same DEX
+      // register.
+      a = b;
+    }
+    return a;
+  }
+
+  float floatField = 4.2f;
+  float otherFloatField = 42.2f;
+  boolean test1 = true;
+  boolean test2 = true;
+}
diff --git a/test/430-live-register-slow-path/expected.txt b/test/430-live-register-slow-path/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/430-live-register-slow-path/expected.txt
diff --git a/test/430-live-register-slow-path/info.txt b/test/430-live-register-slow-path/info.txt
new file mode 100644
index 0000000..6f2af28
--- /dev/null
+++ b/test/430-live-register-slow-path/info.txt
@@ -0,0 +1,2 @@
+Regression test for the linear scan register allocator. It used
+to miscompute the number of live registers at a safepoint.
diff --git a/test/430-live-register-slow-path/src/Main.java b/test/430-live-register-slow-path/src/Main.java
new file mode 100644
index 0000000..b84e647
--- /dev/null
+++ b/test/430-live-register-slow-path/src/Main.java
@@ -0,0 +1,39 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+   $opt$TestSlowPath();
+  }
+
+  public static void $opt$TestSlowPath() {
+    Object[] o = bar();
+    assertEquals(0, o.length);
+    // The slowpath of the instanceof requires the live register
+    // holding `o` to be saved before going into runtime. The linear
+    // scan register allocator used to miscompute the number of
+    // live registers at a safepoint, so the place at which the register
+    // was saved was wrong.
+    doCall(o instanceof Interface[], o);
+  }
+
+  public static void assertEquals(int a, int b) {}
+  public static boolean doCall(boolean val, Object o) { return val; }
+
+  static Object[] bar() { return new Object[0]; }
+
+  static interface Interface {}
+}
diff --git a/test/431-optimizing-arith-shifts/expected.txt b/test/431-optimizing-arith-shifts/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/431-optimizing-arith-shifts/expected.txt
diff --git a/test/431-optimizing-arith-shifts/info.txt b/test/431-optimizing-arith-shifts/info.txt
new file mode 100644
index 0000000..14ff264
--- /dev/null
+++ b/test/431-optimizing-arith-shifts/info.txt
@@ -0,0 +1 @@
+Tests for shift operations.
diff --git a/test/431-optimizing-arith-shifts/src/Main.java b/test/431-optimizing-arith-shifts/src/Main.java
new file mode 100644
index 0000000..d8667c6
--- /dev/null
+++ b/test/431-optimizing-arith-shifts/src/Main.java
@@ -0,0 +1,305 @@
+/*
+ * 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 {
+
+  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 main(String[] args) {
+    shlInt();
+    shlLong();
+    shrInt();
+    shrLong();
+    ushrInt();
+    ushrLong();
+  }
+
+  private static void shlInt() {
+    expectEquals(48, $opt$ShlConst2(12));
+    expectEquals(12, $opt$ShlConst0(12));
+    expectEquals(-48, $opt$Shl(-12, 2));
+    expectEquals(1024, $opt$Shl(32, 5));
+
+    expectEquals(7, $opt$Shl(7, 0));
+    expectEquals(14, $opt$Shl(7, 1));
+    expectEquals(0, $opt$Shl(0, 30));
+
+    expectEquals(1073741824L, $opt$Shl(1, 30));
+    expectEquals(Integer.MIN_VALUE, $opt$Shl(1, 31));  // overflow
+    expectEquals(Integer.MIN_VALUE, $opt$Shl(1073741824, 1));  // overflow
+    expectEquals(1073741824, $opt$Shl(268435456, 2));
+
+   // othe nly 5 lower bits should be used for shifting (& 0x1f).
+    expectEquals(7, $opt$Shl(7, 32));  // 32 & 0x1f = 0
+    expectEquals(14, $opt$Shl(7, 33));  // 33 & 0x1f = 1
+    expectEquals(32, $opt$Shl(1, 101));  // 101 & 0x1f = 5
+
+    expectEquals(Integer.MIN_VALUE, $opt$Shl(1, -1));  // -1 & 0x1f = 31
+    expectEquals(14, $opt$Shl(7, -31));  // -31 & 0x1f = 1
+    expectEquals(7, $opt$Shl(7, -32));  // -32 & 0x1f = 0
+    expectEquals(-536870912, $opt$Shl(7, -3));  // -3 & 0x1f = 29
+
+    expectEquals(Integer.MIN_VALUE, $opt$Shl(7, Integer.MAX_VALUE));
+    expectEquals(7, $opt$Shl(7, Integer.MIN_VALUE));
+  }
+
+  private static void shlLong() {
+    expectEquals(48L, $opt$ShlConst2(12L));
+    expectEquals(12L, $opt$ShlConst0(12L));
+    expectEquals(-48L, $opt$Shl(-12L, 2L));
+    expectEquals(1024L, $opt$Shl(32L, 5L));
+
+    expectEquals(7L, $opt$Shl(7L, 0L));
+    expectEquals(14L, $opt$Shl(7L, 1L));
+    expectEquals(0L, $opt$Shl(0L, 30L));
+
+    expectEquals(1073741824L, $opt$Shl(1L, 30L));
+    expectEquals(2147483648L, $opt$Shl(1L, 31L));
+    expectEquals(2147483648L, $opt$Shl(1073741824L, 1L));
+
+    // Long shifts can use up to 6 lower bits.
+    expectEquals(4294967296L, $opt$Shl(1L, 32L));
+    expectEquals(60129542144L, $opt$Shl(7L, 33L));
+    expectEquals(Long.MIN_VALUE, $opt$Shl(1L, 63L));  // overflow
+
+    // Only the 6 lower bits should be used for shifting (& 0x3f).
+    expectEquals(7L, $opt$Shl(7L, 64L));  // 64 & 0x3f = 0
+    expectEquals(14L, $opt$Shl(7L, 65L));  // 65 & 0x3f = 1
+    expectEquals(137438953472L, $opt$Shl(1L, 101L));  // 101 & 0x3f = 37
+
+    expectEquals(Long.MIN_VALUE, $opt$Shl(1L, -1L));  // -1 & 0x3f = 63
+    expectEquals(14L, $opt$Shl(7L, -63L));  // -63 & 0x3f = 1
+    expectEquals(7L, $opt$Shl(7L, -64L));  // -64 & 0x3f = 0
+    expectEquals(2305843009213693952L, $opt$Shl(1L, -3L));  // -3 & 0x3f = 61
+
+    expectEquals(Long.MIN_VALUE, $opt$Shl(7L, Long.MAX_VALUE));
+    expectEquals(7L, $opt$Shl(7L, Long.MIN_VALUE));
+  }
+
+  private static void shrInt() {
+    expectEquals(3, $opt$ShrConst2(12));
+    expectEquals(12, $opt$ShrConst0(12));
+    expectEquals(-3, $opt$Shr(-12, 2));
+    expectEquals(1, $opt$Shr(32, 5));
+
+    expectEquals(7, $opt$Shr(7, 0));
+    expectEquals(3, $opt$Shr(7, 1));
+    expectEquals(0, $opt$Shr(0, 30));
+    expectEquals(0, $opt$Shr(1, 30));
+    expectEquals(-1, $opt$Shr(-1, 30));
+
+    expectEquals(0, $opt$Shr(Integer.MAX_VALUE, 31));
+    expectEquals(-1, $opt$Shr(Integer.MIN_VALUE, 31));
+
+    // Only the 5 lower bits should be used for shifting (& 0x1f).
+    expectEquals(7, $opt$Shr(7, 32));  // 32 & 0x1f = 0
+    expectEquals(3, $opt$Shr(7, 33));  // 33 & 0x1f = 1
+
+    expectEquals(0, $opt$Shr(1, -1));  // -1 & 0x1f = 31
+    expectEquals(3, $opt$Shr(7, -31));  // -31 & 0x1f = 1
+    expectEquals(7, $opt$Shr(7, -32));  // -32 & 0x1f = 0
+    expectEquals(-4, $opt$Shr(Integer.MIN_VALUE, -3));  // -3 & 0x1f = 29
+
+    expectEquals(0, $opt$Shr(7, Integer.MAX_VALUE));
+    expectEquals(7, $opt$Shr(7, Integer.MIN_VALUE));
+  }
+
+  private static void shrLong() {
+    expectEquals(3L, $opt$ShrConst2(12L));
+    expectEquals(12L, $opt$ShrConst0(12L));
+    expectEquals(-3L, $opt$Shr(-12L, 2L));
+    expectEquals(1, $opt$Shr(32, 5));
+
+    expectEquals(7L, $opt$Shr(7L, 0L));
+    expectEquals(3L, $opt$Shr(7L, 1L));
+    expectEquals(0L, $opt$Shr(0L, 30L));
+    expectEquals(0L, $opt$Shr(1L, 30L));
+    expectEquals(-1L, $opt$Shr(-1L, 30L));
+
+
+    expectEquals(1L, $opt$Shr(1073741824L, 30L));
+    expectEquals(1L, $opt$Shr(2147483648L, 31L));
+    expectEquals(1073741824L, $opt$Shr(2147483648L, 1L));
+
+    // Long shifts can use up to 6 lower bits.
+    expectEquals(1L, $opt$Shr(4294967296L, 32L));
+    expectEquals(7L, $opt$Shr(60129542144L, 33L));
+    expectEquals(0L, $opt$Shr(Long.MAX_VALUE, 63L));
+    expectEquals(-1L, $opt$Shr(Long.MIN_VALUE, 63L));
+
+    // Only the 6 lower bits should be used for shifting (& 0x3f).
+    expectEquals(7L, $opt$Shr(7L, 64L));  // 64 & 0x3f = 0
+    expectEquals(3L, $opt$Shr(7L, 65L));  // 65 & 0x3f = 1
+
+    expectEquals(-1L, $opt$Shr(Long.MIN_VALUE, -1L));  // -1 & 0x3f = 63
+    expectEquals(3L, $opt$Shr(7L, -63L));  // -63 & 0x3f = 1
+    expectEquals(7L, $opt$Shr(7L, -64L));  // -64 & 0x3f = 0
+    expectEquals(1L, $opt$Shr(2305843009213693952L, -3L));  // -3 & 0x3f = 61
+    expectEquals(-4L, $opt$Shr(Integer.MIN_VALUE, -3));  // -3 & 0x1f = 29
+
+    expectEquals(0L, $opt$Shr(7L, Long.MAX_VALUE));
+    expectEquals(7L, $opt$Shr(7L, Long.MIN_VALUE));
+  }
+
+  private static void ushrInt() {
+    expectEquals(3, $opt$UShrConst2(12));
+    expectEquals(12, $opt$UShrConst0(12));
+    expectEquals(1073741821, $opt$UShr(-12, 2));
+    expectEquals(1, $opt$UShr(32, 5));
+
+    expectEquals(7, $opt$UShr(7, 0));
+    expectEquals(3, $opt$UShr(7, 1));
+    expectEquals(0, $opt$UShr(0, 30));
+    expectEquals(0, $opt$UShr(1, 30));
+    expectEquals(3, $opt$UShr(-1, 30));
+
+    expectEquals(0, $opt$UShr(Integer.MAX_VALUE, 31));
+    expectEquals(1, $opt$UShr(Integer.MIN_VALUE, 31));
+
+    // Only the 5 lower bits should be used for shifting (& 0x1f).
+    expectEquals(7, $opt$UShr(7, 32));  // 32 & 0x1f = 0
+    expectEquals(3, $opt$UShr(7, 33));  // 33 & 0x1f = 1
+
+    expectEquals(0, $opt$UShr(1, -1));  // -1 & 0x1f = 31
+    expectEquals(3, $opt$UShr(7, -31));  // -31 & 0x1f = 1
+    expectEquals(7, $opt$UShr(7, -32));  // -32 & 0x1f = 0
+    expectEquals(4, $opt$UShr(Integer.MIN_VALUE, -3));  // -3 & 0x1f = 29
+
+    expectEquals(0, $opt$UShr(7, Integer.MAX_VALUE));
+    expectEquals(7, $opt$UShr(7, Integer.MIN_VALUE));
+  }
+
+  private static void ushrLong() {
+    expectEquals(3L, $opt$UShrConst2(12L));
+    expectEquals(12L, $opt$UShrConst0(12L));
+    expectEquals(4611686018427387901L, $opt$UShr(-12L, 2L));
+    expectEquals(1, $opt$UShr(32, 5));
+
+    expectEquals(7L, $opt$UShr(7L, 0L));
+    expectEquals(3L, $opt$UShr(7L, 1L));
+    expectEquals(0L, $opt$UShr(0L, 30L));
+    expectEquals(0L, $opt$UShr(1L, 30L));
+    expectEquals(17179869183L, $opt$UShr(-1L, 30L));
+
+
+    expectEquals(1L, $opt$UShr(1073741824L, 30L));
+    expectEquals(1L, $opt$UShr(2147483648L, 31L));
+    expectEquals(1073741824L, $opt$UShr(2147483648L, 1L));
+
+    // Long shifts can use use up to 6 lower bits.
+    expectEquals(1L, $opt$UShr(4294967296L, 32L));
+    expectEquals(7L, $opt$UShr(60129542144L, 33L));
+    expectEquals(0L, $opt$UShr(Long.MAX_VALUE, 63L));
+    expectEquals(1L, $opt$UShr(Long.MIN_VALUE, 63L));
+
+    // Only the 6 lower bits should be used for shifting (& 0x3f).
+    expectEquals(7L, $opt$UShr(7L, 64L));  // 64 & 0x3f = 0
+    expectEquals(3L, $opt$UShr(7L, 65L));  // 65 & 0x3f = 1
+
+    expectEquals(1L, $opt$UShr(Long.MIN_VALUE, -1L));  // -1 & 0x3f = 63
+    expectEquals(3L, $opt$UShr(7L, -63L));  // -63 & 0x3f = 1
+    expectEquals(7L, $opt$UShr(7L, -64L));  // -64 & 0x3f = 0
+    expectEquals(1L, $opt$UShr(2305843009213693952L, -3L));  // -3 & 0x3f = 61
+    expectEquals(4L, $opt$UShr(Long.MIN_VALUE, -3L));  // -3 & 0x3f = 61
+
+    expectEquals(0L, $opt$UShr(7L, Long.MAX_VALUE));
+    expectEquals(7L, $opt$UShr(7L, Long.MIN_VALUE));
+  }
+
+  static int $opt$Shl(int a, int b) {
+    return a << b;
+  }
+
+  static long $opt$Shl(long a, long b) {
+    return a << b;
+  }
+
+  static int $opt$Shr(int a, int b) {
+    return a >> b;
+  }
+
+  static long $opt$Shr(long a, long b) {
+    return a >> b;
+  }
+
+  static int $opt$UShr(int a, int b) {
+    return a >>> b;
+  }
+
+  static long $opt$UShr(long a, long b) {
+    return a >>> b;
+  }
+
+  static int $opt$ShlConst2(int a) {
+    return a << 2;
+  }
+
+  static long $opt$ShlConst2(long a) {
+    return a << 2L;
+  }
+
+  static int $opt$ShrConst2(int a) {
+    return a >> 2;
+  }
+
+  static long $opt$ShrConst2(long a) {
+    return a >> 2L;
+  }
+
+  static int $opt$UShrConst2(int a) {
+    return a >>> 2;
+  }
+
+  static long $opt$UShrConst2(long a) {
+    return a >>> 2L;
+  }
+
+    static int $opt$ShlConst0(int a) {
+    return a << 0;
+  }
+
+  static long $opt$ShlConst0(long a) {
+    return a << 0L;
+  }
+
+  static int $opt$ShrConst0(int a) {
+    return a >> 0;
+  }
+
+  static long $opt$ShrConst0(long a) {
+    return a >> 0L;
+  }
+
+  static int $opt$UShrConst0(int a) {
+    return a >>> 0;
+  }
+
+  static long $opt$UShrConst0(long a) {
+    return a >>> 0L;
+  }
+
+}
+
diff --git a/test/431-type-propagation/expected.txt b/test/431-type-propagation/expected.txt
new file mode 100644
index 0000000..ccaf6f8
--- /dev/null
+++ b/test/431-type-propagation/expected.txt
@@ -0,0 +1 @@
+Enter
diff --git a/test/431-type-propagation/info.txt b/test/431-type-propagation/info.txt
new file mode 100644
index 0000000..b895e91
--- /dev/null
+++ b/test/431-type-propagation/info.txt
@@ -0,0 +1,2 @@
+Regression test for the SSA building of the optimizing
+compiler. See comment in smali file.
diff --git a/test/431-type-propagation/smali/TypePropagation.smali b/test/431-type-propagation/smali/TypePropagation.smali
new file mode 100644
index 0000000..817f0c5
--- /dev/null
+++ b/test/431-type-propagation/smali/TypePropagation.smali
@@ -0,0 +1,43 @@
+# 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.
+
+.class public LTypePropagation;
+
+.super Ljava/lang/Object;
+
+.method public static method([I)V
+   .registers 3
+   const/4 v0, 0
+   aget v1, v2, v0
+   add-int v2, v1, v0
+   if-eq v1, v0, :end
+   # Putting a float in v1 will lead to the creation of a phi with one
+   # float input and one integer input. Since the SSA builder trusts
+   # the verifier, it assumes that the integer input must be converted
+   # to float. However, since v0 is not used afterwards, the verifier
+   # hasn't ensured that. Therefore, the compiler must remove
+   # the phi prior to doing type propagation.
+   int-to-float v1, v0
+   :end
+   # Do a call to create an environment that will capture all Dex registers.
+   # This environment is the reason why a phi is created at the join block
+   # of the if.
+   invoke-static {}, LTypePropagation;->emptyMethod()V
+   return-void
+.end method
+
+.method public static emptyMethod()V
+   .registers 0
+   return-void
+.end method
diff --git a/test/431-type-propagation/src/Main.java b/test/431-type-propagation/src/Main.java
new file mode 100644
index 0000000..91dfe10
--- /dev/null
+++ b/test/431-type-propagation/src/Main.java
@@ -0,0 +1,28 @@
+/*
+ * 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.Method;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    System.out.println("Enter");
+    Class<?> c = Class.forName("TypePropagation");
+    Method m = c.getMethod("method", int[].class);
+    int[] array = new int[7];
+    Object[] arguments = { array };
+    m.invoke(null, arguments);
+  }
+}
diff --git a/test/432-optimizing-cmp/expected.txt b/test/432-optimizing-cmp/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/432-optimizing-cmp/expected.txt
diff --git a/test/432-optimizing-cmp/info.txt b/test/432-optimizing-cmp/info.txt
new file mode 100644
index 0000000..fad6cee
--- /dev/null
+++ b/test/432-optimizing-cmp/info.txt
@@ -0,0 +1 @@
+Tests for compare operations.
diff --git a/test/432-optimizing-cmp/smali/cmp.smali b/test/432-optimizing-cmp/smali/cmp.smali
new file mode 100644
index 0000000..470d940
--- /dev/null
+++ b/test/432-optimizing-cmp/smali/cmp.smali
@@ -0,0 +1,33 @@
+.class public LTestCmp;
+
+.super Ljava/lang/Object;
+
+.method public static $opt$CmpLong(JJ)I
+   .registers 5
+   cmp-long v0, v1, v3
+   return v0
+.end method
+
+.method public static $opt$CmpGtFloat(FF)I
+   .registers 3
+   cmpg-float v0, v1, v2
+   return v0
+.end method
+
+.method public static $opt$CmpLtFloat(FF)I
+   .registers 3
+   cmpl-float v0, v1, v2
+   return v0
+.end method
+
+.method public static $opt$CmpGtDouble(DD)I
+   .registers 5
+   cmpg-double v0, v1, v3
+   return v0
+.end method
+
+.method public static $opt$CmpLtDouble(DD)I
+   .registers 5
+   cmpl-double v0, v1, v3
+   return v0
+.end method
diff --git a/test/432-optimizing-cmp/src/Main.java b/test/432-optimizing-cmp/src/Main.java
new file mode 100644
index 0000000..3c7b13f
--- /dev/null
+++ b/test/432-optimizing-cmp/src/Main.java
@@ -0,0 +1,227 @@
+/*
+ * 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.Method;
+
+public class Main {
+
+  public static void main(String[] args) throws Exception {
+    cmpLong();
+    cmpFloat();
+    cmpDouble();
+  }
+
+  private static void cmpLong() throws Exception {
+    expectLt(3L, 5L);
+    expectGt(5L, 3L);
+    expectLt(Long.MIN_VALUE, Long.MAX_VALUE);
+    expectGt(Long.MAX_VALUE, Long.MIN_VALUE);
+
+    expectEquals(0, smaliCmpLong(0L, 0L));
+    expectEquals(0, smaliCmpLong(1L, 1L));
+    expectEquals(-1, smaliCmpLong(1L, 2L));
+    expectEquals(1, smaliCmpLong(2L, 1L));
+    expectEquals(-1, smaliCmpLong(Long.MIN_VALUE, Long.MAX_VALUE));
+    expectEquals(1, smaliCmpLong(Long.MAX_VALUE, Long.MIN_VALUE));
+    expectEquals(0, smaliCmpLong(Long.MIN_VALUE, Long.MIN_VALUE));
+    expectEquals(0, smaliCmpLong(Long.MAX_VALUE, Long.MAX_VALUE));
+  }
+
+  private static void cmpFloat() throws Exception {
+    expectLt(3.1F, 5.1F);
+    expectGt(5.1F, 3.1F);
+    expectLt(Float.MIN_VALUE, Float.MAX_VALUE);
+    expectGt(Float.MAX_VALUE, Float.MIN_VALUE);
+    expectFalse(3.1F, Float.NaN);
+    expectFalse(Float.NaN, 3.1F);
+
+    expectEquals(0, smaliCmpGtFloat(0F, 0F));
+    expectEquals(0, smaliCmpGtFloat(1F, 1F));
+    expectEquals(-1, smaliCmpGtFloat(1.1F, 2.1F));
+    expectEquals(1, smaliCmpGtFloat(2.1F, 1.1F));
+    expectEquals(-1, smaliCmpGtFloat(Float.MIN_VALUE, Float.MAX_VALUE));
+    expectEquals(1, smaliCmpGtFloat(Float.MAX_VALUE, Float.MIN_VALUE));
+    expectEquals(0, smaliCmpGtFloat(Float.MIN_VALUE, Float.MIN_VALUE));
+    expectEquals(0, smaliCmpGtFloat(Float.MAX_VALUE, Float.MAX_VALUE));
+    expectEquals(1, smaliCmpGtFloat(5F, Float.NaN));
+    expectEquals(1, smaliCmpGtFloat(Float.NaN, 5F));
+
+    expectEquals(0, smaliCmpLtFloat(0F, 0F));
+    expectEquals(0, smaliCmpLtFloat(1F, 1F));
+    expectEquals(-1, smaliCmpLtFloat(1.1F, 2.1F));
+    expectEquals(1, smaliCmpLtFloat(2.1F, 1.1F));
+    expectEquals(-1, smaliCmpLtFloat(Float.MIN_VALUE, Float.MAX_VALUE));
+    expectEquals(1, smaliCmpLtFloat(Float.MAX_VALUE, Float.MIN_VALUE));
+    expectEquals(0, smaliCmpLtFloat(Float.MIN_VALUE, Float.MIN_VALUE));
+    expectEquals(0, smaliCmpLtFloat(Float.MAX_VALUE, Float.MAX_VALUE));
+    expectEquals(-1, smaliCmpLtFloat(5F, Float.NaN));
+    expectEquals(-1, smaliCmpLtFloat(Float.NaN, 5F));
+  }
+
+  private static void cmpDouble() throws Exception {
+    expectLt(3.1D, 5.1D);
+    expectGt(5.1D, 3.1D);
+    expectLt(Double.MIN_VALUE, Double.MAX_VALUE);
+    expectGt(Double.MAX_VALUE, Double.MIN_VALUE);
+    expectFalse(3.1D, Double.NaN);
+    expectFalse(Double.NaN, 3.1D);
+
+    expectEquals(0, smaliCmpGtDouble(0D, 0D));
+    expectEquals(0, smaliCmpGtDouble(1D, 1D));
+    expectEquals(-1, smaliCmpGtDouble(1.1D, 2.1D));
+    expectEquals(1, smaliCmpGtDouble(2.1D, 1.1D));
+    expectEquals(-1, smaliCmpGtDouble(Double.MIN_VALUE, Double.MAX_VALUE));
+    expectEquals(1, smaliCmpGtDouble(Double.MAX_VALUE, Double.MIN_VALUE));
+    expectEquals(0, smaliCmpGtDouble(Double.MIN_VALUE, Double.MIN_VALUE));
+    expectEquals(0, smaliCmpGtDouble(Double.MAX_VALUE, Double.MAX_VALUE));
+    expectEquals(1, smaliCmpGtDouble(5D, Double.NaN));
+    expectEquals(1, smaliCmpGtDouble(Double.NaN, 5D));
+
+    expectEquals(0, smaliCmpLtDouble(0D, 0D));
+    expectEquals(0, smaliCmpLtDouble(1D, 1D));
+    expectEquals(-1, smaliCmpLtDouble(1.1D, 2.1D));
+    expectEquals(1, smaliCmpLtDouble(2.1D, 1.1D));
+    expectEquals(-1, smaliCmpLtDouble(Double.MIN_VALUE, Double.MAX_VALUE));
+    expectEquals(1, smaliCmpLtDouble(Double.MAX_VALUE, Double.MIN_VALUE));
+    expectEquals(0, smaliCmpLtDouble(Double.MIN_VALUE, Double.MIN_VALUE));
+    expectEquals(0, smaliCmpLtDouble(Double.MAX_VALUE, Double.MAX_VALUE));
+    expectEquals(-1, smaliCmpLtDouble(5D, Double.NaN));
+    expectEquals(-1, smaliCmpLtDouble(Float.NaN, 5D));
+  }
+
+ static boolean $opt$lt(long a, long b) {
+    return a < b;
+  }
+
+  static boolean $opt$lt(float a, float b) {
+    return a < b;
+  }
+
+  static boolean $opt$lt(double a, double b) {
+    return a < b;
+  }
+
+  static boolean $opt$gt(long a, long b) {
+    return a > b;
+  }
+
+  static boolean $opt$gt(float a, float b) {
+    return a > b;
+  }
+
+  static boolean $opt$gt(double a, double b) {
+    return a > b;
+  }
+
+  // Wrappers around methods located in file cmp.smali.
+
+  private static int smaliCmpLong(long a, long b) throws Exception {
+    Class<?> c = Class.forName("TestCmp");
+    Method m = c.getMethod("$opt$CmpLong", long.class, long.class);
+    int result = (Integer)m.invoke(null, a, b);
+    return result;
+  }
+
+  private static int smaliCmpGtFloat(float a, float b) throws Exception {
+    Class<?> c = Class.forName("TestCmp");
+    Method m = c.getMethod("$opt$CmpGtFloat", float.class, float.class);
+    int result = (Integer)m.invoke(null, a, b);
+    return result;
+  }
+
+  private static int smaliCmpLtFloat(float a, float b) throws Exception {
+    Class<?> c = Class.forName("TestCmp");
+    Method m = c.getMethod("$opt$CmpLtFloat", float.class, float.class);
+    int result = (Integer)m.invoke(null, a, b);
+    return result;
+  }
+
+  private static int smaliCmpGtDouble(double a, double b) throws Exception {
+    Class<?> c = Class.forName("TestCmp");
+    Method m = c.getMethod("$opt$CmpGtDouble", double.class, double.class);
+    int result = (Integer)m.invoke(null, a, b);
+    return result;
+  }
+
+  private static int smaliCmpLtDouble(double a, double b) throws Exception {
+    Class<?> c = Class.forName("TestCmp");
+    Method m = c.getMethod("$opt$CmpLtDouble", double.class, double.class);
+    int result = (Integer)m.invoke(null, a, b);
+    return result;
+  }
+
+    public static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectLt(long a, long b) {
+    if (!$opt$lt(a, b)) {
+      throw new Error("Expected: " + a + " < " + b);
+    }
+  }
+
+  public static void expectGt(long a, long b) {
+    if (!$opt$gt(a, b)) {
+      throw new Error("Expected: " + a + " > " + b);
+    }
+  }
+
+  public static void expectLt(float a, float b) {
+    if (!$opt$lt(a, b)) {
+      throw new Error("Expected: " + a + " < " + b);
+    }
+  }
+
+  public static void expectGt(float a, float b) {
+    if (!$opt$gt(a, b)) {
+      throw new Error("Expected: " + a + " > " + b);
+    }
+  }
+
+  public static void expectFalse(float a, float b) {
+    if ($opt$lt(a, b)) {
+      throw new Error("Not expecting: " + a + " < " + b);
+    }
+    if ($opt$gt(a, b)) {
+      throw new Error("Not expecting: " + a + " > " + b);
+    }
+  }
+
+  public static void expectLt(double a, double b) {
+    if (!$opt$lt(a, b)) {
+      throw new Error("Expected: " + a + " < " + b);
+    }
+  }
+
+  public static void expectGt(double a, double b) {
+    if (!$opt$gt(a, b)) {
+      throw new Error("Expected: " + a + " > " + b);
+    }
+  }
+
+  public static void expectFalse(double a, double b) {
+    if ($opt$lt(a, b)) {
+      throw new Error("Not expecting: " + a + " < " + b);
+    }
+    if ($opt$gt(a, b)) {
+      throw new Error("Not expecting: " + a + " > " + b);
+    }
+  }
+
+}
+
diff --git a/test/433-gvn/expected.txt b/test/433-gvn/expected.txt
new file mode 100644
index 0000000..d81cc07
--- /dev/null
+++ b/test/433-gvn/expected.txt
@@ -0,0 +1 @@
+42
diff --git a/test/433-gvn/info.txt b/test/433-gvn/info.txt
new file mode 100644
index 0000000..bcdab15
--- /dev/null
+++ b/test/433-gvn/info.txt
@@ -0,0 +1,3 @@
+Regression test for the optimizing compiler's GVN, that
+used to not take into account all side effects between
+a dominator and its dominated blocks.
diff --git a/test/433-gvn/src/Main.java b/test/433-gvn/src/Main.java
new file mode 100644
index 0000000..f9cb594
--- /dev/null
+++ b/test/433-gvn/src/Main.java
@@ -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.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    System.out.println(foo());
+  }
+
+  public static int foo() {
+    Main m = new Main();
+    int a = m.field;
+    if (a == 0) {
+      m.field = 42;
+      if (m.test) {
+        a = 3;
+      }
+    }
+    // The compiler used to GVN this field get with the one line 24,
+    // even though the field is updated in the if.
+    return m.field;
+  }
+
+  public int field;
+  public boolean test = true;
+}
diff --git a/test/434-invoke-direct/expected.txt b/test/434-invoke-direct/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/434-invoke-direct/expected.txt
diff --git a/test/434-invoke-direct/info.txt b/test/434-invoke-direct/info.txt
new file mode 100644
index 0000000..eae1ef0
--- /dev/null
+++ b/test/434-invoke-direct/info.txt
@@ -0,0 +1,2 @@
+Tests that IllegalAccessError is thrown when a subclass invokes-direct a
+private method from the super class.
diff --git a/test/434-invoke-direct/smali/invoke.smali b/test/434-invoke-direct/smali/invoke.smali
new file mode 100644
index 0000000..b3cdd1e
--- /dev/null
+++ b/test/434-invoke-direct/smali/invoke.smali
@@ -0,0 +1,30 @@
+#
+# 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.
+
+.class public LInvokeDirect;
+.super LInvokeDirectSuper;
+
+.method public constructor <init>()V
+      .registers 2
+       invoke-direct {v1}, LInvokeDirectSuper;-><init>()V
+       return-void
+.end method
+
+.method public run()I
+       .registers 3
+       invoke-super {v2}, LInvokeDirectSuper;->privateMethod()I
+       move-result v0
+       return v0
+.end method
diff --git a/test/434-invoke-direct/src/InvokeDirectSuper.java b/test/434-invoke-direct/src/InvokeDirectSuper.java
new file mode 100644
index 0000000..c80a18b
--- /dev/null
+++ b/test/434-invoke-direct/src/InvokeDirectSuper.java
@@ -0,0 +1,23 @@
+/*
+ * 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 InvokeDirectSuper {
+  public int val;
+
+  private int privateMethod() {
+    return val;
+  }
+}
diff --git a/test/434-invoke-direct/src/Main.java b/test/434-invoke-direct/src/Main.java
new file mode 100644
index 0000000..c363e1a
--- /dev/null
+++ b/test/434-invoke-direct/src/Main.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+public class Main {
+
+  public static void main(String[] args) throws Throwable {
+    $opt$InvokeDirect();
+  }
+
+  private static void $opt$InvokeDirect() throws Throwable {
+    try {
+      Class<?> c = Class.forName("InvokeDirect");
+      Method m = c.getMethod("run");
+      m.invoke(c.newInstance());
+      throw new RuntimeException("Failed to throw IllegalAccessError");
+    } catch (InvocationTargetException e) {
+      if (!(e.getCause() instanceof IllegalAccessError)) {
+        throw new RuntimeException("Failed to throw IllegalAccessError");
+      }
+    }
+  }
+
+}
+
diff --git a/test/434-shifter-operand/expected.txt b/test/434-shifter-operand/expected.txt
new file mode 100644
index 0000000..52289c6
--- /dev/null
+++ b/test/434-shifter-operand/expected.txt
@@ -0,0 +1,3 @@
+false
+false
+true
diff --git a/test/434-shifter-operand/info.txt b/test/434-shifter-operand/info.txt
new file mode 100644
index 0000000..1ec9adc
--- /dev/null
+++ b/test/434-shifter-operand/info.txt
@@ -0,0 +1,2 @@
+Regression test for the arm backend of the optimizing
+compiler, that used to misuse ShifterOperand::CanHold.
diff --git a/test/434-shifter-operand/src/Main.java b/test/434-shifter-operand/src/Main.java
new file mode 100644
index 0000000..4d188eb
--- /dev/null
+++ b/test/434-shifter-operand/src/Main.java
@@ -0,0 +1,27 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    System.out.println(foo(42));
+    System.out.println(foo(0xffffffff));
+    System.out.println(foo(0xf0000000));
+  }
+
+  public static boolean foo(int a) {
+    return a < 0xf000000b;
+  }
+}
diff --git a/test/435-new-instance/expected.txt b/test/435-new-instance/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/435-new-instance/expected.txt
diff --git a/test/435-new-instance/info.txt b/test/435-new-instance/info.txt
new file mode 100644
index 0000000..3f30c1b
--- /dev/null
+++ b/test/435-new-instance/info.txt
@@ -0,0 +1,7 @@
+Tests that new-instance throws:
+- InstantiationError on interfaces and abstract classes
+- IllegalAccessError on inaccessible classes
+- NoClassDefFoundError on unknown classes
+
+This also verifies that we don't remove dead (code) new-instances which may
+throw.
diff --git a/test/435-new-instance/smali/instance.smali b/test/435-new-instance/smali/instance.smali
new file mode 100644
index 0000000..2189498
--- /dev/null
+++ b/test/435-new-instance/smali/instance.smali
@@ -0,0 +1,55 @@
+#
+# 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.
+
+.class public LNewInstance;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+      .registers 1
+       invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+       return-void
+.end method
+
+.method public newInstanceInterface()Ljava/lang/Object;
+      .registers 5
+      new-instance v1, LTestInterface;
+      # invoke-direct {v3}, LTestInterface;-><init>()V
+      # intentionally return v4 ("this")
+      return-object v4
+.end method
+
+.method public newInstanceClass()Ljava/lang/Object;
+      .registers 5
+      new-instance v1, LTestClass;
+      # invoke-direct {v3}, LTestClass;-><init>()V
+      # intentionally return v4 ("this")
+      return-object v4
+.end method
+
+.method public newInstancePrivateClass()Ljava/lang/Object;
+      .registers 5
+      new-instance v1, Lpkg/ProtectedClass;
+      # invoke-direct {v3}, Lpck/ProtectedClass;-><init>()V
+      # intentionally return v4 ("this")
+      return-object v4
+.end method
+
+.method public newInstanceUnknownClass()Ljava/lang/Object;
+      .registers 5
+      new-instance v1, LUnknownClass;
+      # invoke-direct {v3}, LUnknownClass;-><init>()V
+      # intentionally return v4 ("this")
+      return-object v4
+.end method
diff --git a/test/435-new-instance/src/Main.java b/test/435-new-instance/src/Main.java
new file mode 100644
index 0000000..b5431ad
--- /dev/null
+++ b/test/435-new-instance/src/Main.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+public class Main {
+
+  public static void main(String[] args) throws Throwable {
+    // Attempt to instantiate an interface.
+    $opt$NewInstance("newInstanceInterface", InstantiationError.class.getCanonicalName());
+    // Attempt to instantiate an abstract class.
+    $opt$NewInstance("newInstanceClass", InstantiationError.class.getCanonicalName());
+    // Attempt to instantiate an interface.
+    $opt$NewInstance("newInstancePrivateClass", IllegalAccessError.class.getCanonicalName());
+    // Attempt to instantiate an abstract class.
+    $opt$NewInstance("newInstanceUnknownClass", NoClassDefFoundError.class.getCanonicalName());
+  }
+
+  private static void $opt$NewInstance(String method, String errorName) throws Throwable {
+    try {
+      Class<?> c = Class.forName("NewInstance");
+      Method m = c.getMethod(method);
+      m.invoke(c.newInstance());
+      throw new RuntimeException("Failed to throw " + errorName);
+    } catch (InvocationTargetException e) {
+      if (!e.getCause().getClass().getCanonicalName().equals(errorName)) {
+        throw new RuntimeException("Failed to throw " + errorName
+            + ". Threw: " + e.getCause());
+      }
+    }
+  }
+}
diff --git a/test/435-new-instance/src/TestClass.java b/test/435-new-instance/src/TestClass.java
new file mode 100644
index 0000000..15b0a0d
--- /dev/null
+++ b/test/435-new-instance/src/TestClass.java
@@ -0,0 +1,21 @@
+/*
+ * 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 abstract class TestClass {
+  // Bogus fields to satisfy dex merger. See b/18051191
+  public int val;
+  public void method() {};
+}
diff --git a/test/435-new-instance/src/TestInterface.java b/test/435-new-instance/src/TestInterface.java
new file mode 100644
index 0000000..db6f3e0
--- /dev/null
+++ b/test/435-new-instance/src/TestInterface.java
@@ -0,0 +1,19 @@
+/*
+ * 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 interface TestInterface {
+  public void method();
+}
diff --git a/test/435-new-instance/src/pkg/ProtectedClass.java b/test/435-new-instance/src/pkg/ProtectedClass.java
new file mode 100644
index 0000000..b262155
--- /dev/null
+++ b/test/435-new-instance/src/pkg/ProtectedClass.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package pkg;
+
+class ProtectedClass {
+}
diff --git a/test/435-try-finally-without-catch/expected.txt b/test/435-try-finally-without-catch/expected.txt
new file mode 100644
index 0000000..8a67802
--- /dev/null
+++ b/test/435-try-finally-without-catch/expected.txt
@@ -0,0 +1,3 @@
+In finally
+In finally
+In finally
diff --git a/test/435-try-finally-without-catch/info.txt b/test/435-try-finally-without-catch/info.txt
new file mode 100644
index 0000000..46217c5
--- /dev/null
+++ b/test/435-try-finally-without-catch/info.txt
@@ -0,0 +1,26 @@
+Exercise a method containing a `try' statement with several
+instructions with a `finally' clause but without any `catch' block,
+enclosed in a loop.
+
+When dx processes an integer division (or modulo) enclosing a `try'
+block and whose result is assigned to a local value, it is smart
+enough not to emit a `div-int' (or `rem-int') instruction when the
+divisor is non-null, as it wouldn't be used.  However, dx is not
+that clever regarding exception handling: if the divisor is known to
+be non-null at compile-time (as is the case in this test), it will
+still emit a block with the exception catching and rethrowing
+mechanism, even if it is not used.
+
+This used to be a problem for a `try' block followed by a `finally'
+clause but with no `catch' block: in that case, the generated Dex code
+item would list zero catch block for this method (see
+art::CodeItem::tries_size_) and the optimizing compiler would have no
+clue that it contains a `try' statement, which it cannot optimize
+(yet).  With no hint that this method might contain one (or several)
+special block(s) related to `catch'-less `try' statement(s), the
+optimizing compiler considered this (these) as dead block(s) and
+improperly tried to remove its (their) instructions, sometimes
+removing instructions used by others instructions, thus triggering
+assertions.  The optimizing compiler was thus adjusted to remove these
+instructions in a proper fashion, by removing them as users first, and
+then by suppressing them for good.
diff --git a/test/435-try-finally-without-catch/src/Main.java b/test/435-try-finally-without-catch/src/Main.java
new file mode 100644
index 0000000..3c29ce8
--- /dev/null
+++ b/test/435-try-finally-without-catch/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 {
+
+  public static void main(String[] args){
+    foo();
+  }
+
+  // Reduced test case inspired by constantPropagationTest() from
+  // test/083-compiler-regressions.
+  static void foo() {
+    int a = 0;
+    int b = 1;
+
+    for (int i = 0; i < 3; i++) {
+      try {
+        a = 1;
+        // Would throw an ArithmeticException if b were null (hence
+        // the enclosing `try' statement).
+        int c = a % b;
+      }
+      finally {
+        System.out.println("In finally");
+      }
+    }
+  }
+}
diff --git a/test/436-rem-float/expected.txt b/test/436-rem-float/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/436-rem-float/expected.txt
diff --git a/test/436-rem-float/info.txt b/test/436-rem-float/info.txt
new file mode 100644
index 0000000..b023f59
--- /dev/null
+++ b/test/436-rem-float/info.txt
@@ -0,0 +1 @@
+Tests for floating point modulo (rem) operation.
diff --git a/test/436-rem-float/src/Main.java b/test/436-rem-float/src/Main.java
new file mode 100644
index 0000000..cc6341a
--- /dev/null
+++ b/test/436-rem-float/src/Main.java
@@ -0,0 +1,264 @@
+/*
+ * 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 {
+
+  public static void main(String[] args) {
+    remFloat();
+    remDouble();
+  }
+
+  private static void remFloat() {
+    expectApproxEquals(1.98F, $opt$Rem(1.98F, 2F));
+    expectApproxEquals(0F, $opt$Rem(2F, 0.5F));
+    expectApproxEquals(0.09999F, $opt$Rem(1.0F, 0.1F));
+    expectApproxEquals(1.9F, $opt$Rem(6.5F, 2.3F));
+    expectApproxEquals(0.48F, $opt$Rem(1.98F, 1.5F));
+    expectApproxEquals(0.9999F, $opt$Rem(0.9999F, 1.222F));
+    expectApproxEquals(0.9999F, $opt$Rem(0.9999F, 1.0001F));
+    expectApproxEquals(-1.98F, $opt$Rem(-1.98F, 2F));
+    expectApproxEquals(-0F, $opt$Rem(-2F, 0.5F));
+    expectApproxEquals(-0.09999F, $opt$Rem(-1.0F, 0.1F));
+    expectApproxEquals(-1.9F, $opt$Rem(-6.5F, 2.3F));
+    expectApproxEquals(-0.48F, $opt$Rem(-1.98F, 1.5F));
+    expectApproxEquals(-0.9999F, $opt$Rem(-0.9999F, 1.222F));
+    expectApproxEquals(-0.9999F, $opt$Rem(-0.9999F, 1.0001F));
+    expectApproxEquals(1.98F, $opt$Rem(1.98F, -2F));
+    expectApproxEquals(0F, $opt$Rem(2F, -0.5F));
+    expectApproxEquals(0.09999F, $opt$Rem(1.0F, -0.1F));
+    expectApproxEquals(1.9F, $opt$Rem(6.5F, -2.3F));
+    expectApproxEquals(0.48F, $opt$Rem(1.98F, -1.5F));
+    expectApproxEquals(0.9999F, $opt$Rem(0.9999F, -1.222F));
+    expectApproxEquals(0.9999F, $opt$Rem(0.9999F, -1.0001F));
+    expectApproxEquals(-1.98F, $opt$Rem(-1.98F, -2F));
+    expectApproxEquals(-0F, $opt$Rem(-2F, -0.5F));
+    expectApproxEquals(-0.09999F, $opt$Rem(-1.0F, -0.1F));
+    expectApproxEquals(-1.9F, $opt$Rem(-6.5F, -2.3F));
+    expectApproxEquals(-0.48F, $opt$Rem(-1.98F, -1.5F));
+    expectApproxEquals(-0.9999F, $opt$Rem(-0.9999F, -1.222F));
+    expectApproxEquals(-0.9999F, $opt$Rem(-0.9999F, -1.0001F));
+
+    expectApproxEquals(1.68267e-18F, $opt$Rem(61615.2F, -2.48699e-17F));
+    expectApproxEquals(-8.63819e-09F, $opt$Rem(-1.73479e+14F, 3.11154e-08F));
+    expectApproxEquals(1.10911e-12F, $opt$Rem(338122F, 4.57572e-12F));
+
+    expectApproxEquals(2F, $opt$RemConst(6F));
+    expectApproxEquals(2F, $opt$Rem(5.1F, 3.1F));
+    expectApproxEquals(2.1F, $opt$Rem(5.1F, 3F));
+    expectApproxEquals(-2F, $opt$Rem(-5.1F, 3.1F));
+    expectApproxEquals(-2.1F, $opt$Rem(-5.1F, -3F));
+    expectApproxEquals(2F, $opt$Rem(6F, 4F));
+    expectApproxEquals(2F, $opt$Rem(6F, -4F));
+    expectApproxEquals(0F, $opt$Rem(6F, 3F));
+    expectApproxEquals(0F, $opt$Rem(6F, -3F));
+    expectApproxEquals(0F, $opt$Rem(6F, 1F));
+    expectApproxEquals(0F, $opt$Rem(6F, -1F));
+    expectApproxEquals(-1F, $opt$Rem(-7F, 3F));
+    expectApproxEquals(-1F, $opt$Rem(-7F, -3F));
+    expectApproxEquals(0F, $opt$Rem(6F, 6F));
+    expectApproxEquals(0F, $opt$Rem(-6F, -6F));
+    expectApproxEquals(7F, $opt$Rem(7F, 9F));
+    expectApproxEquals(7F, $opt$Rem(7F, -9F));
+    expectApproxEquals(-7F, $opt$Rem(-7F, 9F));
+    expectApproxEquals(-7F, $opt$Rem(-7F, -9F));
+    expectApproxEquals(0F, $opt$Rem(Float.MAX_VALUE, 1F));
+    expectApproxEquals(0F, $opt$Rem(Float.MAX_VALUE, -1F));
+    expectApproxEquals(0F, $opt$Rem(Float.MIN_VALUE, 1F));
+    expectApproxEquals(0F, $opt$Rem(Float.MIN_VALUE, -1F));
+    expectApproxEquals(0F, $opt$Rem(0F, 7F));
+    expectApproxEquals(0F, $opt$Rem(0F, Float.MAX_VALUE));
+    expectApproxEquals(0F, $opt$Rem(0F, Float.MIN_VALUE));
+    expectApproxEquals(0F, $opt$Rem(0F, Float.POSITIVE_INFINITY));
+    expectApproxEquals(0F, $opt$Rem(0F, Float.NEGATIVE_INFINITY));
+    expectApproxEquals(4F, $opt$Rem(4F, Float.POSITIVE_INFINITY));
+    expectApproxEquals(4F, $opt$Rem(4F, Float.NEGATIVE_INFINITY));
+    expectApproxEquals(-4F, $opt$Rem(-4F, Float.POSITIVE_INFINITY));
+    expectApproxEquals(-4F, $opt$Rem(-4F, Float.NEGATIVE_INFINITY));
+    expectApproxEquals(0F, $opt$Rem(Float.MIN_NORMAL, Float.MIN_VALUE));
+    expectApproxEquals(0F, $opt$Rem(Float.MIN_NORMAL, Float.MIN_NORMAL));
+    expectApproxEquals(0F, $opt$Rem(Float.MIN_VALUE, Float.MIN_VALUE));
+    expectApproxEquals(0F, $opt$Rem(Float.MAX_VALUE, Float.MIN_VALUE));
+    expectApproxEquals(0F, $opt$Rem(Float.MAX_VALUE, Float.MAX_VALUE));
+    expectApproxEquals(0F, $opt$Rem(Float.MAX_VALUE, Float.MIN_NORMAL));
+    expectApproxEquals(Float.MIN_NORMAL, $opt$Rem(Float.MIN_NORMAL, Float.MAX_VALUE));
+    expectApproxEquals(Float.MIN_NORMAL, $opt$Rem(Float.MIN_NORMAL, Float.NEGATIVE_INFINITY));
+    expectApproxEquals(Float.MIN_NORMAL, $opt$Rem(Float.MIN_NORMAL, Float.POSITIVE_INFINITY));
+    expectApproxEquals(Float.MIN_VALUE, $opt$Rem(Float.MIN_VALUE, Float.MAX_VALUE));
+    expectApproxEquals(Float.MIN_VALUE, $opt$Rem(Float.MIN_VALUE, Float.MIN_NORMAL));
+    expectApproxEquals(Float.MIN_VALUE, $opt$Rem(Float.MIN_VALUE, Float.NEGATIVE_INFINITY));
+    expectApproxEquals(Float.MIN_VALUE, $opt$Rem(Float.MIN_VALUE, Float.POSITIVE_INFINITY));
+    expectApproxEquals(Float.MAX_VALUE, $opt$Rem(Float.MAX_VALUE, Float.NEGATIVE_INFINITY));
+    expectApproxEquals(Float.MAX_VALUE, $opt$Rem(Float.MAX_VALUE, Float.POSITIVE_INFINITY));
+
+    expectNaN($opt$Rem(Float.NaN, 3F));
+    expectNaN($opt$Rem(3F, Float.NaN));
+    expectNaN($opt$Rem(3F, 0F));
+    expectNaN($opt$Rem(1F, 0F));
+    expectNaN($opt$Rem(-1F, 0F));
+    expectNaN($opt$Rem(Float.NEGATIVE_INFINITY, Float.MIN_VALUE));
+    expectNaN($opt$Rem(Float.NEGATIVE_INFINITY, Float.MAX_VALUE));
+    expectNaN($opt$Rem(Float.NEGATIVE_INFINITY, Float.MIN_NORMAL));
+    expectNaN($opt$Rem(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Rem(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Rem(Float.POSITIVE_INFINITY, Float.MIN_VALUE));
+    expectNaN($opt$Rem(Float.POSITIVE_INFINITY, Float.MAX_VALUE));
+    expectNaN($opt$Rem(Float.POSITIVE_INFINITY, Float.MIN_NORMAL));
+    expectNaN($opt$Rem(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Rem(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+  }
+
+  private static void remDouble() {
+    expectApproxEquals(1.98D, $opt$Rem(1.98D, 2D));
+    expectApproxEquals(0D, $opt$Rem(2D, 0.5D));
+    expectApproxEquals(0.09999D, $opt$Rem(1.0D, 0.1D));
+    expectApproxEquals(1.9D, $opt$Rem(6.5D, 2.3D));
+    expectApproxEquals(0.48D, $opt$Rem(1.98D, 1.5D));
+    expectApproxEquals(0.9999D, $opt$Rem(0.9999D, 1.222D));
+    expectApproxEquals(0.9999D, $opt$Rem(0.9999D, 1.0001D));
+    expectApproxEquals(-1.98D, $opt$Rem(-1.98D, 2D));
+    expectApproxEquals(-0D, $opt$Rem(-2D, 0.5D));
+    expectApproxEquals(-0.09999D, $opt$Rem(-1.0D, 0.1D));
+    expectApproxEquals(-1.9D, $opt$Rem(-6.5D, 2.3D));
+    expectApproxEquals(-0.48D, $opt$Rem(-1.98D, 1.5D));
+    expectApproxEquals(-0.9999D, $opt$Rem(-0.9999D, 1.222D));
+    expectApproxEquals(-0.9999D, $opt$Rem(-0.9999D, 1.0001D));
+    expectApproxEquals(1.98D, $opt$Rem(1.98D, -2D));
+    expectApproxEquals(0D, $opt$Rem(2D, -0.5D));
+    expectApproxEquals(0.09999D, $opt$Rem(1.0D, -0.1D));
+    expectApproxEquals(1.9D, $opt$Rem(6.5D, -2.3D));
+    expectApproxEquals(0.48D, $opt$Rem(1.98D, -1.5D));
+    expectApproxEquals(0.9999D, $opt$Rem(0.9999D, -1.222D));
+    expectApproxEquals(0.9999D, $opt$Rem(0.9999D, -1.0001D));
+    expectApproxEquals(-1.98D, $opt$Rem(-1.98D, -2D));
+    expectApproxEquals(-0D, $opt$Rem(-2D, -0.5D));
+    expectApproxEquals(-0.09999D, $opt$Rem(-1.0D, -0.1D));
+    expectApproxEquals(-1.9D, $opt$Rem(-6.5D, -2.3D));
+    expectApproxEquals(-0.48D, $opt$Rem(-1.98D, -1.5D));
+    expectApproxEquals(-0.9999D, $opt$Rem(-0.9999D, -1.222D));
+    expectApproxEquals(-0.9999D, $opt$Rem(-0.9999D, -1.0001D));
+
+    expectApproxEquals(2D, $opt$RemConst(6D));
+    expectApproxEquals(2D, $opt$Rem(5.1D, 3.1D));
+    expectApproxEquals(2.1D, $opt$Rem(5.1D, 3D));
+    expectApproxEquals(-2D, $opt$Rem(-5.1D, 3.1D));
+    expectApproxEquals(-2.1D, $opt$Rem(-5.1D, -3D));
+    expectApproxEquals(2D, $opt$Rem(6D, 4D));
+    expectApproxEquals(2D, $opt$Rem(6D, -4D));
+    expectApproxEquals(0D, $opt$Rem(6D, 3D));
+    expectApproxEquals(0D, $opt$Rem(6D, -3D));
+    expectApproxEquals(0D, $opt$Rem(6D, 1D));
+    expectApproxEquals(0D, $opt$Rem(6D, -1D));
+    expectApproxEquals(-1D, $opt$Rem(-7D, 3D));
+    expectApproxEquals(-1D, $opt$Rem(-7D, -3D));
+    expectApproxEquals(0D, $opt$Rem(6D, 6D));
+    expectApproxEquals(0D, $opt$Rem(-6D, -6D));
+    expectApproxEquals(7D, $opt$Rem(7D, 9D));
+    expectApproxEquals(7D, $opt$Rem(7D, -9D));
+    expectApproxEquals(-7D, $opt$Rem(-7D, 9D));
+    expectApproxEquals(-7D, $opt$Rem(-7D, -9D));
+    expectApproxEquals(0D, $opt$Rem(Double.MAX_VALUE, 1D));
+    expectApproxEquals(0D, $opt$Rem(Double.MAX_VALUE, -1D));
+    expectApproxEquals(0D, $opt$Rem(Double.MIN_VALUE, 1D));
+    expectApproxEquals(0D, $opt$Rem(Double.MIN_VALUE, -1D));
+    expectApproxEquals(0D, $opt$Rem(0D, 7D));
+    expectApproxEquals(0D, $opt$Rem(0D, Double.MAX_VALUE));
+    expectApproxEquals(0D, $opt$Rem(0D, Double.MIN_VALUE));
+    expectApproxEquals(0D, $opt$Rem(0D, Double.POSITIVE_INFINITY));
+    expectApproxEquals(0D, $opt$Rem(0D, Double.NEGATIVE_INFINITY));
+    expectApproxEquals(4D, $opt$Rem(4D, Double.POSITIVE_INFINITY));
+    expectApproxEquals(4D, $opt$Rem(4D, Double.NEGATIVE_INFINITY));
+    expectApproxEquals(-4D, $opt$Rem(-4D, Double.POSITIVE_INFINITY));
+    expectApproxEquals(-4D, $opt$Rem(-4D, Double.NEGATIVE_INFINITY));
+    expectApproxEquals(0D, $opt$Rem(Double.MIN_NORMAL, Double.MIN_VALUE));
+    expectApproxEquals(0D, $opt$Rem(Double.MIN_NORMAL, Double.MIN_NORMAL));
+    expectApproxEquals(0D, $opt$Rem(Double.MIN_VALUE, Double.MIN_VALUE));
+    expectApproxEquals(0D, $opt$Rem(Double.MAX_VALUE, Double.MIN_VALUE));
+    expectApproxEquals(0D, $opt$Rem(Double.MAX_VALUE, Double.MAX_VALUE));
+    expectApproxEquals(0D, $opt$Rem(Double.MAX_VALUE, Double.MIN_NORMAL));
+    expectApproxEquals(Double.MIN_NORMAL, $opt$Rem(Double.MIN_NORMAL, Double.MAX_VALUE));
+    expectApproxEquals(Double.MIN_NORMAL, $opt$Rem(Double.MIN_NORMAL, Double.NEGATIVE_INFINITY));
+    expectApproxEquals(Double.MIN_NORMAL, $opt$Rem(Double.MIN_NORMAL, Double.POSITIVE_INFINITY));
+    expectApproxEquals(Double.MIN_VALUE, $opt$Rem(Double.MIN_VALUE, Double.MAX_VALUE));
+    expectApproxEquals(Double.MIN_VALUE, $opt$Rem(Double.MIN_VALUE, Double.MIN_NORMAL));
+    expectApproxEquals(Double.MIN_VALUE, $opt$Rem(Double.MIN_VALUE, Double.NEGATIVE_INFINITY));
+    expectApproxEquals(Double.MIN_VALUE, $opt$Rem(Double.MIN_VALUE, Double.POSITIVE_INFINITY));
+    expectApproxEquals(Double.MAX_VALUE, $opt$Rem(Double.MAX_VALUE, Double.NEGATIVE_INFINITY));
+    expectApproxEquals(Double.MAX_VALUE, $opt$Rem(Double.MAX_VALUE, Double.POSITIVE_INFINITY));
+
+    expectNaN($opt$Rem(Double.NaN, 3D));
+    expectNaN($opt$Rem(3D, Double.NaN));
+    expectNaN($opt$Rem(3D, 0D));
+    expectNaN($opt$Rem(1D, 0D));
+    expectNaN($opt$Rem(-1D, 0D));
+    expectNaN($opt$Rem(Double.NEGATIVE_INFINITY, Double.MIN_VALUE));
+    expectNaN($opt$Rem(Double.NEGATIVE_INFINITY, Double.MAX_VALUE));
+    expectNaN($opt$Rem(Double.NEGATIVE_INFINITY, Double.MIN_NORMAL));
+    expectNaN($opt$Rem(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Rem(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+    expectNaN($opt$Rem(Double.POSITIVE_INFINITY, Double.MIN_VALUE));
+    expectNaN($opt$Rem(Double.POSITIVE_INFINITY, Double.MAX_VALUE));
+    expectNaN($opt$Rem(Double.POSITIVE_INFINITY, Double.MIN_NORMAL));
+    expectNaN($opt$Rem(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Rem(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+  }
+
+  static float $opt$Rem(float a, float b) {
+    return a % b;
+  }
+
+ static float $opt$RemConst(float a) {
+    return a % 4F;
+  }
+
+  static double $opt$Rem(double a, double b) {
+    return a % b;
+  }
+
+  static double $opt$RemConst(double a) {
+    return a % 4D;
+  }
+
+  public static void expectApproxEquals(float a, float b) {
+    float maxDelta = 0.00001F;
+    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);
+    }
+  }
+
+}
diff --git a/test/436-shift-constant/expected.txt b/test/436-shift-constant/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/436-shift-constant/expected.txt
diff --git a/test/436-shift-constant/info.txt b/test/436-shift-constant/info.txt
new file mode 100644
index 0000000..dc20646
--- /dev/null
+++ b/test/436-shift-constant/info.txt
@@ -0,0 +1 @@
+Regression tests for shift instructions and constants larger than 8bits.
diff --git a/test/436-shift-constant/src/Main.java b/test/436-shift-constant/src/Main.java
new file mode 100644
index 0000000..e69f64b
--- /dev/null
+++ b/test/436-shift-constant/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    assertEquals(0x80000000, doShiftInt(1));
+    assertEquals(0x8000000000000000L, doShiftLong(1L));
+  }
+
+  public static int doShiftInt(int value) {
+    return value << 0xFFFF;
+  }
+
+  public static long doShiftLong(long value) {
+    return value << 0xFFFF;
+  }
+
+  public static void assertEquals(int a, int b) {
+    if (a != b) {
+      throw new Error("Expected " + a + ", got " + b);
+    }
+  }
+
+  public static void assertEquals(long a, long b) {
+    if (a != b) {
+      throw new Error("Expected " + a + ", got " + b);
+    }
+  }
+}
diff --git a/test/437-inline/expected.txt b/test/437-inline/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/437-inline/expected.txt
diff --git a/test/437-inline/info.txt b/test/437-inline/info.txt
new file mode 100644
index 0000000..6487a21
--- /dev/null
+++ b/test/437-inline/info.txt
@@ -0,0 +1 @@
+Tests inlining in the compiler.
diff --git a/test/437-inline/src/Main.java b/test/437-inline/src/Main.java
new file mode 100644
index 0000000..daabe4e
--- /dev/null
+++ b/test/437-inline/src/Main.java
@@ -0,0 +1,103 @@
+/*
+ * 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 {
+  public static void main(String[] args) {
+    if ($opt$inline$returnInt() != 4) {
+      throw new Error();
+    }
+
+    if ($opt$inline$returnParameter(42) != 42) {
+      throw new Error();
+    }
+
+    if ($opt$inline$returnWide() != 12L) {
+      throw new Error();
+    }
+
+    if ($opt$inline$returnWideParameter(0x100000001L) != 0x100000001L) {
+      throw new Error();
+    }
+
+    if ($opt$inline$returnReferenceParameter(Main.class) != Main.class) {
+      throw new Error();
+    }
+
+    $opt$inline$returnVoid();
+    $opt$inline$returnVoidWithOneParameter(32);
+
+    if ($opt$inline$returnAdd(42, 1) != 43) {
+      throw new Error();
+    }
+
+    if ($opt$inline$returnSub(42, 1) != 41) {
+      throw new Error();
+    }
+
+    // Some architectures used to not be able to allocate registers with
+    // floating point operations. This call is a regression test that we don't
+    // try inlining methods with floats in it on such architectures. The
+    // compiler used to crash after inlining a method it cannot allocate
+    // registers for.
+    tryInlineFloat();
+  }
+
+  public static int tryInlineFloat() {
+    return useFloatMethod();
+  }
+
+  public static float staticFloat = 42.0f;
+
+  public static int useFloatMethod() {
+    return (int)staticFloat;
+  }
+
+  public static int $opt$inline$returnParameter(int a) {
+    return a;
+  }
+
+  public static int $opt$inline$returnAdd(int a, int b) {
+    return a + b;
+  }
+
+  public static int $opt$inline$returnSub(int a, int b) {
+    return a - b;
+  }
+
+  public static int $opt$inline$returnInt() {
+    return 4;
+  }
+
+  public static long $opt$inline$returnWideParameter(long a) {
+    return a;
+  }
+
+  public static long $opt$inline$returnWide() {
+    return 12L;
+  }
+
+  public static Object $opt$inline$returnReferenceParameter(Object o) {
+    return o;
+  }
+
+  public static void $opt$inline$returnVoid() {
+    return;
+  }
+
+  public static void $opt$inline$returnVoidWithOneParameter(int a) {
+    return;
+  }
+}
diff --git a/test/438-volatile/expected.txt b/test/438-volatile/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/438-volatile/expected.txt
diff --git a/test/438-volatile/info.txt b/test/438-volatile/info.txt
new file mode 100644
index 0000000..7a4c81a
--- /dev/null
+++ b/test/438-volatile/info.txt
@@ -0,0 +1 @@
+Tests basic operations (set/get) on volatiles.
diff --git a/test/438-volatile/src/Main.java b/test/438-volatile/src/Main.java
new file mode 100644
index 0000000..a870e4c
--- /dev/null
+++ b/test/438-volatile/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * 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 {
+  static volatile long long_volatile;
+  static volatile double double_volatile;
+
+  public static void main(String[] args) {
+    checkVolatileUpdate(0L);
+    checkVolatileUpdate(Long.MAX_VALUE);
+    checkVolatileUpdate(Long.MIN_VALUE);
+
+    checkVolatileUpdate(0.0);
+    checkVolatileUpdate(Double.MAX_VALUE);
+    checkVolatileUpdate(-Double.MAX_VALUE);
+  }
+
+  public static long $opt$update(long a) {
+     long_volatile = a;
+     return long_volatile;
+  }
+
+  public static double $opt$update(double a) {
+     double_volatile = a;
+     return double_volatile;
+  }
+
+  public static void checkVolatileUpdate(long value) {
+    if (value != $opt$update(value)) {
+      throw new RuntimeException("Volatile update failed for long:" + value);
+    }
+  }
+
+  public static void checkVolatileUpdate(double value) {
+    if (value != $opt$update(value)) {
+      throw new RuntimeException("Volatile update failed for double:" + value);
+    }
+  }
+
+}
diff --git a/test/439-npe/expected.txt b/test/439-npe/expected.txt
new file mode 100644
index 0000000..271d40d
--- /dev/null
+++ b/test/439-npe/expected.txt
@@ -0,0 +1,18 @@
+$opt$setObjectField
+$opt$setIntField
+$opt$setFloatField
+$opt$setLongField
+$opt$setDoubleField
+$opt$setByteField
+$opt$setBooleanField
+$opt$setCharField
+$opt$setShortField
+$opt$getObjectField
+$opt$getIntField
+$opt$getFloatField
+$opt$getLongField
+$opt$getDoubleField
+$opt$getByteField
+$opt$getBooleanField
+$opt$getCharField
+$opt$getShortField
diff --git a/test/439-npe/info.txt b/test/439-npe/info.txt
new file mode 100644
index 0000000..d15ab2c
--- /dev/null
+++ b/test/439-npe/info.txt
@@ -0,0 +1,2 @@
+More tests for NullPointerExceptions to complement 122-npe.
+They check set/get to volatile fields.
diff --git a/test/439-npe/src/Main.java b/test/439-npe/src/Main.java
new file mode 100644
index 0000000..40c2645
--- /dev/null
+++ b/test/439-npe/src/Main.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015 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 volatile Object objectField;
+  private volatile int intField;
+  private volatile float floatField;
+  private volatile long longField;
+  private volatile double doubleField;
+  private volatile byte byteField;
+  private volatile boolean booleanField;
+  private volatile char charField;
+  private volatile short shortField;
+
+  public static void $opt$setObjectField(Main m) {
+    m.objectField = null;
+  }
+
+  public static void $opt$setIntField(Main m) {
+    m.intField = 0;
+  }
+
+  public static void $opt$setFloatField(Main m) {
+    m.floatField = 0;
+  }
+
+  public static void $opt$setLongField(Main m) {
+    m.longField = 0;
+  }
+
+  public static void $opt$setDoubleField(Main m) {
+    m.doubleField = 0;
+  }
+
+  public static void $opt$setByteField(Main m) {
+    m.byteField = 0;
+  }
+
+  public static void $opt$setBooleanField(Main m) {
+    m.booleanField = false;
+  }
+
+  public static void $opt$setCharField(Main m) {
+    m.charField = 0;
+  }
+
+  public static void $opt$setShortField(Main m) {
+    m.shortField = 0;
+  }
+
+  public static Object $opt$getObjectField(Main m) {
+    return m.objectField;
+  }
+
+  public static int $opt$getIntField(Main m) {
+    return m.intField;
+  }
+
+  public static float $opt$getFloatField(Main m) {
+    return m.floatField;
+  }
+
+  public static long $opt$getLongField(Main m) {
+    return m.longField;
+  }
+
+  public static double $opt$getDoubleField(Main m) {
+    return m.doubleField;
+  }
+
+  public static byte $opt$getByteField(Main m) {
+    return m.byteField;
+  }
+
+  public static boolean $opt$getBooleanField(Main m) {
+    return m.booleanField;
+  }
+
+  public static char $opt$getCharField(Main m) {
+    return m.charField;
+  }
+
+  public static short $opt$getShortField(Main m) {
+    return m.shortField;
+  }
+
+  public static void main(String[] args) {
+    int methodLine = 30;
+    int thisLine = 103;
+    try {
+      $opt$setObjectField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 2, methodLine, "$opt$setObjectField");
+    }
+    try {
+      $opt$setIntField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setIntField");
+    }
+    try {
+      $opt$setFloatField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setFloatField");
+    }
+    try {
+      $opt$setLongField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setLongField");
+    }
+    try {
+      $opt$setDoubleField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setDoubleField");
+    }
+    try {
+      $opt$setByteField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setByteField");
+    }
+    try {
+      $opt$setBooleanField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setBooleanField");
+    }
+    try {
+      $opt$setCharField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setCharField");
+    }
+    try {
+      $opt$setShortField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$setShortField");
+    }
+    try {
+      $opt$getObjectField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getObjectField");
+    }
+    try {
+      $opt$getIntField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getIntField");
+    }
+    try {
+      $opt$getFloatField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getFloatField");
+    }
+    try {
+      $opt$getLongField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getLongField");
+    }
+    try {
+      $opt$getDoubleField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getDoubleField");
+    }
+    try {
+      $opt$getByteField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getByteField");
+    }
+    try {
+      $opt$getBooleanField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getBooleanField");
+    }
+    try {
+      $opt$getCharField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getCharField");
+    }
+    try {
+      $opt$getShortField(null);
+      throw new RuntimeException("Failed to throw NullPointerException.");
+    } catch (NullPointerException npe) {
+      check(npe, thisLine += 6, methodLine += 4, "$opt$getShortField");
+    }
+  }
+
+  static void check(NullPointerException npe, int mainLine, int medthodLine, String methodName) {
+    System.out.println(methodName);
+    StackTraceElement[] trace = npe.getStackTrace();
+    checkElement(trace[0], "Main", methodName, "Main.java", medthodLine);
+    checkElement(trace[1], "Main", "main", "Main.java", mainLine);
+  }
+
+  static void checkElement(StackTraceElement element,
+                           String declaringClass, String methodName,
+                           String fileName, int lineNumber) {
+    assertEquals(declaringClass, element.getClassName());
+    assertEquals(methodName, element.getMethodName());
+    assertEquals(fileName, element.getFileName());
+    assertEquals(lineNumber, element.getLineNumber());
+  }
+
+  static void assertEquals(Object expected, Object actual) {
+    if (!expected.equals(actual)) {
+      String msg = "Expected \"" + expected + "\" but got \"" + actual + "\"";
+      throw new AssertionError(msg);
+    }
+  }
+
+  static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+}
diff --git a/test/439-swap-double/expected.txt b/test/439-swap-double/expected.txt
new file mode 100644
index 0000000..019c901
--- /dev/null
+++ b/test/439-swap-double/expected.txt
@@ -0,0 +1,4 @@
+-26.0
+-24.0
+-22.0
+-20.0
diff --git a/test/439-swap-double/info.txt b/test/439-swap-double/info.txt
new file mode 100644
index 0000000..23447d2
--- /dev/null
+++ b/test/439-swap-double/info.txt
@@ -0,0 +1,2 @@
+Test for the optimizing compiler's parallel swap support in
+the presence of register pairs (in this case, doubles on ARM).
diff --git a/test/439-swap-double/src/Main.java b/test/439-swap-double/src/Main.java
new file mode 100644
index 0000000..da11577
--- /dev/null
+++ b/test/439-swap-double/src/Main.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+// Test for the optimizing compiler's parallel swap support in
+// the presence of register pairs (in this case, doubles on ARM).
+public class Main {
+  public static void main(String[] args) {
+    new Main().foo();
+  }
+
+  public void foo() {
+    // Do multiple calls to force swapping of registers. Note that
+    // this depends on the calling convention, as a stack-only convention
+    // may not need the swapping.
+    callWithDoubles(a, b, c, d, e, f, g);
+    callWithDoubles(b, c, d, e, f, g, a);
+    callWithDoubles(c, d, e, f, g, a, b);
+    callWithDoubles(d, e, f, g, a, b, c);
+  }
+
+  public static void callWithDoubles(
+      double a, double b, double c, double d, double e, double f, double g) {
+    System.out.println(a - b - c - d - e - f - g);
+  }
+
+  double a = 1.0;
+  double b = 2.0;
+  double c = 3.0;
+  double d = 4.0;
+  double e = 5.0;
+  double f = 6.0;
+  double g = 7.0;
+}
diff --git a/test/440-stmp/expected.txt b/test/440-stmp/expected.txt
new file mode 100644
index 0000000..e995b05
--- /dev/null
+++ b/test/440-stmp/expected.txt
@@ -0,0 +1 @@
+-118.0
diff --git a/test/440-stmp/info.txt b/test/440-stmp/info.txt
new file mode 100644
index 0000000..c4a7bf1
--- /dev/null
+++ b/test/440-stmp/info.txt
@@ -0,0 +1,3 @@
+Regression test for optimizing, that used to consider
+a S/D register a temp, while it conflicted with the
+hard-float calling convention.
diff --git a/test/440-stmp/src/Main.java b/test/440-stmp/src/Main.java
new file mode 100644
index 0000000..2dd10f8
--- /dev/null
+++ b/test/440-stmp/src/Main.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+class Main {
+  public static void main(String[] args) {
+    new Main().bar();
+  }
+
+  public void bar() {
+    // Use up all available D registers on ARM.
+    baz(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
+  }
+
+  public static void baz(float a, float b, float c, float d, float e, float f, float g,
+                         float h, float i, float j, float k, float l, float m, float n, float o) {
+    System.out.println(a - b - c - d - e - f - g - h - i - j - k - l - m - n - o);
+  }
+
+  float a = 1.0f;
+  float b = 2.0f;
+  float c = 3.0f;
+  float d = 4.0f;
+  float e = 5.0f;
+  float f = 6.0f;
+  float g = 7.0f;
+  float h = 8.0f;
+  float i = 9.0f;
+  float j = 10.0f;
+  float k = 11.0f;
+  float l = 12.0f;
+  float m = 13.0f;
+  float n = 14.0f;
+  float o = 15.0f;
+}
diff --git a/test/441-checker-inliner/expected.txt b/test/441-checker-inliner/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/441-checker-inliner/expected.txt
diff --git a/test/441-checker-inliner/info.txt b/test/441-checker-inliner/info.txt
new file mode 100644
index 0000000..66a3270
--- /dev/null
+++ b/test/441-checker-inliner/info.txt
@@ -0,0 +1 @@
+Tests inlining in the optimizing compiler.
diff --git a/test/441-checker-inliner/src/Main.java b/test/441-checker-inliner/src/Main.java
new file mode 100644
index 0000000..631b140
--- /dev/null
+++ b/test/441-checker-inliner/src/Main.java
@@ -0,0 +1,242 @@
+/*
+* 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 {
+
+  // CHECK-START: void Main.InlineVoid() inliner (before)
+  // CHECK-DAG:     [[Const42:i\d+]] IntConstant 42
+  // CHECK-DAG:                      InvokeStaticOrDirect
+  // CHECK-DAG:                      InvokeStaticOrDirect [ [[Const42]] ]
+
+  // CHECK-START: void Main.InlineVoid() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static void InlineVoid() {
+    returnVoid();
+    returnVoidWithOneParameter(42);
+  }
+
+  // CHECK-START: int Main.InlineParameter(int) inliner (before)
+  // CHECK-DAG:     [[Param:i\d+]]  ParameterValue
+  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect [ [[Param]] ]
+  // CHECK-DAG:                     Return [ [[Result]] ]
+
+  // CHECK-START: int Main.InlineParameter(int) inliner (after)
+  // CHECK-DAG:     [[Param:i\d+]]  ParameterValue
+  // CHECK-DAG:                     Return [ [[Param]] ]
+
+  public static int InlineParameter(int a) {
+    return returnParameter(a);
+  }
+
+  // CHECK-START: long Main.InlineWideParameter(long) inliner (before)
+  // CHECK-DAG:     [[Param:j\d+]]  ParameterValue
+  // CHECK-DAG:     [[Result:j\d+]] InvokeStaticOrDirect [ [[Param]] ]
+  // CHECK-DAG:                     Return [ [[Result]] ]
+
+  // CHECK-START: long Main.InlineWideParameter(long) inliner (after)
+  // CHECK-DAG:     [[Param:j\d+]]  ParameterValue
+  // CHECK-DAG:                     Return [ [[Param]] ]
+
+  public static long InlineWideParameter(long a) {
+    return returnWideParameter(a);
+  }
+
+  // CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (before)
+  // CHECK-DAG:     [[Param:l\d+]]  ParameterValue
+  // CHECK-DAG:     [[Result:l\d+]] InvokeStaticOrDirect [ [[Param]] ]
+  // CHECK-DAG:                     Return [ [[Result]] ]
+
+  // CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (after)
+  // CHECK-DAG:     [[Param:l\d+]]  ParameterValue
+  // CHECK-DAG:                     Return [ [[Param]] ]
+
+  public static Object InlineReferenceParameter(Object o) {
+    return returnReferenceParameter(o);
+  }
+
+  // CHECK-START: int Main.InlineInt() inliner (before)
+  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [ [[Result]] ]
+
+  // CHECK-START: int Main.InlineInt() inliner (after)
+  // CHECK-DAG:     [[Const4:i\d+]] IntConstant 4
+  // CHECK-DAG:                     Return [ [[Const4]] ]
+
+  public static int InlineInt() {
+    return returnInt();
+  }
+
+  // CHECK-START: long Main.InlineWide() inliner (before)
+  // CHECK-DAG:     [[Result:j\d+]] InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [ [[Result]] ]
+
+  // CHECK-START: long Main.InlineWide() inliner (after)
+  // CHECK-DAG:     [[Const8:j\d+]] LongConstant 8
+  // CHECK-DAG:                     Return [ [[Const8]] ]
+
+  public static long InlineWide() {
+    return returnWide();
+  }
+
+  // CHECK-START: int Main.InlineAdd() inliner (before)
+  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
+  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
+  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [ [[Result]] ]
+
+  // CHECK-START: int Main.InlineAdd() inliner (after)
+  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
+  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
+  // CHECK-DAG:     [[Add:i\d+]]    Add [ [[Const3]] [[Const5]] ]
+  // CHECK-DAG:                     Return [ [[Add]] ]
+
+  public static int InlineAdd() {
+    return returnAdd(3, 5);
+  }
+
+  // CHECK-START: int Main.InlineFieldAccess() inliner (before)
+  // CHECK-DAG:     [[After:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                     Return [ [[After]] ]
+
+  // CHECK-START: int Main.InlineFieldAccess() inliner (after)
+  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
+  // CHECK-DAG:     [[Before:i\d+]] StaticFieldGet
+  // CHECK-DAG:     [[After:i\d+]]  Add [ [[Before]] [[Const1]] ]
+  // CHECK-DAG:                     StaticFieldSet [ {{l\d+}} [[After]] ]
+  // CHECK-DAG:                     Return [ [[After]] ]
+
+  // CHECK-START: int Main.InlineFieldAccess() inliner (after)
+  // CHECK-NOT:                     InvokeStaticOrDirect
+
+  public static int InlineFieldAccess() {
+    return incCounter();
+  }
+
+  // CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (before)
+  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
+  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
+  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
+  // CHECK-DAG:     [[Add:i\d+]]    InvokeStaticOrDirect [ [[Const1]] [[Const3]] ]
+  // CHECK-DAG:     [[Sub:i\d+]]    InvokeStaticOrDirect [ [[Const5]] [[Const3]] ]
+  // CHECK-DAG:     [[Phi:i\d+]]    Phi [ [[Add]] [[Sub]] ]
+  // CHECK-DAG:                     Return [ [[Phi]] ]
+
+  // CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
+  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
+  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
+  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
+  // CHECK-DAG:     [[Add:i\d+]]    Add [ [[Const1]] [[Const3]] ]
+  // CHECK-DAG:     [[Sub:i\d+]]    Sub [ [[Const5]] [[Const3]] ]
+  // CHECK-DAG:     [[Phi:i\d+]]    Phi [ [[Add]] [[Sub]] ]
+  // CHECK-DAG:                     Return [ [[Phi]] ]
+
+  public static int InlineWithControlFlow(boolean cond) {
+    int x, const1, const3, const5;
+    const1 = 1;
+    const3 = 3;
+    const5 = 5;
+    if (cond) {
+      x = returnAdd(const1, const3);
+    } else {
+      x = returnSub(const5, const3);
+    }
+    return x;
+  }
+
+
+  private static void returnVoid() {
+    return;
+  }
+
+  private static void returnVoidWithOneParameter(int a) {
+    return;
+  }
+
+  private static int returnParameter(int a) {
+    return a;
+  }
+
+  private static long returnWideParameter(long a) {
+    return a;
+  }
+
+  private static Object returnReferenceParameter(Object o) {
+    return o;
+  }
+
+  private static int returnInt() {
+    return 4;
+  }
+
+  private static long returnWide() {
+    return 8L;
+  }
+
+  private static int returnAdd(int a, int b) {
+    return a + b;
+  }
+
+  private static int returnSub(int a, int b) {
+    return a - b;
+  }
+
+  private static int counter = 42;
+
+  private static int incCounter() {
+    return ++counter;
+  }
+
+  public static void main(String[] args) {
+    InlineVoid();
+
+    if (InlineInt() != 4) {
+      throw new Error();
+    }
+
+    if (InlineWide() != 8L) {
+      throw new Error();
+    }
+
+    if (InlineParameter(42) != 42) {
+      throw new Error();
+    }
+
+    if (InlineWideParameter(0x100000001L) != 0x100000001L) {
+      throw new Error();
+    }
+
+    if (InlineReferenceParameter(Main.class) != Main.class) {
+      throw new Error();
+    }
+
+    if (InlineAdd() != 8) {
+      throw new Error();
+    }
+
+    if (InlineFieldAccess() != 43 || InlineFieldAccess() != 44) {
+      throw new Error();
+    }
+
+    if (InlineWithControlFlow(true) != 4) {
+      throw new Error();
+    }
+
+    if (InlineWithControlFlow(false) != 2) {
+      throw new Error();
+    }
+  }
+}
diff --git a/test/442-checker-constant-folding/expected.txt b/test/442-checker-constant-folding/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/442-checker-constant-folding/expected.txt
diff --git a/test/442-checker-constant-folding/info.txt b/test/442-checker-constant-folding/info.txt
new file mode 100644
index 0000000..5073972
--- /dev/null
+++ b/test/442-checker-constant-folding/info.txt
@@ -0,0 +1 @@
+Tests constant folding in the optimizing compiler.
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
new file mode 100644
index 0000000..de2c5c7
--- /dev/null
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -0,0 +1,259 @@
+/*
+* 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 {
+
+  /**
+   * Tiny three-register program exercising int constant folding
+   * on negation.
+   */
+
+  // CHECK-START: int Main.IntNegation() constant_folding (before)
+  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
+  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Const42]] ]
+  // CHECK-DAG:                       Return [ [[Neg]] ]
+
+  // CHECK-START: int Main.IntNegation() constant_folding (after)
+  // CHECK-DAG:     [[ConstN42:i\d+]] IntConstant -42
+  // CHECK-DAG:                       Return [ [[ConstN42]] ]
+
+  public static int IntNegation() {
+    int x, y;
+    x = 42;
+    y = -x;
+    return y;
+  }
+
+  /**
+   * Tiny three-register program exercising int constant folding
+   * on addition.
+   */
+
+  // CHECK-START: int Main.IntAddition1() constant_folding (before)
+  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
+  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
+  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[Const1]] [[Const2]] ]
+  // CHECK-DAG:                      Return [ [[Add]] ]
+
+  // CHECK-START: int Main.IntAddition1() constant_folding (after)
+  // CHECK-DAG:     [[Const3:i\d+]]  IntConstant 3
+  // CHECK-DAG:                      Return [ [[Const3]] ]
+
+  public static int IntAddition1() {
+    int a, b, c;
+    a = 1;
+    b = 2;
+    c = a + b;
+    return c;
+  }
+
+ /**
+  * Small three-register program exercising int constant folding
+  * on addition.
+  */
+
+  // CHECK-START: int Main.IntAddition2() constant_folding (before)
+  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
+  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
+  // CHECK-DAG:     [[Const5:i\d+]]  IntConstant 5
+  // CHECK-DAG:     [[Const6:i\d+]]  IntConstant 6
+  // CHECK-DAG:     [[Add1:i\d+]]    Add [ [[Const1]] [[Const2]] ]
+  // CHECK-DAG:     [[Add2:i\d+]]    Add [ [[Const5]] [[Const6]] ]
+  // CHECK-DAG:     [[Add3:i\d+]]    Add [ [[Add1]] [[Add2]] ]
+  // CHECK-DAG:                      Return [ [[Add3]] ]
+
+  // CHECK-START: int Main.IntAddition2() constant_folding (after)
+  // CHECK-DAG:     [[Const14:i\d+]] IntConstant 14
+  // CHECK-DAG:                      Return [ [[Const14]] ]
+
+  public static int IntAddition2() {
+    int a, b, c;
+    a = 1;
+    b = 2;
+    a += b;
+    b = 5;
+    c = 6;
+    b += c;
+    c = a + b;
+    return c;
+  }
+
+  /**
+   * Tiny three-register program exercising int constant folding
+   * on subtraction.
+   */
+
+  // CHECK-START: int Main.IntSubtraction() constant_folding (before)
+  // CHECK-DAG:     [[Const6:i\d+]]  IntConstant 6
+  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
+  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[Const6]] [[Const2]] ]
+  // CHECK-DAG:                      Return [ [[Sub]] ]
+
+  // CHECK-START: int Main.IntSubtraction() constant_folding (after)
+  // CHECK-DAG:     [[Const4:i\d+]]  IntConstant 4
+  // CHECK-DAG:                      Return [ [[Const4]] ]
+
+  public static int IntSubtraction() {
+    int a, b, c;
+    a = 6;
+    b = 2;
+    c = a - b;
+    return c;
+  }
+
+  /**
+   * Tiny three-register program exercising long constant folding
+   * on addition.
+   */
+
+  // CHECK-START: long Main.LongAddition() constant_folding (before)
+  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
+  // CHECK-DAG:     [[Const2:j\d+]]  LongConstant 2
+  // CHECK-DAG:     [[Add:j\d+]]     Add [ [[Const1]] [[Const2]] ]
+  // CHECK-DAG:                      Return [ [[Add]] ]
+
+  // CHECK-START: long Main.LongAddition() constant_folding (after)
+  // CHECK-DAG:     [[Const3:j\d+]]  LongConstant 3
+  // CHECK-DAG:                      Return [ [[Const3]] ]
+
+  public static long LongAddition() {
+    long a, b, c;
+    a = 1L;
+    b = 2L;
+    c = a + b;
+    return c;
+  }
+
+  /**
+   * Tiny three-register program exercising long constant folding
+   * on subtraction.
+   */
+
+  // CHECK-START: long Main.LongSubtraction() constant_folding (before)
+  // CHECK-DAG:     [[Const6:j\d+]]  LongConstant 6
+  // CHECK-DAG:     [[Const2:j\d+]]  LongConstant 2
+  // CHECK-DAG:     [[Sub:j\d+]]     Sub [ [[Const6]] [[Const2]] ]
+  // CHECK-DAG:                      Return [ [[Sub]] ]
+
+  // CHECK-START: long Main.LongSubtraction() constant_folding (after)
+  // CHECK-DAG:     [[Const4:j\d+]]  LongConstant 4
+  // CHECK-DAG:                      Return [ [[Const4]] ]
+
+  public static long LongSubtraction() {
+    long a, b, c;
+    a = 6L;
+    b = 2L;
+    c = a - b;
+    return c;
+  }
+
+  /**
+   * Three-register program with a constant (static) condition.
+   */
+
+  // CHECK-START: int Main.StaticCondition() constant_folding (before)
+  // CHECK-DAG:     [[Const7:i\d+]]  IntConstant 7
+  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
+  // CHECK-DAG:     [[Cond:z\d+]]    GreaterThanOrEqual [ [[Const7]] [[Const2]] ]
+  // CHECK-DAG:                      If [ [[Cond]] ]
+
+  // CHECK-START: int Main.StaticCondition() constant_folding (after)
+  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
+  // CHECK-DAG:                      If [ [[Const1]] ]
+
+  public static int StaticCondition() {
+    int a, b, c;
+    a = 7;
+    b = 2;
+    if (a < b)
+      c = a + b;
+    else
+      c = a - b;
+    return c;
+  }
+
+  /**
+   * Four-variable program with jumps leading to the creation of many
+   * blocks.
+   *
+   * The intent of this test is to ensure that all constant expressions
+   * are actually evaluated at compile-time, thanks to the reverse
+   * (forward) post-order traversal of the the dominator tree.
+   */
+
+  // CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (before)
+  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
+  // CHECK-DAG:     [[Const5:i\d+]]  IntConstant 5
+  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[Const5]] [[Const2]] ]
+  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[Const5]] [[Const2]] ]
+  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
+  // CHECK-DAG:                      Return [ [[Phi]] ]
+
+  // CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (after)
+  // CHECK-DAG:     [[Const3:i\d+]]  IntConstant 3
+  // CHECK-DAG:     [[Const7:i\d+]]  IntConstant 7
+  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Const7]] [[Const3]] ]
+  // CHECK-DAG:                      Return [ [[Phi]] ]
+
+  public static int JumpsAndConditionals(boolean cond) {
+    int a, b, c;
+    a = 5;
+    b = 2;
+    if (cond)
+      c = a + b;
+    else
+      c = a - b;
+    return c;
+  }
+
+  public static void main(String[] args) {
+    if (IntNegation() != -42) {
+      throw new Error();
+    }
+
+    if (IntAddition1() != 3) {
+      throw new Error();
+    }
+
+    if (IntAddition2() != 14) {
+      throw new Error();
+    }
+
+    if (IntSubtraction() != 4) {
+      throw new Error();
+    }
+
+    if (LongAddition() != 3L) {
+      throw new Error();
+    }
+
+    if (LongSubtraction() != 4L) {
+      throw new Error();
+    }
+
+    if (StaticCondition() != 5) {
+      throw new Error();
+    }
+
+    if (JumpsAndConditionals(true) != 7) {
+      throw new Error();
+    }
+
+    if (JumpsAndConditionals(false) != 3) {
+      throw new Error();
+    }
+  }
+}
diff --git a/test/443-not-bool-inline/expected.txt b/test/443-not-bool-inline/expected.txt
new file mode 100644
index 0000000..3ee3849
--- /dev/null
+++ b/test/443-not-bool-inline/expected.txt
@@ -0,0 +1 @@
+Hello World 2
diff --git a/test/443-not-bool-inline/info.txt b/test/443-not-bool-inline/info.txt
new file mode 100644
index 0000000..31f2321
--- /dev/null
+++ b/test/443-not-bool-inline/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing, who used a wrong instruction
+for simplifying Equals(foo, false);
diff --git a/test/443-not-bool-inline/src/Main.java b/test/443-not-bool-inline/src/Main.java
new file mode 100644
index 0000000..3a6f3be
--- /dev/null
+++ b/test/443-not-bool-inline/src/Main.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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 {
+  public static void main(String[] args) {
+    // For some reason, dx wants != for generating if-eq.
+    if (falseField != false) {
+      System.out.println("Hello World 1");
+    }
+
+    if (trueField != false) {
+      System.out.println("Hello World 2");
+    }
+  }
+
+  static boolean falseField = false;
+  static boolean trueField = true;
+}
diff --git a/test/703-floating-point-div/expected.txt b/test/703-floating-point-div/expected.txt
new file mode 100644
index 0000000..76f5a5a
--- /dev/null
+++ b/test/703-floating-point-div/expected.txt
@@ -0,0 +1 @@
+Done!
diff --git a/test/703-floating-point-div/info.txt b/test/703-floating-point-div/info.txt
new file mode 100644
index 0000000..418b831
--- /dev/null
+++ b/test/703-floating-point-div/info.txt
@@ -0,0 +1 @@
+Simple tests to check floating point division.
diff --git a/test/703-floating-point-div/src/Main.java b/test/703-floating-point-div/src/Main.java
new file mode 100644
index 0000000..9990a54
--- /dev/null
+++ b/test/703-floating-point-div/src/Main.java
@@ -0,0 +1,90 @@
+/*
+ * 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 {
+
+    static double dPi = Math.PI;
+    static float  fPi = (float)Math.PI;
+
+    public static void expectEquals(long expected, long result) {
+        if (expected != result) {
+            throw new Error("Expected: " + expected + ", found: " + result);
+        }
+    }
+
+    public static void expectEquals(int expected, int result) {
+        if (expected != result) {
+            throw new Error("Expected: " + expected + ", found: " + result);
+        }
+    }
+
+    public static void divDoubleTest() {
+        double d1 = 0x1.0p1023;
+        double d2 = -2.0;
+        double d3 = 0.0;
+        double d4 = Double.MIN_NORMAL;
+        double d5 = Double.POSITIVE_INFINITY;
+        double d6 = Double.NEGATIVE_INFINITY;
+        double d7 = -0.0;
+        double d8 = Double.MAX_VALUE;
+        double d9 = Double.MIN_VALUE;
+        double d0 = Double.NaN;
+
+        expectEquals(Double.doubleToRawLongBits(dPi/d1), 0x1921fb54442d18L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d2), 0xbff921fb54442d18L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d3), 0x7ff0000000000000L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d4), 0x7fe921fb54442d18L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d5), 0x0L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d6), 0x8000000000000000L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d7), 0xfff0000000000000L);
+
+        expectEquals(Double.doubleToRawLongBits(dPi/d8), 0xc90fdaa22168cL);
+        expectEquals(Double.doubleToRawLongBits(dPi/d9), 0x7ff0000000000000L);
+        expectEquals(Double.doubleToRawLongBits(dPi/d0), 0x7ff8000000000000L);
+    }
+
+    public static void divFloatTest() {
+        float f1 = 0x1.0p127f;
+        float f2 = -2.0f;
+        float f3 = 0.0f;
+        float f4 = Float.MIN_NORMAL;
+        float f5 = Float.POSITIVE_INFINITY;
+        float f6 = Float.NEGATIVE_INFINITY;
+        float f7 = -0.0f;
+        float f8 = Float.MAX_VALUE;
+        float f9 = Float.MIN_VALUE;
+        float f0 = Float.NaN;
+
+        expectEquals(Float.floatToRawIntBits(fPi/f1), 0xc90fdb);
+        expectEquals(Float.floatToRawIntBits(fPi/f2), 0xbfc90fdb);
+        expectEquals(Float.floatToRawIntBits(fPi/f3), 0x7f800000);
+        expectEquals(Float.floatToRawIntBits(fPi/f4), 0x7f490fdb);
+        expectEquals(Float.floatToRawIntBits(fPi/f5), 0x0);
+        expectEquals(Float.floatToRawIntBits(fPi/f6), 0x80000000);
+        expectEquals(Float.floatToRawIntBits(fPi/f7), 0xff800000);
+
+        expectEquals(Float.floatToRawIntBits(fPi/f8), 0x6487ee);
+        expectEquals(Float.floatToRawIntBits(fPi/f9), 0x7f800000);
+        expectEquals(Float.floatToRawIntBits(fPi/f0), 0x7fc00000);
+    }
+
+    public static void main(String[] args) {
+        divDoubleTest();
+        divFloatTest();
+        System.out.println("Done!");
+    }
+
+}
diff --git a/test/704-multiply-accumulate/expected.txt b/test/704-multiply-accumulate/expected.txt
new file mode 100644
index 0000000..76f5a5a
--- /dev/null
+++ b/test/704-multiply-accumulate/expected.txt
@@ -0,0 +1 @@
+Done!
diff --git a/test/704-multiply-accumulate/info.txt b/test/704-multiply-accumulate/info.txt
new file mode 100644
index 0000000..a12fd44
--- /dev/null
+++ b/test/704-multiply-accumulate/info.txt
@@ -0,0 +1 @@
+Tests for multiply accumulate operations.
diff --git a/test/704-multiply-accumulate/src/Main.java b/test/704-multiply-accumulate/src/Main.java
new file mode 100644
index 0000000..7404b9b
--- /dev/null
+++ b/test/704-multiply-accumulate/src/Main.java
@@ -0,0 +1,171 @@
+/*
+ * 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 {
+
+    static int imax = Integer.MAX_VALUE;
+    static int imin = Integer.MIN_VALUE;
+    static long lmax = Long.MAX_VALUE;
+    static long lmin = Long.MIN_VALUE;
+    static CA ca;
+
+    public static void expectEquals(long expected, long result) {
+        if (expected != result) {
+            throw new Error("Expected: " + expected + ", found: " + result);
+        }
+    }
+
+    public static void expectEquals(int expected, int result) {
+        if (expected != result) {
+            throw new Error("Expected: " + expected + ", found: " + result);
+        }
+    }
+
+    public static void test_int() {
+        int result = 0;
+        int a = imax;
+        int b = imin;
+        int c = 10;
+        int d = c;
+        int tmp = 0;
+        int [] ia = new int[5];
+        for (int i = 0; i < 100; i++) {
+            tmp = i*c;
+            result += i*i;
+            result = i - tmp;
+        }
+        expectEquals(result, -891);
+
+        result = c*c + (result - c);
+        expectEquals(result, -801);
+
+        result = a + a*a;
+        expectEquals(result, -2147483648);
+
+        result = b + b*b;
+        expectEquals(result, -2147483648);
+
+        result = b - a*a;
+        expectEquals(result, 2147483647);
+
+        result = d*d;
+        d++;
+        result += result;
+        expectEquals(result, 200);
+
+        result = c*c;
+        tmp++;
+        result += result;
+        expectEquals(result, 200);
+
+        result = 0;
+        try {
+            result = c*c;
+            ia[c] = d;  // array out of bound.
+            result += d;
+        } catch (Exception e) {
+        }
+        expectEquals(result, 100);
+
+        CA obj = new CA();
+        result = a*c + obj.ia;
+        expectEquals(result, 2);
+
+        result = 0;
+        obj = ca;
+        try {
+            result = a*c;
+            tmp = obj.ia;
+            result = result + tmp;
+        } catch (Exception e) {
+        }
+        expectEquals(result, -10);
+    }
+
+    public static void test_long() {
+        long result = 0;
+        long a = lmax;
+        long b = lmin;
+        long c = 10;
+        long d = c;
+        long tmp = 0;
+        int [] ia = new int[5];
+        for (long i = 0; i < 100; i++) {
+            tmp = i*c;
+            result += i*i;
+            result = i - tmp;
+        }
+        expectEquals(result, -891L);
+
+        result = c*c + (result - c);
+        expectEquals(result, -801L);
+
+        result = a + a*a;
+        expectEquals(result, -9223372036854775808L);
+
+        result = b + b*b;
+        expectEquals(result, -9223372036854775808L);
+
+        result = b - a*a;
+        expectEquals(result, 9223372036854775807L);
+
+        result = d*d;
+        d++;
+        result += result;
+        expectEquals(result, 200L);
+
+        result = c*c;
+        tmp++;
+        result += result;
+        expectEquals(result, 200L);
+
+        result = 0;
+        int index = 10;
+        try {
+            result = c*c;
+            ia[index] = 10;  // array out of bound.
+            result += d;
+        } catch (Exception e) {
+        }
+        expectEquals(result, 100L);
+
+        CA obj = new CA();
+        result = a*c + obj.la;
+        expectEquals(result, 113L);
+
+        result = 0;
+        obj = ca;
+        try {
+            result = a*c;
+            tmp = obj.la;
+            result = result + tmp;
+        } catch (Exception e) {
+        }
+        expectEquals(result, -10L);
+    }
+
+    public static void main(String[] args) {
+        test_int();
+        test_long();
+        System.out.println("Done!");
+    }
+
+}
+
+class CA {
+    public int ia = 12;
+    public long la = 123L;
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
new file mode 100644
index 0000000..6cb08f4
--- /dev/null
+++ b/test/800-smali/expected.txt
@@ -0,0 +1,16 @@
+PackedSwitch
+b/17790197
+b/17978759
+FloatBadArgReg
+negLong
+sameFieldNames
+b/18380491
+invoke-super abstract
+BadCaseInOpRegRegReg
+CmpLong
+FloatIntConstPassing
+b/18718277
+b/18800943 (1)
+b/18800943 (2)
+MoveExc
+Done!
diff --git a/test/800-smali/info.txt b/test/800-smali/info.txt
new file mode 100644
index 0000000..3022962
--- /dev/null
+++ b/test/800-smali/info.txt
@@ -0,0 +1,4 @@
+Smali-based tests.
+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/smali/BadCaseInOpRegRegReg.smali b/test/800-smali/smali/BadCaseInOpRegRegReg.smali
new file mode 100644
index 0000000..2683790
--- /dev/null
+++ b/test/800-smali/smali/BadCaseInOpRegRegReg.smali
@@ -0,0 +1,13 @@
+.class public LBadCaseInOpRegRegReg;
+
+.super Ljava/lang/Object;
+
+.method public static getInt()I
+    .registers 2
+    const/4 v0, 0x0
+    const/4 v1, 0x1
+    add-int/2addr v0, v1
+    add-int/lit8 v1, v0, 0x1
+    mul-int v0, v1, v0
+    return v0
+.end method
diff --git a/test/800-smali/smali/CmpLong.smali b/test/800-smali/smali/CmpLong.smali
new file mode 100644
index 0000000..d54812f
--- /dev/null
+++ b/test/800-smali/smali/CmpLong.smali
@@ -0,0 +1,18 @@
+.class public LCmpLong;
+.super Ljava/lang/Object;
+
+
+.method public constructor <init>()V
+.registers 1
+       invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+       return-void
+.end method
+
+.method public static run()I
+.registers 5000
+       const-wide v100, 5678233453L
+       move-wide/from16 v101, v100
+       const-wide v4, 5678233453L
+       cmp-long v0, v101, v4
+       return v0
+.end method
diff --git a/test/800-smali/smali/FloatBadArgReg.smali b/test/800-smali/smali/FloatBadArgReg.smali
new file mode 100644
index 0000000..719ba09
--- /dev/null
+++ b/test/800-smali/smali/FloatBadArgReg.smali
@@ -0,0 +1,16 @@
+.class public LFloatBadArgReg;
+
+.super Ljava/lang/Object;
+
+.method public static getInt(I)I
+    .registers 2
+    const/4 v0, 0x0
+    if-ne v0, v0, :after
+    float-to-int v0, v0
+    :exit
+    add-int/2addr v0, v1
+    return v0
+    :after
+    move v1, v0
+    goto :exit
+.end method
diff --git a/test/800-smali/smali/FloatIntConstPassing.smali b/test/800-smali/smali/FloatIntConstPassing.smali
new file mode 100644
index 0000000..a2916c5
--- /dev/null
+++ b/test/800-smali/smali/FloatIntConstPassing.smali
@@ -0,0 +1,29 @@
+.class public LFloatIntConstPassing;
+
+.super Ljava/lang/Object;
+
+.method public static getInt(I)I
+  .registers 2
+  const/4 v0, 1
+  add-int/2addr v0, p0
+  return v0
+.end method
+
+.method public static getFloat(F)F
+  .registers 2
+  const/4 v0, 0
+  mul-float/2addr v0, p0
+  return v0
+.end method
+
+.method public static run()I
+  .registers 3
+  const/4 v0, 1
+  invoke-static {v0}, LFloatIntConstPassing;->getInt(I)I
+  move-result v1
+  invoke-static {v0}, LFloatIntConstPassing;->getFloat(F)F
+  move-result v2
+  float-to-int v2, v2
+  add-int/2addr v1, v2
+  return v1
+.end method
diff --git a/test/800-smali/smali/PackedSwitch.smali b/test/800-smali/smali/PackedSwitch.smali
new file mode 100644
index 0000000..6a3e5f0
--- /dev/null
+++ b/test/800-smali/smali/PackedSwitch.smali
@@ -0,0 +1,26 @@
+.class public LPackedSwitch;
+
+.super Ljava/lang/Object;
+
+.method public static packedSwitch(I)I
+    .registers 2
+
+    const/4 v0, 0
+    packed-switch v0, :switch_data
+    goto :default
+
+    :switch_data
+    .packed-switch 0x0
+        :case
+    .end packed-switch
+
+    :return
+    return v1
+
+    :default
+    goto :return
+
+    :case
+    goto :return
+
+.end method
diff --git a/test/800-smali/smali/b_17790197.smali b/test/800-smali/smali/b_17790197.smali
new file mode 100644
index 0000000..7560fcf
--- /dev/null
+++ b/test/800-smali/smali/b_17790197.smali
@@ -0,0 +1,17 @@
+.class public LB17790197;
+
+.super Ljava/lang/Object;
+
+.method public static getInt()I
+    .registers 4
+    const/16 v0, 100
+    const/4 v1, 1
+    const/4 v2, 7
+    :loop
+    if-eq v2, v0, :done
+    add-int v2, v2, v1
+    goto :loop
+    :done
+    add-float v3, v0, v1
+    return v2
+.end method
diff --git a/test/800-smali/smali/b_17978759.smali b/test/800-smali/smali/b_17978759.smali
new file mode 100644
index 0000000..07bcae5
--- /dev/null
+++ b/test/800-smali/smali/b_17978759.smali
@@ -0,0 +1,28 @@
+.class public LB17978759;
+.super Ljava/lang/Object;
+
+  .method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+  .end method
+
+  .method public test()V
+    .registers 2
+
+    move-object   v0, p0
+    # v0 and p0 alias
+    monitor-enter p0
+    # monitor-enter on p0
+    monitor-exit  v0
+    # monitor-exit on v0, however, verifier doesn't track this and so this is
+    # a warning. Verifier will still think p0 is locked.
+
+    move-object   v0, p0
+    # v0 will now appear locked.
+    monitor-enter v0
+    # Attempt to lock v0 twice is a verifier failure.
+    monitor-exit  v0
+
+    return-void
+  .end method
diff --git a/test/800-smali/smali/b_18380491AbstractBase.smali b/test/800-smali/smali/b_18380491AbstractBase.smali
new file mode 100644
index 0000000..7aa1b1a
--- /dev/null
+++ b/test/800-smali/smali/b_18380491AbstractBase.smali
@@ -0,0 +1,12 @@
+.class public LB18380491ActractBase;
+
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+    .locals 0
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public abstract foo(I)I
+.end method
diff --git a/test/800-smali/smali/b_18380491ConcreteClass.smali b/test/800-smali/smali/b_18380491ConcreteClass.smali
new file mode 100644
index 0000000..db5ef3b
--- /dev/null
+++ b/test/800-smali/smali/b_18380491ConcreteClass.smali
@@ -0,0 +1,19 @@
+.class public LB18380491ConcreteClass;
+
+.super LB18380491ActractBase;
+
+.method public constructor <init>()V
+    .locals 0
+    invoke-direct {p0}, LB18380491ActractBase;-><init>()V
+    return-void
+.end method
+
+.method public foo(I)I
+  .locals 1
+  if-eqz p1, :invoke_super_abstract
+  return p1
+  :invoke_super_abstract
+  invoke-super {p0, p1}, LB18380491ActractBase;->foo(I)I
+  move-result v0
+  return v0
+.end method
diff --git a/test/800-smali/smali/b_18718277.smali b/test/800-smali/smali/b_18718277.smali
new file mode 100644
index 0000000..b14ad20
--- /dev/null
+++ b/test/800-smali/smali/b_18718277.smali
@@ -0,0 +1,29 @@
+.class public LB18718277;
+
+.super Ljava/lang/Object;
+
+.method public static helper(I)I
+    .locals 1
+    add-int/lit8 v0, p0, 2
+    neg-int v0, v0
+    return v0
+.end method
+
+.method public static getInt()I
+    .registers 2
+    const/4 v1, 3
+    invoke-static {v1}, LB18718277;->helper(I)I
+    move-result v0
+    :outer_loop
+    if-eqz v1, :exit_outer_loop
+    const/4 v0, 0
+    if-eqz v0, :skip_dead_loop
+    :dead_loop
+    add-int/2addr v0, v0
+    if-gez v0, :dead_loop
+    :skip_dead_loop
+    add-int/lit8 v1, v1, -1
+    goto :outer_loop
+    :exit_outer_loop
+    return v0
+.end method
diff --git a/test/800-smali/smali/b_18800943_1.smali b/test/800-smali/smali/b_18800943_1.smali
new file mode 100644
index 0000000..868438e
--- /dev/null
+++ b/test/800-smali/smali/b_18800943_1.smali
@@ -0,0 +1,9 @@
+.class public LB18800943_1;
+.super Ljava/lang/Object;
+
+# This constructor should fail verification as the object is not initialized by a super-call.
+.method public constructor <init>()V
+.registers 1
+       nop
+       return-void
+.end method
diff --git a/test/800-smali/smali/b_18800943_2.smali b/test/800-smali/smali/b_18800943_2.smali
new file mode 100644
index 0000000..6052ada
--- /dev/null
+++ b/test/800-smali/smali/b_18800943_2.smali
@@ -0,0 +1,9 @@
+.class public LB18800943_2;
+.super Ljava/lang/Object;
+
+# This constructor should fail verification as the object is not initialized by a super-call.
+.method public constructor <init>()V
+.registers 1
+       const v0, 0x0
+       return-void
+.end method
diff --git a/test/800-smali/smali/move_exc.smali b/test/800-smali/smali/move_exc.smali
new file mode 100644
index 0000000..4ade4bc
--- /dev/null
+++ b/test/800-smali/smali/move_exc.smali
@@ -0,0 +1,29 @@
+.class public LMoveExc;
+.super Ljava/lang/Object;
+
+
+.method public constructor <init>()V
+.registers 1
+       invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+       return-void
+.end method
+
+.method public static run()V
+.registers 6
+:Label1
+       const v1, 15
+       const v2, 0
+       div-int v0, v1, v2
+
+:Label2
+       goto :Label4
+
+:Label3
+       move-exception v3
+       throw v3
+
+:Label4
+       return-void
+
+.catchall {:Label1 .. :Label2} :Label3
+.end method
diff --git a/test/800-smali/smali/negLong.smali b/test/800-smali/smali/negLong.smali
new file mode 100755
index 0000000..29d416e
--- /dev/null
+++ b/test/800-smali/smali/negLong.smali
@@ -0,0 +1,186 @@
+.class public LnegLong;
+.super Ljava/lang/Object;
+.source "negLong.java"
+# static fields
+.field public static final N:I = 0x64
+.field public static i:I
+# direct methods
+.method static constructor <clinit>()V
+    .registers 1
+    .prologue
+    .line 5
+    const/16 v0, 0x44da
+    sput v0, LnegLong;->i:I
+    return-void
+.end method
+.method public constructor <init>()V
+    .registers 1
+    .prologue
+    .line 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+.method public static checkSum1([S)J
+    .registers 7
+    .prologue
+    .line 14
+    array-length v3, p0
+    .line 15
+    const-wide/16 v0, 0x0
+    .line 16
+    const/4 v2, 0x0
+    :goto_4
+    if-ge v2, v3, :cond_d
+    .line 17
+    aget-short v4, p0, v2
+    int-to-long v4, v4
+    add-long/2addr v0, v4
+    .line 16
+    add-int/lit8 v2, v2, 0x1
+    goto :goto_4
+    .line 18
+    :cond_d
+    return-wide v0
+.end method
+.method public static init1([SS)V
+    .registers 4
+    .prologue
+    .line 8
+    array-length v1, p0
+    .line 9
+    const/4 v0, 0x0
+    :goto_2
+    if-ge v0, v1, :cond_9
+    .line 10
+    aput-short p1, p0, v0
+    .line 9
+    add-int/lit8 v0, v0, 0x1
+    goto :goto_2
+    .line 11
+    :cond_9
+    return-void
+.end method
+.method public static main([Ljava/lang/String;)V
+    .registers 6
+    .prologue
+    .line 50
+    invoke-static {}, LnegLong;->negLong()J
+    move-result-wide v0
+    .line 51
+    sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    new-instance v3, Ljava/lang/StringBuilder;
+    invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
+    const-string v4, "nbp ztw p = "
+    invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+    move-result-object v3
+    invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;
+    move-result-object v0
+    invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+    move-result-object v0
+    invoke-virtual {v2, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+    .line 52
+    return-void
+.end method
+.method public static negLong()J
+    .registers 17
+    .prologue
+    .line 23
+    const-wide v1, -0x4c4a1f4aa9b1db83L
+    .line 24
+    const v7, -0x3f727efa
+    .line 25
+    const/16 v4, -0x284b
+    const v3, 0xdc01
+    .line 26
+    const/16 v0, 0x64
+    new-array v8, v0, [S
+    .line 28
+    const/16 v0, 0x1c60
+    invoke-static {v8, v0}, LnegLong;->init1([SS)V
+    .line 29
+    const/4 v0, 0x2
+    move v6, v0
+    :goto_18
+    const/16 v0, 0x56
+    if-ge v6, v0, :cond_64
+    .line 30
+    const/4 v0, 0x1
+    move v5, v0
+    move v0, v3
+    move-wide v15, v1
+    move-wide v2, v15
+    :goto_21
+    if-ge v5, v6, :cond_5d
+    .line 31
+    int-to-float v0, v4
+    neg-float v1, v7
+    add-float/2addr v0, v1
+    float-to-int v1, v0
+    .line 32
+    const/4 v0, 0x1
+    move v4, v1
+    move-wide v15, v2
+    move-wide v1, v15
+    .line 33
+    :goto_2b
+    add-int/lit8 v3, v0, 0x1
+    const/16 v0, 0x1b
+    if-ge v3, v0, :cond_3a
+    .line 35
+    int-to-long v9, v5
+    mul-long v0, v9, v1
+    neg-long v1, v0
+    .line 38
+    sget v0, LnegLong;->i:I
+    move v4, v0
+    move v0, v3
+    goto :goto_2b
+    .line 40
+    :cond_3a
+    aget-short v0, v8, v6
+    int-to-double v9, v0
+    long-to-double v11, v1
+    const-wide v13, 0x403f9851eb851eb8L
+    sub-double/2addr v11, v13
+    add-double/2addr v9, v11
+    double-to-int v0, v9
+    int-to-short v0, v0
+    aput-short v0, v8, v6
+    .line 41
+    const/4 v0, 0x2
+    :goto_4a
+    const/16 v9, 0x43
+    if-ge v0, v9, :cond_56
+    .line 42
+    neg-long v9, v1
+    const-wide/16 v11, 0x1
+    or-long/2addr v9, v11
+    add-long/2addr v1, v9
+    .line 41
+    add-int/lit8 v0, v0, 0x1
+    goto :goto_4a
+    .line 30
+    :cond_56
+    add-int/lit8 v0, v5, 0x1
+    move v5, v0
+    move v0, v3
+    move-wide v15, v1
+    move-wide v2, v15
+    goto :goto_21
+    .line 29
+    :cond_5d
+    add-int/lit8 v1, v6, 0x1
+    move v6, v1
+    move-wide v15, v2
+    move-wide v1, v15
+    move v3, v0
+    goto :goto_18
+    .line 45
+    :cond_64
+    invoke-static {v8}, LnegLong;->checkSum1([S)J
+    move-result-wide v0
+    int-to-long v2, v3
+    add-long/2addr v0, v2
+    .line 46
+    return-wide v0
+.end method
diff --git a/test/800-smali/smali/sameFieldNames.smali b/test/800-smali/smali/sameFieldNames.smali
new file mode 100644
index 0000000..107161b
--- /dev/null
+++ b/test/800-smali/smali/sameFieldNames.smali
@@ -0,0 +1,64 @@
+.class public LsameFieldNames;
+.super Ljava/lang/Object;
+
+# Test multiple fields with the same name and different types.
+# (Invalid in Java language but valid in bytecode.)
+.field static public a:D
+.field static public a:S
+.field static public a:J
+.field static public a:F
+.field static public a:Z
+.field static public a:I
+.field static public a:B
+.field static public a:C
+.field static public a:Ljava/lang/Integer;
+.field static public a:Ljava/lang/Long;
+.field static public a:Ljava/lang/Float;
+.field static public a:Ljava/lang/Double;
+.field static public a:Ljava/lang/Boolean;
+.field static public a:Ljava/lang/Void;
+.field static public a:Ljava/lang/Short;
+.field static public a:Ljava/lang/Char;
+.field static public a:Ljava/lang/Byte;
+
+# Add some more fields to stress test the sorting for offset assignment.
+.field static public b:C
+.field static public c:J
+.field static public d:C
+.field static public e:B
+.field static public f:C
+.field static public g:J
+.field static public h:C
+.field static public i:J
+.field static public j:I
+.field static public k:J
+.field static public l:J
+.field static public m:I
+.field static public n:J
+.field static public o:I
+.field static public p:Ljava/lang/Integer;
+.field static public q:I
+.field static public r:J
+.field static public s:I
+.field static public t:Ljava/lang/Integer;
+.field static public u:I
+.field static public v:J
+.field static public w:I
+.field static public x:Ljava/lang/Integer;
+.field static public y:I
+.field static public z:Ljava/lang/Integer;
+
+.method public static getInt()I
+    .locals 2
+    const/4 v0, 2
+    sput v0, LsameFieldNames;->a:I
+    sget-object v1, LsameFieldNames;->a:Ljava/lang/Integer;
+    const/4 v1, 0
+    if-nez v1, :fail
+    const/4 v0, 7
+    :ret
+    return v0
+    :fail
+    const/4 v0, 0
+    goto :ret
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
new file mode 100644
index 0000000..2eda850
--- /dev/null
+++ b/test/800-smali/src/Main.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+import java.lang.reflect.Modifier;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Smali excercise.
+ */
+public class Main {
+
+    private static class TestCase {
+        public TestCase(String testName, String testClass, String testMethodName, Object[] values,
+                        Throwable expectedException, Object expectedReturn) {
+            this.testName = testName;
+            this.testClass = testClass;
+            this.testMethodName = testMethodName;
+            this.values = values;
+            this.expectedException = expectedException;
+            this.expectedReturn = expectedReturn;
+        }
+
+        String testName;
+        String testClass;
+        String testMethodName;
+        Object[] values;
+        Throwable expectedException;
+        Object expectedReturn;
+    }
+
+    private List<TestCase> testCases;
+
+    public Main() {
+        // Create the test cases.
+        testCases = new LinkedList<TestCase>();
+        testCases.add(new TestCase("PackedSwitch", "PackedSwitch", "packedSwitch",
+          new Object[]{123}, null, 123));
+
+        testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100));
+        testCases.add(new TestCase("b/17978759", "B17978759", "test", null, new VerifyError(), null));
+        testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt",
+            new Object[]{100}, null, 100));
+        testCases.add(new TestCase("negLong", "negLong", "negLong", null, null, 122142L));
+        testCases.add(new TestCase("sameFieldNames", "sameFieldNames", "getInt", null, null, 7));
+        testCases.add(new TestCase("b/18380491", "B18380491ConcreteClass", "foo",
+            new Object[]{42}, null, 42));
+        testCases.add(new TestCase("invoke-super abstract", "B18380491ConcreteClass", "foo",
+            new Object[]{0}, new AbstractMethodError(), null));
+        testCases.add(new TestCase("BadCaseInOpRegRegReg", "BadCaseInOpRegRegReg", "getInt", null, null, 2));
+        testCases.add(new TestCase("CmpLong", "CmpLong", "run", null, null, 0));
+        testCases.add(new TestCase("FloatIntConstPassing", "FloatIntConstPassing", "run", null, null, 2));
+        testCases.add(new TestCase("b/18718277", "B18718277", "getInt", null, null, 0));
+        testCases.add(new TestCase("b/18800943 (1)", "B18800943_1", "n_a", null, new VerifyError(), 0));
+        testCases.add(new TestCase("b/18800943 (2)", "B18800943_2", "n_a", null, new VerifyError(), 0));
+        testCases.add(new TestCase("MoveExc", "MoveExc", "run", null, new ArithmeticException(), null));
+    }
+
+    public void runTests() {
+        for (TestCase tc : testCases) {
+            System.out.println(tc.testName);
+            try {
+                runTest(tc);
+            } catch (Exception exc) {
+                exc.printStackTrace(System.out);
+            }
+        }
+    }
+
+    private void runTest(TestCase tc) throws Exception {
+        Exception errorReturn = null;
+        try {
+            Class<?> c = Class.forName(tc.testClass);
+
+            Method[] methods = c.getDeclaredMethods();
+
+            // For simplicity we assume that test methods are not overloaded. So searching by name
+            // will give us the method we need to run.
+            Method method = null;
+            for (Method m : methods) {
+                if (m.getName().equals(tc.testMethodName)) {
+                    method = m;
+                    break;
+                }
+            }
+
+            if (method == null) {
+                errorReturn = new IllegalArgumentException("Could not find test method " +
+                                                           tc.testMethodName + " in class " +
+                                                           tc.testClass + " for test " +
+                                                           tc.testName);
+            } else {
+                Object retValue;
+                if (Modifier.isStatic(method.getModifiers())) {
+                    retValue = method.invoke(null, tc.values);
+                } else {
+                    retValue = method.invoke(method.getDeclaringClass().newInstance(), tc.values);
+                }
+                if (tc.expectedException != null) {
+                    errorReturn = new IllegalStateException("Expected an exception in test " +
+                                                            tc.testName);
+                }
+                if (tc.expectedReturn == null && retValue != null) {
+                    errorReturn = new IllegalStateException("Expected a null result in test " +
+                                                            tc.testName);
+                } else if (tc.expectedReturn != null &&
+                           (retValue == null || !tc.expectedReturn.equals(retValue))) {
+                    errorReturn = new IllegalStateException("Expected return " +
+                                                            tc.expectedReturn +
+                                                            ", but got " + retValue);
+                } else {
+                    // Expected result, do nothing.
+                }
+            }
+        } catch (Throwable exc) {
+            if (tc.expectedException == null) {
+                errorReturn = new IllegalStateException("Did not expect exception", exc);
+            } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
+                       exc.getCause().getClass().equals(tc.expectedException.getClass())) {
+                // Expected exception is wrapped in InvocationTargetException.
+            } else if (!tc.expectedException.getClass().equals(exc.getClass())) {
+                errorReturn = new IllegalStateException("Expected " +
+                                                        tc.expectedException.getClass().getName() +
+                                                        ", but got " + exc.getClass(), exc);
+            } else {
+              // Expected exception, do nothing.
+            }
+        } finally {
+            if (errorReturn != null) {
+                throw errorReturn;
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        Main main = new Main();
+
+        main.runTests();
+
+        System.out.println("Done!");
+    }
+}
diff --git a/test/801-VoidCheckCast/classes.dex b/test/801-VoidCheckCast/classes.dex
new file mode 100644
index 0000000..e6f0f02
--- /dev/null
+++ b/test/801-VoidCheckCast/classes.dex
Binary files differ
diff --git a/test/801-VoidCheckCast/expected.txt b/test/801-VoidCheckCast/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/801-VoidCheckCast/expected.txt
diff --git a/test/801-VoidCheckCast/info.txt b/test/801-VoidCheckCast/info.txt
new file mode 100644
index 0000000..422f740
--- /dev/null
+++ b/test/801-VoidCheckCast/info.txt
@@ -0,0 +1,4 @@
+A test that is only available as a DEX binary.
+
+This tests that an attempt to use check-cast with the void type doesn't
+cause the compiler to crash.
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 2d139a6..c9c0475 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -24,6 +24,7 @@
   004-ReferenceMap/stack_walk_refmap_jni.cc \
   004-StackWalk/stack_walk_jni.cc \
   004-UnsafeTest/unsafe_test.cc \
+  051-thread/thread_test.cc \
   116-nodex2oat/nodex2oat.cc \
   117-nopatchoat/nopatchoat.cc \
   118-noimage-dex2oat/noimage-dex2oat.cc
@@ -58,8 +59,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 +68,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 ae5b08f..bd9941d 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -36,9 +36,11 @@
 # $(1): the test number
 define define-build-art-run-test
   dmart_target := $(art_run_tests_dir)/art-run-tests/$(1)/touch
-$$(dmart_target): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
+$$(dmart_target): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger
 	$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
 	$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+	  SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
+	  DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
 	  $(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
 	$(hide) touch $$@
 
@@ -64,13 +66,11 @@
 ########################################################################
 # 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
+PREBUILD_TYPES :=
+ifeq ($(ART_TEST_RUN_TEST_PREBUILD),true)
+  PREBUILD_TYPES += prebuild
+endif
 ifeq ($(ART_TEST_RUN_TEST_NO_PREBUILD),true)
   PREBUILD_TYPES += no-prebuild
 endif
@@ -113,28 +113,48 @@
 ifeq ($(ART_TEST_RUN_TEST_NO_IMAGE),true)
   IMAGE_TYPES += no-image
 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)
+ifeq ($(ART_TEST_PIC_IMAGE),true)
+  IMAGE_TYPES += picimage
+endif
+PICTEST_TYPES := nopictest
+ifeq ($(ART_TEST_PIC_TEST),true)
+  PICTEST_TYPES += pictest
+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)
+ADDRESS_SIZES_HOST := $(ART_PHONY_TEST_HOST_SUFFIX)
+ifeq ($(ART_TEST_RUN_TEST_2ND_ARCH),true)
+  ADDRESS_SIZES_TARGET += $(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+  ADDRESS_SIZES_HOST += $(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+endif
 ALL_ADDRESS_SIZES := 64 32
 
 # 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 pictest, $(10), \
+                      $(foreach test, $(11), \
+                        $(foreach address_size, $(12), \
+                          test-art-$(target)-run-test-$(run-type)-$(prebuild)-$(compiler)-$(relocate)-$(trace)-$(gc)-$(jni)-$(image)-$(pictest)-$(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))
 
@@ -150,30 +170,21 @@
 
  # 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))
+        $(IMAGE_TYPES), $(PICTEST_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_TIMING_SENSITIVE_RUN_TESTS :=
 
-TEST_ART_BROKEN_RUN_TESTS := \
-  004-ThreadStress
-
-ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
-      $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
-      $(IMAGE_TYPES), $(TEST_ART_BROKEN_RUN_TESTS), $(ALL_ADDRESS_SIZES))
-
-TEST_ART_BROKEN_RUN_TESTS :=
-
 # Note 116-nodex2oat is not broken per-se it just doesn't (and isn't meant to) work with --prebuild.
 TEST_ART_BROKEN_PREBUILD_RUN_TESTS := \
   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))
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(TEST_ART_BROKEN_PREBUILD_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_BROKEN_PREBUILD_RUN_TESTS :=
@@ -182,9 +193,9 @@
   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))
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_BROKEN_NO_PREBUILD_TESTS :=
@@ -195,30 +206,37 @@
   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))
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(TEST_ART_BROKEN_NO_RELOCATE_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
 
 # Tests that are broken with GC stress.
-TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
-  004-SignalTest
+TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
 
 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))
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 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), \
-    $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES),115-native-bridge, \
+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),$(PICTEST_TYPES),115-native-bridge, \
     $(ALL_ADDRESS_SIZES))
 
+# 130-hprof dumps the heap and runs hprof-conv to check whether the file is somewhat readable. This
+# is only possible on the host.
+# TODO: Turn off all the other combinations, this is more about testing actual ART code. A gtest is
+#       very hard to write here, as (for a complete test) JDWP must be set up.
+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), \
+    $(PICTEST_TYPES),130-hprof,$(ALL_ADDRESS_SIZES))
+
 # All these tests check that we have sane behavior if we don't have a patchoat or dex2oat.
 # Therefore we shouldn't run them in situations where we actually don't have these since they
 # explicitly test for them. These all also assume we have an image.
@@ -229,26 +247,108 @@
   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))
+      $(PICTEST_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))
+      $(PICTEST_TYPES), $(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))
+      $(IMAGE_TYPES),$(PICTEST_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 \
+  051-thread \
+  115-native-bridge \
+  116-nodex2oat \
+  117-nopatchoat \
+  118-noimage-dex2oat \
+  119-noimage-patchoat \
+  131-structural-change \
+
+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), \
+      $(PICTEST_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 :=
+
+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),$(PICTEST_TYPES),$(TEST_ART_BROKEN_DEFAULT_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_DEFAULT_RUN_TESTS :=
+
+# Tests known to be broken for the optimizing compiler on 32-bit targets due to
+# inability to allocate registers for methods with long values.
+TEST_ART_BROKEN_OPTIMIZING_32_RUN_TESTS := \
+  441-checker-inliner \
+  442-checker-constant-folding \
+
+ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(PICTEST_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_32_RUN_TESTS),32)
+endif
+
+TEST_ART_BROKEN_OPTIMIZING_32_RUN_TESTS :=
+
+# Known broken tests for the arm64 optimizing compiler backend.
+TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS :=
+
+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),$(PICTEST_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS),64)
+endif
+
+TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS :=
+
+# Known broken tests for the optimizing compiler.
+TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS := \
+  099-vmdebug \ # b/18098594
+
+ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(PICTEST_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+# If ART_USE_OPTIMIZING_COMPILER is set to true, then the default core.art has been
+# compiled with the optimizing compiler.
+ifeq ($(ART_USE_OPTIMIZING_COMPILER),true)
+  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),$(PICTEST_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_OPTIMIZING_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), \
@@ -278,9 +378,13 @@
 $(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)
+# We need dex2oat and dalvikvm on the target as well as the core images (all images as we sync
+# only once).
+TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUTS)
 
 # Also need libarttest.
 TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
@@ -294,29 +398,28 @@
 TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libnativebridgetest.so
 endif
 
-# All tests require the host executables and the core images.
+# All tests require the host executables. The tests also depend on the core images, but on
+# specific version depending on the compiler.
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
   $(ART_HOST_EXECUTABLES) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libnativebridgetest$(ART_HOST_SHLIB_EXTENSION) \
-  $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
-  $(HOST_CORE_IMG_OUT)
+  $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
 
 ifneq ($(HOST_PREFER_32_BIT),true)
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libnativebridgetest$(ART_HOST_SHLIB_EXTENSION) \
-  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
-  $(2ND_HOST_CORE_IMG_OUT)
+  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
 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 picimage}-{10: pictest nopictest}-{11: test name}{12: 32 or 64}
 define define-test-art-run-test
-  run_test_options := $(addprefix --runtime-option ,$(DALVIKVM_FLAGS))
+  run_test_options :=
   prereq_rule :=
   test_groups :=
   uc_host_or_target :=
@@ -337,127 +440,175 @@
       $$(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
+    run_test_options += --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
+        run_test_options += --quick
       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)
-      test_groups += ART_RUN_TEST_$$(uc_host_or_target)_IMAGE_RULES
+    # Add the core dependency. This is required for pre-building.
+    ifeq ($(1),host)
+      prereq_rule += $(HOST_CORE_IMAGE_$(4)_no-pic_$(12))
     else
-      $$(error found $(8) expected $(IMAGE_TYPES))
+      prereq_rule += $(TARGET_CORE_IMAGE_$(4)_no-pic_$(12))
+    endif
+  else
+    ifeq ($(9),image)
+      test_groups += ART_RUN_TEST_$$(uc_host_or_target)_IMAGE_RULES
+      # Add the core dependency.
+      ifeq ($(1),host)
+        prereq_rule += $(HOST_CORE_IMAGE_$(4)_no-pic_$(12))
+      else
+        prereq_rule += $(TARGET_CORE_IMAGE_$(4)_no-pic_$(12))
+      endif
+    else
+      ifeq ($(9),picimage)
+        test_groups += ART_RUN_TEST_$$(uc_host_or_target)_PICIMAGE_RULES
+        run_test_options += --pic-image
+        ifeq ($(1),host)
+          prereq_rule += $(HOST_CORE_IMAGE_$(4)_pic_$(12))
+        else
+          prereq_rule += $(TARGET_CORE_IMAGE_$(4)_pic_$(12))
+        endif
+      else
+        $$(error found $(9) expected $(IMAGE_TYPES))
+      endif
     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)
+  ifeq ($(10),pictest)
+    run_test_options += --pic-test
+  else
+    ifeq ($(10),nopictest)
+      # Nothing to be done.
+    else
+      $$(error found $(10) expected $(PICTEST_TYPES))
+    endif
+  endif
+  # $(11) is the test name
+  test_groups += ART_RUN_TEST_$$(uc_host_or_target)_$(call name-to-var,$(11))_RULES
+  ifeq ($(12),64)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_64_RULES
     run_test_options += --64
   else
-    ifeq ($(10),32)
+    ifeq ($(12),32)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_32_RULES
     else
-      $$(error found $(10) expected $(ALL_ADDRESS_SIZES))
+      $$(error found $(12) 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)$(12)
   run_test_options := --output-path $(ART_HOST_TEST_DIR)/run-test-output/$$(run_test_rule_name) \
       $$(run_test_options)
+  ifneq ($(ART_TEST_ANDROID_ROOT),)
+    run_test_options := --android-root $(ART_TEST_ANDROID_ROOT) $$(run_test_options)
+  endif
 $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
 .PHONY: $$(run_test_rule_name)
-$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $$(prereq_rule)
+$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
 	  DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
-	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(9) \
+	    SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
+	    DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
+	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(11) \
 	      && $$(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)" && \
@@ -475,16 +626,18 @@
 
 $(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), \
+                      $(foreach pictest, $(PICTEST_TYPES), \
+                        $(eval $(call define-test-art-run-test,$(target),$(run_type),$(prebuild),$(compiler),$(relocate),$(trace),$(gc),$(jni),$(image),$(pictest),$(test),$(address_size))) \
+                  ))))))))))))
 define-test-art-run-test :=
 
 # Define a phony rule whose purpose is to test its prerequisites.
@@ -504,6 +657,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), \
@@ -557,6 +713,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 :=
@@ -569,6 +728,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..58c9564 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -17,23 +17,51 @@
 # Stop if something fails.
 set -e
 
+DX_FLAGS=""
+
+while true; do
+  if [ "x$1" = "x--dx-option" ]; then
+    shift
+    option="$1"
+    DX_FLAGS="${DX_FLAGS} $option"
+    shift
+  elif expr "x$1" : "x--" >/dev/null 2>&1; then
+    echo "unknown $0 option: $1" 1>&2
+    exit 1
+  else
+    break
+  fi
+done
+
+if [ -e classes.dex ]; then
+  zip $TEST_NAME.jar classes.dex
+  exit 0
+fi
+
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 
-if [ -r src2 ]; then
+if [ -d src2 ]; then
   ${JAVAC} -d classes `find src2 -name '*.java'`
 fi
 
 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
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+    --dump-width=1000 ${DX_FLAGS} classes
 fi
 
-if [ -r src-ex ]; then
+if [ -d 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 [ -d src-ex ]; then
   mkdir classes-ex
   ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
   if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex --dump-width=1000 classes-ex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
+      --dump-width=1000 ${DX_FLAGS} classes-ex
 
     # quick shuffle so that the stored name is "classes.dex"
     mv classes.dex classes-1.dex
@@ -43,3 +71,7 @@
     mv classes-1.dex classes.dex
   fi
 fi
+
+if [ ${NEED_DEX} = "true" ]; then
+  zip $TEST_NAME.jar classes.dex
+fi
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
deleted file mode 100755
index c020478..0000000
--- a/test/etc/host-run-test-jar
+++ /dev/null
@@ -1,237 +0,0 @@
-#!/bin/bash
-#
-# Run the code in test.jar using the host-mode virtual machine. The jar should
-# contain a top-level class named Main to run.
-
-msg() {
-    if [ "$QUIET" = "n" ]; then
-        echo "$@"
-    fi
-}
-
-DEBUGGER="n"
-PREBUILD="n"
-GDB="n"
-ISA="x86"
-INTERPRETER="n"
-VERIFY="y"
-RELOCATE="y"
-OPTIMIZE="y"
-INVOKE_WITH=""
-DEV_MODE="n"
-QUIET="n"
-FLAGS=""
-COMPILER_FLAGS=""
-BUILD_BOOT_OPT=""
-PATCHOAT=""
-DEX2OAT=""
-FALSE_BIN="/bin/false"
-HAVE_IMAGE="y"
-TIME_OUT="y"
-TIME_OUT_VALUE=5m
-exe="${ANDROID_HOST_OUT}/bin/dalvikvm32"
-main="Main"
-
-while true; do
-    if [ "x$1" = "x--quiet" ]; then
-        QUIET="y"
-        shift
-    elif [ "x$1" = "x--prebuild" ]; then
-        PREBUILD="y"
-        shift
-    elif [ "x$1" = "x--no-dex2oat" ]; then
-        DEX2OAT="-Xcompiler:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--no-patchoat" ]; then
-        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--lib" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --lib" 1>&2
-            exit 1
-        fi
-        LIB="$1"
-        if [ `uname` = "Darwin" ]; then
-            LIB=${LIB/%so/dylib}
-        fi
-        shift
-    elif [ "x$1" = "x--no-image" ]; then
-        HAVE_IMAGE="n"
-        shift
-    elif [ "x$1" = "x--boot" ]; then
-        shift
-        option="$1"
-        BOOT_OPT="$option"
-        BUILD_BOOT_OPT="--boot-image=${option#-Ximage:}"
-        shift
-    elif [ "x$1" = "x--debug" ]; then
-        DEBUGGER="y"
-        TIME_OUT="n"
-        shift
-    elif [ "x$1" = "x--gdb" ]; then
-        GDB="y"
-        DEV_MODE="y"
-        TIME_OUT="n"
-        shift
-    elif [ "x$1" = "x--invoke-with" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --invoke-with" 1>&2
-            exit 1
-        fi
-        if [ "x$INVOKE_WITH" = "x" ]; then
-            INVOKE_WITH="$1"
-        else
-            INVOKE_WITH="$INVOKE_WITH $1"
-        fi
-        shift
-    elif [ "x$1" = "x--dev" ]; then
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--interpreter" ]; then
-        INTERPRETER="y"
-        shift
-    elif [ "x$1" = "x--64" ]; then
-        ISA="x86_64"
-        exe="${ANDROID_HOST_OUT}/bin/dalvikvm64"
-        shift
-    elif [ "x$1" = "x--no-verify" ]; then
-        VERIFY="n"
-        shift
-    elif [ "x$1" = "x--no-optimize" ]; then
-        OPTIMIZE="n"
-        shift
-    elif [ "x$1" = "x--no-relocate" ]; then
-        RELOCATE="n"
-        shift
-    elif [ "x$1" = "x--relocate" ]; then
-        RELOCATE="y"
-        shift
-    elif [ "x$1" = "x-Xcompiler-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} -Xcompiler-option $option"
-        COMPILER_FLAGS="${COMPILER_FLAGS} $option"
-        shift
-    elif [ "x$1" = "x--runtime-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} $option"
-        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 [ "x$1" = "x" ] ; then
-  main="Main"
-else
-  main="$1"
-fi
-
-msg "------------------------------"
-
-export ANDROID_PRINTF_LOG=brief
-if [ "$DEV_MODE" = "y" ]; then
-    export ANDROID_LOG_TAGS='*:d'
-else
-    export ANDROID_LOG_TAGS='*:s'
-fi
-export ANDROID_DATA="$DEX_LOCATION"
-export ANDROID_ROOT="${ANDROID_HOST_OUT}"
-export LD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
-export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
-
-if [ "$DEBUGGER" = "y" ]; then
-    PORT=8000
-    msg "Waiting for jdb to connect:"
-    msg "    jdb -attach localhost:$PORT"
-    DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
-fi
-
-if [ "$GDB" = "y" ]; then
-    if [ `uname` = "Darwin" ]; then
-        gdb=lldb
-        gdbargs="-- $exe"
-        exe=
-    else
-        gdb=gdb
-        gdbargs="--args $exe"
-        # Enable for Emacs "M-x gdb" support. TODO: allow extra gdb arguments on command line.
-        # gdbargs="--annotate=3 $gdbargs"
-    fi
-fi
-
-if [ "$INTERPRETER" = "y" ]; then
-    INT_OPTS="-Xint"
-    COMPILER_FLAGS="${COMPILER_FLAGS} --compiler-filter=interpret-only"
-fi
-
-if [ "$HAVE_IMAGE" = "n" ]; then
-    # Set image to a place were there isn't one.
-    BOOT_OPT="-Ximage:/system/non-existant/core.art"
-fi
-
-if [ "$RELOCATE" = "y" ]; then
-  FLAGS="${FLAGS} -Xrelocate"
-  COMPILER_FLAGS="${COMPILER_FLAGS} --runtime-arg -Xnorelocate --include-patch-information"
-  # Run test sets a fairly draconian ulimit that we will likely blow right over
-  # since we are relocating. Get the total size of the /system/framework directory
-  # in 512 byte blocks and set it as the ulimit. This should be more than enough
-  # room.
-  if [ ! `uname` = "Darwin" ]; then  # TODO: Darwin doesn't support "du -B..."
-    ulimit -S $(du -c -B512 ${ANDROID_ROOT}/framework | tail -1 | cut -f1) || exit 1
-  fi
-else
-  FLAGS="${FLAGS} -Xnorelocate"
-  COMPILER_FLAGS="${COMPILER_FLAGS} --runtime-arg -Xnorelocate --no-include-patch-information"
-fi
-
-mkdir_cmd="mkdir -p ${DEX_LOCATION}/dalvik-cache/$ISA"
-if [ "$PREBUILD" = "y" ]; then
-  prebuild_cmd="${ANDROID_HOST_OUT}/bin/dex2oatd $COMPILER_FLAGS --instruction-set=$ISA $BUILD_BOOT_OPT --dex-file=$DEX_LOCATION/$TEST_NAME.jar --oat-file=$DEX_LOCATION/dalvik-cache/$ISA/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g")"
-else
-  prebuild_cmd="true"
-fi
-
-JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
-cmdline="$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $PATCHOAT $DEX2OAT $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar $main"
-if [ "$TIME_OUT" = "y" ]; then
-  # Add timeout command if time out is desired.
-  cmdline="timeout $TIME_OUT_VALUE $cmdline"
-fi
-if [ "$DEV_MODE" = "y" ]; then
-  if [ "$PREBUILD" = "y" ]; then
-    echo "$mkdir_cmd && $prebuild_cmd && $cmdline"
-  elif [ "$RELOCATE" = "y" ]; then
-    echo "$mkdir_cmd && $cmdline"
-  else
-    echo $cmdline
-  fi
-fi
-
-cd $ANDROID_BUILD_TOP
-
-$mkdir_cmd || exit 1
-$prebuild_cmd || exit 2
-
-if [ "$GDB" = "y" ]; then
-  # When running under gdb, we cannot do piping and grepping...
-  LD_PRELOAD=libsigchain.so $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\.$"
-  # 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
-  fi
-fi
diff --git a/test/etc/push-and-run-prebuilt-test-jar b/test/etc/push-and-run-prebuilt-test-jar
deleted file mode 100755
index 91b8a0f..0000000
--- a/test/etc/push-and-run-prebuilt-test-jar
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/bin/sh
-#
-# Run the code in test.jar on the device. The jar should contain a top-level
-# class named Main to run.
-
-msg() {
-    if [ "$QUIET" = "n" ]; then
-        echo "$@"
-    fi
-}
-
-ARCHITECTURES_32="(arm|x86|mips|none)"
-ARCHITECTURES_64="(arm64|x86_64|none)"
-ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
-RELOCATE="y"
-GDB="n"
-DEBUGGER="n"
-INTERPRETER="n"
-VERIFY="y"
-OPTIMIZE="y"
-ZYGOTE=""
-QUIET="n"
-DEV_MODE="n"
-INVOKE_WITH=""
-FLAGS=""
-TARGET_SUFFIX="32"
-GDB_TARGET_SUFFIX=""
-COMPILE_FLAGS=""
-FALSE_BIN="/system/bin/false"
-PATCHOAT=""
-DEX2OAT=""
-HAVE_IMAGE="y"
-
-while true; do
-    if [ "x$1" = "x--quiet" ]; then
-        QUIET="y"
-        shift
-    elif [ "x$1" = "x--lib" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --lib" 1>&2
-            exit 1
-        fi
-        LIB="$1"
-        shift
-    elif [ "x$1" = "x-Xcompiler-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} -Xcompiler-option $option"
-        COMPILE_FLAGS="${COMPILE_FLAGS} $option"
-        shift
-    elif [ "x$1" = "x--runtime-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} $option"
-        shift
-    elif [ "x$1" = "x--boot" ]; then
-        shift
-        BOOT_OPT="$1"
-        BUILD_BOOT_OPT="--boot-image=${1#-Ximage:}"
-        shift
-    elif [ "x$1" = "x--no-dex2oat" ]; then
-        DEX2OAT="-Xcompiler:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--no-patchoat" ]; then
-        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--relocate" ]; then
-        RELOCATE="y"
-        shift
-    elif [ "x$1" = "x--no-relocate" ]; then
-        RELOCATE="n"
-        shift
-    elif [ "x$1" = "x--no-image" ]; then
-        HAVE_IMAGE="n"
-        shift
-    elif [ "x$1" = "x--debug" ]; then
-        DEBUGGER="y"
-        shift
-    elif [ "x$1" = "x--gdb" ]; then
-        GDB="y"
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--zygote" ]; then
-        ZYGOTE="--zygote"
-        msg "Spawning from zygote"
-        shift
-    elif [ "x$1" = "x--dev" ]; then
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--interpreter" ]; then
-        INTERPRETER="y"
-        shift
-    elif [ "x$1" = "x--invoke-with" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --invoke-with" 1>&2
-            exit 1
-        fi
-        if [ "x$INVOKE_WITH" = "x" ]; then
-            INVOKE_WITH="$1"
-        else
-            INVOKE_WITH="$INVOKE_WITH $1"
-        fi
-        shift
-    elif [ "x$1" = "x--no-verify" ]; then
-        VERIFY="n"
-        shift
-    elif [ "x$1" = "x--no-optimize" ]; then
-        OPTIMIZE="n"
-        shift
-    elif [ "x$1" = "x--" ]; then
-        shift
-        break
-    elif [ "x$1" = "x--64" ]; then
-        TARGET_SUFFIX="64"
-        GDB_TARGET_SUFFIX="64"
-        ARCHITECTURES_PATTERN="${ARCHITECTURES_64}"
-        shift
-    elif expr "x$1" : "x--" >/dev/null 2>&1; then
-        echo "unknown $0 option: $1" 1>&2
-        exit 1
-    else
-        break
-    fi
-done
-
-if [ "$ZYGOTE" = "" ]; then
-    if [ "$OPTIMIZE" = "y" ]; then
-        if [ "$VERIFY" = "y" ]; then
-            DEX_OPTIMIZE="-Xdexopt:verified"
-        else
-            DEX_OPTIMIZE="-Xdexopt:all"
-        fi
-        msg "Performing optimizations"
-    else
-        DEX_OPTIMIZE="-Xdexopt:none"
-        msg "Skipping optimizations"
-    fi
-
-    if [ "$VERIFY" = "y" ]; then
-        DEX_VERIFY=""
-        msg "Performing verification"
-    else
-        DEX_VERIFY="-Xverify:none"
-        msg "Skipping verification"
-    fi
-fi
-
-msg "------------------------------"
-
-if [ "$HAVE_IMAGE" = "n" ]; then
-    BOOT_OPT="-Ximage:/system/non-existant/core.art"
-fi
-
-ARCH=$(adb shell ls -F /data/dalvik-cache | grep -Ewo "${ARCHITECTURES_PATTERN}")
-if [ x"$ARCH" = "x" ]; then
-  echo "Unable to determine architecture"
-  exit 1
-fi
-
-if [ "$QUIET" = "n" ]; then
-  adb shell rm -r $DEX_LOCATION
-  adb shell mkdir -p $DEX_LOCATION
-  adb push $TEST_NAME.jar $DEX_LOCATION
-  adb push $TEST_NAME-ex.jar $DEX_LOCATION
-else
-  adb shell rm -r $DEX_LOCATION >/dev/null 2>&1
-  adb shell mkdir -p $DEX_LOCATION >/dev/null 2>&1
-  adb push $TEST_NAME.jar $DEX_LOCATION >/dev/null 2>&1
-  adb push $TEST_NAME-ex.jar $DEX_LOCATION >/dev/null 2>&1
-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"
-  # TODO: add a separate --ddms option?
-
-  PORT=12345
-  msg "Waiting for jdb to connect:"
-  msg "    adb forward tcp:$PORT tcp:$PORT"
-  msg "    jdb -attach localhost:$PORT"
-  DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
-fi
-
-if [ "$GDB" = "y" ]; then
-    gdb="gdbserver$GDB_TARGET_SUFFIX :5039"
-    gdbargs="$exe"
-fi
-
-if [ "$INTERPRETER" = "y" ]; then
-    INT_OPTS="-Xint"
-    COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
-fi
-
-JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
-
-if [ "$RELOCATE" = "y" ]; then
-    RELOCATE_OPT="-Xrelocate"
-    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
-    COMPILE_FLAGS="${COMPILE_FLAGS} --include-patch-information"
-    FLAGS="${FLAGS} -Xcompiler-option --include-patch-information"
-else
-    RELOCATE_OPT="-Xnorelocate"
-    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
-fi
-
-# This is due to the fact this cmdline can get longer than the longest allowed
-# adb command and there is no way to get the exit status from a adb shell
-# command.
-cmdline="cd $DEX_LOCATION && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
-    mkdir -p $DEX_LOCATION/dalvik-cache/$ARCH/ && \
-    $INVOKE_WITH /system/bin/dex2oatd $COMPILE_FLAGS $BUILD_BOOT_OPT $BUILD_RELOCATE_OPT  --runtime-arg -classpath --runtime-arg $DEX_LOCATION/$TEST_NAME.jar --dex-file=$DEX_LOCATION/$TEST_NAME.jar --oat-file=$DEX_LOCATION/dalvik-cache/$ARCH/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") --instruction-set=$ARCH && \
-    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $gdbargs -XXlib:$LIB $PATCHOAT $DEX2OAT $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main $@"
-cmdfile=$(tempfile -p "cmd-" -s "-$TEST_NAME")
-echo "$cmdline" > $cmdfile
-
-if [ "$DEV_MODE" = "y" ]; then
-  echo $cmdline
-fi
-
-if [ "$QUIET" = "n" ]; then
-  adb push $cmdfile $DEX_LOCATION/cmdline.sh
-else
-  adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1
-fi
-
-adb shell sh $DEX_LOCATION/cmdline.sh
-
-rm -f $cmdfile
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
deleted file mode 100755
index e398b5d..0000000
--- a/test/etc/push-and-run-test-jar
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/bin/sh
-#
-# Run the code in test.jar on the device. The jar should contain a top-level
-# class named Main to run.
-
-msg() {
-    if [ "$QUIET" = "n" ]; then
-        echo "$@"
-    fi
-}
-
-RELOCATE="y"
-GDB="n"
-DEBUGGER="n"
-INTERPRETER="n"
-VERIFY="y"
-OPTIMIZE="y"
-ZYGOTE=""
-QUIET="n"
-DEV_MODE="n"
-INVOKE_WITH=""
-FLAGS=""
-TARGET_SUFFIX="32"
-GDB_TARGET_SUFFIX=""
-FALSE_BIN="/system/bin/false"
-PATCHOAT=""
-DEX2OAT=""
-HAVE_IMAGE="y"
-
-while true; do
-    if [ "x$1" = "x--quiet" ]; then
-        QUIET="y"
-        shift
-    elif [ "x$1" = "x--lib" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --lib" 1>&2
-            exit 1
-        fi
-        LIB="$1"
-        shift
-    elif [ "x$1" = "x-Xcompiler-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} -Xcompiler-option $option"
-        shift
-    elif [ "x$1" = "x--no-image" ]; then
-        HAVE_IMAGE="n"
-        shift
-    elif [ "x$1" = "x--no-dex2oat" ]; then
-        DEX2OAT="-Xcompiler:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--no-patchoat" ]; then
-        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
-        shift
-    elif [ "x$1" = "x--runtime-option" ]; then
-        shift
-        option="$1"
-        FLAGS="${FLAGS} $option"
-        shift
-    elif [ "x$1" = "x--boot" ]; then
-        shift
-        BOOT_OPT="$1"
-        shift
-    elif [ "x$1" = "x--debug" ]; then
-        DEBUGGER="y"
-        shift
-    elif [ "x$1" = "x--gdb" ]; then
-        GDB="y"
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--zygote" ]; then
-        ZYGOTE="--zygote"
-        msg "Spawning from zygote"
-        shift
-    elif [ "x$1" = "x--dev" ]; then
-        DEV_MODE="y"
-        shift
-    elif [ "x$1" = "x--relocate" ]; then
-        RELOCATE="y"
-        shift
-    elif [ "x$1" = "x--no-relocate" ]; then
-        RELOCATE="n"
-        shift
-    elif [ "x$1" = "x--interpreter" ]; then
-        INTERPRETER="y"
-        shift
-    elif [ "x$1" = "x--invoke-with" ]; then
-        shift
-        if [ "x$1" = "x" ]; then
-            echo "$0 missing argument to --invoke-with" 1>&2
-            exit 1
-        fi
-        if [ "x$INVOKE_WITH" = "x" ]; then
-            INVOKE_WITH="$1"
-        else
-            INVOKE_WITH="$INVOKE_WITH $1"
-        fi
-        shift
-    elif [ "x$1" = "x--no-verify" ]; then
-        VERIFY="n"
-        shift
-    elif [ "x$1" = "x--no-optimize" ]; then
-        OPTIMIZE="n"
-        shift
-    elif [ "x$1" = "x--" ]; then
-        shift
-        break
-    elif [ "x$1" = "x--64" ]; then
-        TARGET_SUFFIX="64"
-        GDB_TARGET_SUFFIX="64"
-        shift
-    elif expr "x$1" : "x--" >/dev/null 2>&1; then
-        echo "unknown $0 option: $1" 1>&2
-        exit 1
-    else
-        break
-    fi
-done
-
-if [ "$ZYGOTE" = "" ]; then
-    if [ "$OPTIMIZE" = "y" ]; then
-        if [ "$VERIFY" = "y" ]; then
-            DEX_OPTIMIZE="-Xdexopt:verified"
-        else
-            DEX_OPTIMIZE="-Xdexopt:all"
-        fi
-        msg "Performing optimizations"
-    else
-        DEX_OPTIMIZE="-Xdexopt:none"
-        msg "Skipping optimizations"
-    fi
-
-    if [ "$VERIFY" = "y" ]; then
-        DEX_VERIFY=""
-        msg "Performing verification"
-    else
-        DEX_VERIFY="-Xverify:none"
-        msg "Skipping verification"
-    fi
-fi
-
-msg "------------------------------"
-
-if [ "$HAVE_IMAGE" = "n" ]; then
-    BOOT_OPT="-Ximage:/system/non-existant/core.art"
-fi
-
-if [ "$QUIET" = "n" ]; then
-  adb shell rm -r $DEX_LOCATION
-  adb shell mkdir -p $DEX_LOCATION
-  adb push $TEST_NAME.jar $DEX_LOCATION
-  adb push $TEST_NAME-ex.jar $DEX_LOCATION
-else
-  adb shell rm -r $DEX_LOCATION >/dev/null 2>&1
-  adb shell mkdir -p $DEX_LOCATION >/dev/null 2>&1
-  adb push $TEST_NAME.jar $DEX_LOCATION >/dev/null 2>&1
-  adb push $TEST_NAME-ex.jar $DEX_LOCATION >/dev/null 2>&1
-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"
-  # TODO: add a separate --ddms option?
-
-  PORT=12345
-  msg "Waiting for jdb to connect:"
-  msg "    adb forward tcp:$PORT tcp:$PORT"
-  msg "    jdb -attach localhost:$PORT"
-  DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
-fi
-
-if [ "$GDB" = "y" ]; then
-    gdb="gdbserver$GDB_TARGET_SUFFIX :5039"
-    gdbargs="$exe"
-fi
-
-if [ "$INTERPRETER" = "y" ]; then
-    INT_OPTS="-Xint"
-fi
-
-JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
-
-if [ "$RELOCATE" = "y" ]; then
-  RELOCATE_OPT="-Xrelocate"
-  FLAGS="${FLAGS} -Xcompiler-option --include-patch-information"
-else
-  RELOCATE_OPT="-Xnorelocate"
-fi
-
-cmdline="cd $DEX_LOCATION && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
-    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $gdbargs -XXlib:$LIB $PATCHOAT $DEX2OAT $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main"
-if [ "$DEV_MODE" = "y" ]; then
-  echo $cmdline "$@"
-fi
-
-adb shell $cmdline "$@"
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
new file mode 100755
index 0000000..92b1e82
--- /dev/null
+++ b/test/etc/run-test-jar
@@ -0,0 +1,415 @@
+#!/bin/bash
+#
+# Runner for an individual run-test.
+
+msg() {
+    if [ "$QUIET" = "n" ]; then
+        echo "$@"
+    fi
+}
+
+ANDROID_ROOT="/system"
+ARCHITECTURES_32="(arm|x86|mips|none)"
+ARCHITECTURES_64="(arm64|x86_64|mips64|none)"
+ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
+BOOT_IMAGE=""
+COMPILE_FLAGS=""
+DALVIKVM="dalvikvm32"
+DEBUGGER="n"
+DEV_MODE="n"
+DEX2OAT=""
+FALSE_BIN="/system/bin/false"
+FLAGS=""
+GDB=""
+GDB_ARGS=""
+GDB_SERVER="gdbserver"
+HAVE_IMAGE="y"
+HOST="n"
+INTERPRETER="n"
+INVOKE_WITH=""
+ISA=x86
+LIBRARY_DIRECTORY="lib"
+MAIN=""
+OPTIMIZE="y"
+PATCHOAT=""
+PREBUILD="y"
+QUIET="n"
+RELOCATE="y"
+SECONDARY_DEX=""
+TIME_OUT="y"
+# Value in minutes.
+TIME_OUT_VALUE=10
+USE_GDB="n"
+USE_JVM="n"
+VERIFY="y"
+ZYGOTE=""
+DEX_VERIFY=""
+
+while true; do
+    if [ "x$1" = "x--quiet" ]; then
+        QUIET="y"
+        shift
+    elif [ "x$1" = "x--lib" ]; then
+        shift
+        if [ "x$1" = "x" ]; then
+            echo "$0 missing argument to --lib" 1>&2
+            exit 1
+        fi
+        LIB="$1"
+        shift
+    elif [ "x$1" = "x-Xcompiler-option" ]; then
+        shift
+        option="$1"
+        FLAGS="${FLAGS} -Xcompiler-option $option"
+        COMPILE_FLAGS="${COMPILE_FLAGS} $option"
+        shift
+    elif [ "x$1" = "x--runtime-option" ]; then
+        shift
+        option="$1"
+        FLAGS="${FLAGS} $option"
+        shift
+    elif [ "x$1" = "x--boot" ]; then
+        shift
+        BOOT_IMAGE="$1"
+        shift
+    elif [ "x$1" = "x--no-dex2oat" ]; then
+        DEX2OAT="-Xcompiler:${FALSE_BIN}"
+        shift
+    elif [ "x$1" = "x--no-patchoat" ]; then
+        PATCHOAT="-Xpatchoat:${FALSE_BIN}"
+        shift
+    elif [ "x$1" = "x--relocate" ]; then
+        RELOCATE="y"
+        shift
+    elif [ "x$1" = "x--no-relocate" ]; then
+        RELOCATE="n"
+        shift
+    elif [ "x$1" = "x--prebuild" ]; then
+        PREBUILD="y"
+        shift
+    elif [ "x$1" = "x--host" ]; then
+        HOST="y"
+        ANDROID_ROOT="$ANDROID_HOST_OUT"
+        shift
+    elif [ "x$1" = "x--no-prebuild" ]; then
+        PREBUILD="n"
+        shift
+    elif [ "x$1" = "x--no-image" ]; then
+        HAVE_IMAGE="n"
+        shift
+    elif [ "x$1" = "x--secondary" ]; then
+        SECONDARY_DEX=":$DEX_LOCATION/$TEST_NAME-ex.jar"
+        shift
+    elif [ "x$1" = "x--debug" ]; then
+        DEBUGGER="y"
+        TIME_OUT="n"
+        shift
+    elif [ "x$1" = "x--gdb" ]; then
+        USE_GDB="y"
+        DEV_MODE="y"
+        TIME_OUT="n"
+        shift
+    elif [ "x$1" = "x--gdb-arg" ]; then
+        shift
+        gdb_arg="$1"
+        GDB_ARGS="${GDB_ARGS} $gdb_arg"
+        shift
+    elif [ "x$1" = "x--zygote" ]; then
+        ZYGOTE="-Xzygote"
+        msg "Spawning from zygote"
+        shift
+    elif [ "x$1" = "x--dev" ]; then
+        DEV_MODE="y"
+        shift
+    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
+            echo "$0 missing argument to --invoke-with" 1>&2
+            exit 1
+        fi
+        if [ "x$INVOKE_WITH" = "x" ]; then
+            INVOKE_WITH="$1"
+        else
+            INVOKE_WITH="$INVOKE_WITH $1"
+        fi
+        shift
+    elif [ "x$1" = "x--no-verify" ]; then
+        VERIFY="n"
+        shift
+    elif [ "x$1" = "x--no-optimize" ]; then
+        OPTIMIZE="n"
+        shift
+    elif [ "x$1" = "x--android-root" ]; then
+        shift
+        ANDROID_ROOT="$1"
+        shift
+    elif [ "x$1" = "x--" ]; then
+        shift
+        break
+    elif [ "x$1" = "x--64" ]; then
+        ISA="x86_64"
+        GDB_SERVER="gdbserver64"
+        DALVIKVM="dalvikvm64"
+        LIBRARY_DIRECTORY="lib64"
+        ARCHITECTURES_PATTERN="${ARCHITECTURES_64}"
+        shift
+    elif [ "x$1" = "x--pic-test" ]; then
+        FLAGS="${FLAGS} -Xcompiler-option --compile-pic"
+        COMPILE_FLAGS="${COMPILE_FLAGS} --compile-pic"
+        shift
+    elif expr "x$1" : "x--" >/dev/null 2>&1; then
+        echo "unknown $0 option: $1" 1>&2
+        exit 1
+    else
+        break
+    fi
+done
+
+if [ "x$1" = "x" ] ; then
+  MAIN="Main"
+else
+  MAIN="$1"
+fi
+
+if [ "$ZYGOTE" = "" ]; then
+    if [ "$OPTIMIZE" = "y" ]; then
+        if [ "$VERIFY" = "y" ]; then
+            DEX_OPTIMIZE="-Xdexopt:verified"
+        else
+            DEX_OPTIMIZE="-Xdexopt:all"
+        fi
+        msg "Performing optimizations"
+    else
+        DEX_OPTIMIZE="-Xdexopt:none"
+        msg "Skipping optimizations"
+    fi
+
+    if [ "$VERIFY" = "y" ]; then
+        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 [ "$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"
+  # TODO: add a separate --ddms option?
+
+  PORT=12345
+  msg "Waiting for jdb to connect:"
+  if [ "$HOST" = "n" ]; then
+    msg "    adb forward tcp:$PORT tcp:$PORT"
+  fi
+  msg "    jdb -attach localhost:$PORT"
+  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
+    DALVIKVM_BOOT_OPT="-Ximage:/system/non-existant/core.art"
+else
+    DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}"
+fi
+
+
+if [ "$USE_GDB" = "y" ]; then
+  if [ "$HOST" = "n" ]; then
+    GDB="$GDB_SERVER :5039"
+  else
+    if [ `uname` = "Darwin" ]; then
+        GDB=lldb
+        GDB_ARGS="$GDB_ARGS -- $DALVIKVM"
+        DALVIKVM=
+    else
+        GDB=gdb
+        GDB_ARGS="$GDB_ARGS --args $DALVIKVM"
+        # Enable for Emacs "M-x gdb" support. TODO: allow extra gdb arguments on command line.
+        # gdbargs="--annotate=3 $gdbargs"
+    fi
+  fi
+fi
+
+if [ "$INTERPRETER" = "y" ]; then
+    INT_OPTS="-Xint"
+    if [ "$VERIFY" = "y" ] ; then
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
+    else
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
+      DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
+    fi
+fi
+
+JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
+
+if [ "$RELOCATE" = "y" ]; then
+    COMPILE_FLAGS="${COMPILE_FLAGS} --include-patch-information --runtime-arg -Xnorelocate"
+    FLAGS="${FLAGS} -Xrelocate -Xcompiler-option --include-patch-information"
+    if [ "$HOST" = "y" ]; then
+        # Run test sets a fairly draconian ulimit that we will likely blow right over
+        # since we are relocating. Get the total size of the /system/framework directory
+        # in 512 byte blocks and set it as the ulimit. This should be more than enough
+        # room.
+        if [ ! `uname` = "Darwin" ]; then  # TODO: Darwin doesn't support "du -B..."
+          ulimit -S $(du -c -B512 ${ANDROID_HOST_OUT}/framework | tail -1 | cut -f1) || exit 1
+        fi
+    fi
+else
+    FLAGS="$FLAGS -Xnorelocate"
+    COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
+fi
+
+if [ "$HOST" = "n" ]; then
+  ISA=$(adb shell ls -F /data/dalvik-cache | grep -Ewo "${ARCHITECTURES_PATTERN}")
+  if [ x"$ISA" = "x" ]; then
+    echo "Unable to determine architecture"
+    exit 1
+  fi
+fi
+
+dex2oat_cmdline="true"
+mkdir_cmdline="mkdir -p ${DEX_LOCATION}/dalvik-cache/$ISA"
+
+if [ "$PREBUILD" = "y" ]; then
+  dex2oat_cmdline="$INVOKE_WITH $ANDROID_ROOT/bin/dex2oatd \
+                      $COMPILE_FLAGS \
+                      --boot-image=${BOOT_IMAGE} \
+                      --dex-file=$DEX_LOCATION/$TEST_NAME.jar \
+                      --oat-file=$DEX_LOCATION/dalvik-cache/$ISA/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") \
+                      --instruction-set=$ISA"
+fi
+
+dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \
+                  $GDB_ARGS \
+                  $FLAGS \
+                  $DEX_VERIFY \
+                  -XXlib:$LIB \
+                  $PATCHOAT \
+                  $DEX2OAT \
+                  $ZYGOTE \
+                  $JNI_OPTS \
+                  $INT_OPTS \
+                  $DEBUGGER_OPTS \
+                  $DALVIKVM_BOOT_OPT \
+                  -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX $MAIN"
+
+
+if [ "$HOST" = "n" ]; then
+    adb root > /dev/null
+    adb wait-for-device
+    if [ "$QUIET" = "n" ]; then
+      adb shell rm -r $DEX_LOCATION
+      adb shell mkdir -p $DEX_LOCATION
+      adb push $TEST_NAME.jar $DEX_LOCATION
+      adb push $TEST_NAME-ex.jar $DEX_LOCATION
+    else
+      adb shell rm -r $DEX_LOCATION >/dev/null 2>&1
+      adb shell mkdir -p $DEX_LOCATION >/dev/null 2>&1
+      adb push $TEST_NAME.jar $DEX_LOCATION >/dev/null 2>&1
+      adb push $TEST_NAME-ex.jar $DEX_LOCATION >/dev/null 2>&1
+    fi
+
+    LD_LIBRARY_PATH=
+    if [ "$ANDROID_ROOT" != "/system" ]; then
+      # Current default installation is dalvikvm 64bits and dex2oat 32bits,
+      # so we can only use LD_LIBRARY_PATH when testing on a local
+      # installation.
+      LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBRARY_DIRECTORY
+    fi
+
+    # Create a script with the command. The command can get longer than the longest
+    # allowed adb command and there is no way to get the exit status from a adb shell
+    # command.
+    cmdline="cd $DEX_LOCATION && \
+             export ANDROID_DATA=$DEX_LOCATION && \
+             export DEX_LOCATION=$DEX_LOCATION && \
+             export ANDROID_ROOT=$ANDROID_ROOT && \
+             export LD_LIBRARY_PATH=$LD_LIBRARY_PATH && \
+             $mkdir_cmdline && \
+             $dex2oat_cmdline && \
+             $dalvikvm_cmdline"
+
+    cmdfile=$(tempfile -p "cmd-" -s "-$TEST_NAME")
+    echo "$cmdline" > $cmdfile
+
+    if [ "$DEV_MODE" = "y" ]; then
+      echo $cmdline
+    fi
+
+    if [ "$QUIET" = "n" ]; then
+      adb push $cmdfile $DEX_LOCATION/cmdline.sh
+    else
+      adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1
+    fi
+
+    adb shell sh $DEX_LOCATION/cmdline.sh
+
+    rm -f $cmdfile
+else
+    export ANDROID_PRINTF_LOG=brief
+    if [ "$DEV_MODE" = "y" ]; then
+        export ANDROID_LOG_TAGS='*:d'
+    else
+        export ANDROID_LOG_TAGS='*:s'
+    fi
+    export ANDROID_DATA="$DEX_LOCATION"
+    export ANDROID_ROOT="${ANDROID_ROOT}"
+    export LD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
+    export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
+    export PATH="$PATH:${ANDROID_ROOT}/bin"
+
+    cmdline="$dalvikvm_cmdline"
+
+    if [ "$TIME_OUT" = "y" ]; then
+      # Add timeout command if time out is desired.
+      #
+      # Note: We use nested timeouts. The inner timeout sends SIGRTMIN+2 (usually 36) to ART, which
+      #       will induce a full thread dump before abort. However, dumping threads might deadlock,
+      #       so the outer timeout sends the regular SIGTERM after an additional minute to ensure
+      #       termination (without dumping all threads).
+      TIME_PLUS_ONE=$(($TIME_OUT_VALUE + 1))
+      cmdline="timeout ${TIME_PLUS_ONE}m timeout -s SIGRTMIN+2 ${TIME_OUT_VALUE}m $cmdline"
+    fi
+
+    if [ "$DEV_MODE" = "y" ]; then
+      if [ "$PREBUILD" = "y" ]; then
+        echo "$mkdir_cmdline && $dex2oat_cmdline && $cmdline"
+      elif [ "$RELOCATE" = "y" ]; then
+        echo "$mkdir_cmdline && $cmdline"
+      else
+        echo $cmdline
+      fi
+    fi
+
+    cd $ANDROID_BUILD_TOP
+
+    $mkdir_cmdline || exit 1
+    $dex2oat_cmdline || exit 2
+
+    if [ "$USE_GDB" = "y" ]; then
+      # When running under gdb, we cannot do piping and grepping...
+      $cmdline "$@"
+    else
+      $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
+      fi
+    fi
+fi
diff --git a/test/run-test b/test/run-test
index b140fbf..8ef3e3e 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}" : ".* -> \(.*\)$"`
@@ -38,10 +39,11 @@
 else
   tmp_dir="${TMPDIR}/$USER/${test_dir}"
 fi
+checker="${progdir}/../tools/checker.py"
 
 export JAVA="java"
 export JAVAC="javac -g"
-export RUN="${progdir}/etc/push-and-run-test-jar"
+export RUN="${progdir}/etc/run-test-jar"
 export DEX_LOCATION=/data/run-test/${test_dir}
 export NEED_DEX="true"
 
@@ -55,6 +57,16 @@
   export JASMIN="jasmin"
 fi
 
+# If smali was not set by the environment variable, assume it is in the path.
+if [ -z "$SMALI" ]; then
+  export SMALI="smali"
+fi
+
+# If dexmerger was not set by the environment variable, assume it is in the path.
+if [ -z "$DXMERGER" ]; then
+  export DXMERGER="dexmerger"
+fi
+
 
 info="info.txt"
 build="build"
@@ -63,8 +75,10 @@
 check_cmd="check"
 output="output.txt"
 build_output="build-output.txt"
+cfg_output="cfg-output.txt"
 lib="libartd.so"
 run_args="--quiet"
+build_args=""
 
 prebuild_mode="yes"
 target_mode="yes"
@@ -84,16 +98,22 @@
 have_dex2oat="yes"
 have_patchoat="yes"
 have_image="yes"
+image_suffix=""
+pic_image_suffix=""
+android_root="/system"
 
 while true; do
     if [ "x$1" = "x--host" ]; then
         target_mode="no"
         DEX_LOCATION=$tmp_dir
+        run_args="${run_args} --host"
         shift
     elif [ "x$1" = "x--jvm" ]; then
         target_mode="no"
         runtime="jvm"
+        prebuild_mode="no"
         NEED_DEX="false"
+        run_args="${run_args} --jvm"
         shift
     elif [ "x$1" = "x-O" ]; then
         lib="libart.so"
@@ -111,6 +131,12 @@
     elif [ "x$1" = "x--no-image" ]; then
         have_image="no"
         shift
+    elif [ "x$1" = "x--pic-image" ]; then
+        pic_image_suffix="-pic"
+        shift
+    elif [ "x$1" = "x--pic-test" ]; then
+        run_args="${run_args} --pic-test"
+        shift
     elif [ "x$1" = "x--relocate" ]; then
         relocate="yes"
         shift
@@ -118,9 +144,11 @@
         relocate="no"
         shift
     elif [ "x$1" = "x--prebuild" ]; then
+        run_args="${run_args} --prebuild"
         prebuild_mode="yes"
         shift;
     elif [ "x$1" = "x--no-prebuild" ]; then
+        run_args="${run_args} --no-prebuild"
         prebuild_mode="no"
         shift;
     elif [ "x$1" = "x--gcverify" ]; then
@@ -146,6 +174,11 @@
         option="$1"
         run_args="${run_args} --runtime-option $option"
         shift
+    elif [ "x$1" = "x--gdb-arg" ]; then
+        shift
+        gdb_arg="$1"
+        run_args="${run_args} --gdb-arg $gdb_arg"
+        shift
     elif [ "x$1" = "x--debug" ]; then
         run_args="${run_args} --debug"
         shift
@@ -158,6 +191,14 @@
         shift
     elif [ "x$1" = "x--interpreter" ]; then
         run_args="${run_args} --interpreter"
+        image_suffix="-interpreter"
+        shift
+    elif [ "x$1" = "x--optimizing" ]; then
+        run_args="${run_args} -Xcompiler-option --compiler-backend=Optimizing"
+        image_suffix="-optimizing"
+        shift
+    elif [ "x$1" = "x--quick" ]; then
+        run_args="${run_args} -Xcompiler-option --compiler-backend=Quick"
         shift
     elif [ "x$1" = "x--no-verify" ]; then
         run_args="${run_args} --no-verify"
@@ -194,6 +235,16 @@
             break
         fi
         shift
+    elif [ "x$1" = "x--android-root" ]; then
+        shift
+        if [ "x$1" = "x" ]; then
+            echo "$0 missing argument to --android-root" 1>&2
+            usage="yes"
+            break
+        fi
+        android_root="$1"
+        run_args="${run_args} --android-root $1"
+        shift
     elif [ "x$1" = "x--update" ]; then
         update_mode="yes"
         shift
@@ -210,6 +261,9 @@
     elif [ "x$1" = "x--always-clean" ]; then
         always_clean="yes"
         shift
+    elif [ "x$1" = "x--dex2oat-swap" ]; then
+        run_args="${run_args} --dex2oat-swap"
+        shift
     elif expr "x$1" : "x--" >/dev/null 2>&1; then
         echo "unknown $0 option: $1" 1>&2
         usage="yes"
@@ -230,7 +284,8 @@
 mkdir -p $tmp_dir
 
 if [ "$basic_verify" = "true" ]; then
-  run_args="${run_args} --runtime-option -Xgc:preverify --runtime-option -Xgc:postverify"
+  # Set HspaceCompactForOOMMinIntervalMs to zero to run hspace compaction for OOM more frequently in tests.
+  run_args="${run_args} --runtime-option -Xgc:preverify --runtime-option -Xgc:postverify --runtime-option -XX:HspaceCompactForOOMMinIntervalMs=0"
 fi
 if [ "$gc_verify" = "true" ]; then
   run_args="${run_args} --runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc"
@@ -246,7 +301,7 @@
 # Try to map the suffix64 flag and what we find in ${ANDROID_PRODUCT_OUT}/data/art-test to an architecture name.
 function guess_arch_name() {
     grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
-    grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64)$'`
+    grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'`
     if [ "x${suffix64}" = "x64" ]; then
         target_arch_name=${grep64bit}
     else
@@ -256,20 +311,10 @@
 
 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;
         fi
-    else
-        RUN="${progdir}/etc/host-run-test-jar"
-        if [ "$prebuild_mode" = "yes" ]; then
-            run_args="${run_args} --prebuild"
-        fi
-    fi
-else
-    if [ "$prebuild_mode" = "yes" ]; then
-        RUN="${progdir}/etc/push-and-run-prebuilt-test-jar"
     fi
 fi
 
@@ -295,19 +340,19 @@
     fi
 elif [ "$runtime" = "art" ]; then
     if [ "$target_mode" = "no" ]; then
-	# ANDROID_BUILD_TOP and ANDROID_HOST_OUT are not set in a build environment.
+        # ANDROID_BUILD_TOP and ANDROID_HOST_OUT are not set in a build environment.
         if [ -z "$ANDROID_BUILD_TOP" ]; then
-	    export ANDROID_BUILD_TOP=$oldwd
+            export ANDROID_BUILD_TOP=$oldwd
         fi
         if [ -z "$ANDROID_HOST_OUT" ]; then
-	    export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
+            export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
         fi
-        run_args="${run_args} --boot -Ximage:${ANDROID_HOST_OUT}/framework/core.art"
+        run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}${pic_image_suffix}.art"
         run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}"
     else
         guess_arch_name
         run_args="${run_args} --runtime-option -Djava.library.path=/data/art-test/${target_arch_name}"
-        run_args="${run_args} --boot -Ximage:/data/art-test/core.art"
+        run_args="${run_args} --boot /data/art-test/core${image_suffix}${pic_image_suffix}.art"
     fi
     if [ "$relocate" = "yes" ]; then
       run_args="${run_args} --relocate"
@@ -325,7 +370,7 @@
         framework="${ANDROID_HOST_OUT}/framework"
         bpath_suffix="-hostdex"
     else
-        framework="/system/framework"
+        framework="${android_root}/framework"
         bpath_suffix=""
     fi
     # TODO If the target was compiled WITH_DEXPREOPT=true then these tests will
@@ -378,39 +423,43 @@
         echo '  Omitting the test name or specifying "-" will use the' \
              "current directory."
         echo "  Runtime Options:"
-        echo "    -O                   Run non-debug rather than debug build (off by default)."
-        echo "    -Xcompiler-option    Pass an option to the compiler."
-        echo "    --runtime-option     Pass an option to the runtime."
-        echo "    --debug              Wait for a debugger to attach."
-        echo "    --gdb                Run under gdb; incompatible with some tests."
-        echo "    --build-only         Build test files only (off by default)."
-        echo "    --interpreter        Enable interpreter only mode (off by default)."
-        echo "    --no-verify          Turn off verification (on by default)."
-        echo "    --no-optimize        Turn off optimization (on by default)."
-        echo "    --no-precise         Turn off precise GC (on by default)."
-        echo "    --zygote             Spawn the process from the Zygote." \
+        echo "    -O                    Run non-debug rather than debug build (off by default)."
+        echo "    -Xcompiler-option     Pass an option to the compiler."
+        echo "    --runtime-option      Pass an option to the runtime."
+        echo "    --debug               Wait for a debugger to attach."
+        echo "    --gdb                 Run under gdb; incompatible with some tests."
+        echo "    --build-only          Build test files only (off by default)."
+        echo "    --interpreter         Enable interpreter only mode (off by default)."
+        echo "    --optimizing          Enable optimizing compiler (off by default)."
+        echo "    --quick               Use Quick compiler (default)."
+        echo "    --no-verify           Turn off verification (on by default)."
+        echo "    --no-optimize         Turn off optimization (on by default)."
+        echo "    --no-precise          Turn off precise GC (on by default)."
+        echo "    --zygote              Spawn the process from the Zygote." \
              "If used, then the"
-        echo "                         other runtime options are ignored."
-        echo "    --no-dex2oat         Run as though dex2oat was failing."
-        echo "    --no-patchoat        Run as though patchoat was failing."
-        echo "    --prebuild           Run dex2oat on the files before starting test. (default)"
-        echo "    --no-prebuild        Do not run dex2oat on the files before starting"
-        echo "                         the test."
-        echo "    --relocate           Force the use of relocating in the test, making"
-        echo "                         the image and oat files be relocated to a random"
-        echo "                         address before running. (default)"
-        echo "    --no-relocate        Force the use of no relocating in the test"
-        echo "    --host               Use the host-mode virtual machine."
-        echo "    --invoke-with        Pass --invoke-with option to runtime."
-        echo "    --dalvik             Use Dalvik (off by default)."
-        echo "    --jvm                Use a host-local RI virtual machine."
-        echo "    --output-path [path] Location where to store the build" \
+        echo "                          other runtime options are ignored."
+        echo "    --no-dex2oat          Run as though dex2oat was failing."
+        echo "    --no-patchoat         Run as though patchoat was failing."
+        echo "    --prebuild            Run dex2oat on the files before starting test. (default)"
+        echo "    --no-prebuild         Do not run dex2oat on the files before starting"
+        echo "                          the test."
+        echo "    --relocate            Force the use of relocating in the test, making"
+        echo "                          the image and oat files be relocated to a random"
+        echo "                          address before running. (default)"
+        echo "    --no-relocate         Force the use of no relocating in the test"
+        echo "    --host                Use the host-mode virtual machine."
+        echo "    --invoke-with         Pass --invoke-with option to runtime."
+        echo "    --dalvik              Use Dalvik (off by default)."
+        echo "    --jvm                 Use a host-local RI virtual machine."
+        echo "    --output-path [path]  Location where to store the build" \
              "files."
-        echo "    --64                 Run the test in 64-bit mode"
-        echo "    --trace              Run with method tracing"
-        echo "    --gcstress           Run with gc stress testing"
-        echo "    --gcverify           Run with gc verification"
-        echo "    --always-clean       Delete the test files even if the test fails."
+        echo "    --64                  Run the test in 64-bit mode"
+        echo "    --trace               Run with method tracing"
+        echo "    --gcstress            Run with gc stress testing"
+        echo "    --gcverify            Run with gc verification"
+        echo "    --always-clean        Delete the test files even if the test fails."
+        echo "    --android-root [path] The path on target for the android root. (/system by default)."
+        echo "    --dex2oat-swap       Use a dex2oat swap file."
     ) 1>&2
     exit 1
 fi
@@ -457,23 +506,37 @@
 
 export TEST_NAME=`basename ${test_dir}`
 
+# Tests named '<number>-checker-*' will also have their CFGs verified with
+# Checker when compiled with Optimizing on host.
+if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then
+  # Build Checker DEX files without dx's optimizations so the input to dex2oat
+  # better resembles the Java source. We always build the DEX the same way, even
+  # if Checker is not invoked and the test only runs the program.
+  build_args="${build_args} --dx-option --no-optimize"
+
+  if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$target_mode" = "no" ]; then
+    run_checker="yes"
+    run_args="${run_args} -Xcompiler-option --dump-cfg=$tmp_dir/$cfg_output \
+                          -Xcompiler-option -j1"
+  fi
+fi
+
 # To cause tests to fail fast, limit the file sizes created by dx, dex2oat and ART output to 2MB.
 file_size_limit=2048
 if echo "$test_dir" | grep 089; then
   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"
 fi
 
 good="no"
+good_build="yes"
+good_run="yes"
 if [ "$dev_mode" = "yes" ]; then
-    "./${build}" 2>&1
+    "./${build}" $build_args 2>&1
     build_exit="$?"
     echo "build exit status: $build_exit" 1>&2
     if [ "$build_exit" = '0' ]; then
@@ -486,11 +549,14 @@
         fi
     fi
 elif [ "$update_mode" = "yes" ]; then
-    "./${build}" >"$build_output" 2>&1
+    "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
+        if [ "$run_checker" = "yes" ]; then
+          "$checker" -q "$cfg_output" "$tmp_dir" >> "$output" 2>&1
+        fi
         sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}"
         good="yes"
     else
@@ -499,7 +565,7 @@
     fi
 elif [ "$build_only" = "yes" ]; then
     good="yes"
-    "./${build}" >"$build_output" 2>&1
+    "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" '!=' '0' ]; then
         cp "$build_output" "$output"
@@ -514,22 +580,46 @@
     find $tmp_dir -mindepth 1  ! -regex ".*/\(.*jar\|$output\|$expected\)" | xargs rm -rf
     exit 0
 else
-    "./${build}" >"$build_output" 2>&1
+    "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
+        run_exit="$?"
+        if [ "$run_exit" != "0" ]; then
+            echo "run exit status: $run_exit" 1>&2
+            good_run="no"
+        elif [ "$run_checker" = "yes" ]; then
+            "$checker" -q "$cfg_output" "$tmp_dir" >> "$output" 2>&1
+            checker_exit="$?"
+            if [ "$checker_exit" != "0" ]; then
+                echo "checker exit status: $checker_exit" 1>&2
+                good_run="no"
+            else
+                good_run="yes"
+            fi
+        else
+            good_run="yes"
+        fi
     else
+        good_build="no"
         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"
+        max_name_length=$(getconf NAME_MAX ${tmp_dir})
+        echo "Max filename (NAME_MAX): ${max_name_length}" >> "$output"
+        max_path_length=$(getconf PATH_MAX ${tmp_dir})
+        echo "Max pathlength (PATH_MAX): ${max_path_length}" >> "$output"
     fi
     ./$check_cmd "$expected" "$output"
     if [ "$?" = "0" ]; then
-        # output == expected
-        good="yes"
-        echo "${test_dir}: succeeded!" 1>&2
+        if [ "$good_build" = "no" -o "$good_run" = "yes" ]; then
+          # output == expected
+          good="yes"
+          echo "${test_dir}: succeeded!" 1>&2
+        fi
     fi
 fi
 
@@ -540,7 +630,7 @@
         echo '#################### info'
         cat "${td_info}" | sed 's/^/# /g'
         echo '#################### diffs'
-        diff --strip-trailing-cr -u "$expected" "$output" | tail -n 500
+        diff --strip-trailing-cr -u "$expected" "$output" | tail -n 2000
         echo '####################'
         echo ' '
     fi
diff --git a/tools/analyze-init-failures.py b/tools/analyze-init-failures.py
new file mode 100755
index 0000000..f803ea3
--- /dev/null
+++ b/tools/analyze-init-failures.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Analyzes the dump of initialization failures and creates a Graphviz dot file
+   representing dependencies."""
+
+import codecs
+import os
+import re
+import string
+import sys
+
+
+_CLASS_RE = re.compile(r'^L(.*);$')
+_ERROR_LINE_RE = re.compile(r'^java.lang.InternalError: (.*)')
+_STACK_LINE_RE = re.compile(r'^\s*at\s[^\s]*\s([^\s]*)')
+
+def Confused(filename, line_number, line):
+  sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line))
+  raise Exception("giving up!")
+  sys.exit(1)
+
+
+def ProcessFile(filename):
+  lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+  it = iter(lines)
+
+  class_fail_class = {}
+  class_fail_method = {}
+  root_failures = set()
+  root_errors = {}
+
+  while True:
+    try:
+      # We start with a class descriptor.
+      raw_line = it.next()
+      m = _CLASS_RE.search(raw_line)
+      # print(raw_line)
+      if m is None:
+        continue
+      # Found a class.
+      failed_clazz = m.group(1).replace('/','.')
+      # print('Is a class %s' % failed_clazz)
+      # The error line should be next.
+      raw_line = it.next()
+      m = _ERROR_LINE_RE.search(raw_line)
+      # print(raw_line)
+      if m is None:
+        Confused(filename, -1, raw_line)
+        continue
+      # Found an error line.
+      error = m.group(1)
+      # print('Is an error %s' % error)
+      # Get the top of the stack
+      raw_line = it.next()
+      m = _STACK_LINE_RE.search(raw_line)
+      if m is None:
+        continue
+      # Found a stack line. Get the method.
+      method = m.group(1)
+      # print('Is a stack element %s' % method)
+      (left_of_paren,paren,right_of_paren) = method.partition('(')
+      (root_err_class,dot,root_method_name) = left_of_paren.rpartition('.')
+      # print('Error class %s' % err_class)
+      # print('Error method %s' % method_name)
+      # Record the root error.
+      root_failures.add(root_err_class)
+      # Parse all the trace elements to find the "immediate" cause.
+      immediate_class = root_err_class
+      immediate_method = root_method_name
+      root_errors[root_err_class] = error
+      # Now go "up" the stack.
+      while True:
+        raw_line = it.next()
+        m = _STACK_LINE_RE.search(raw_line)
+        if m is None:
+          break  # Nothing more to see here.
+        method = m.group(1)
+        (left_of_paren,paren,right_of_paren) = method.partition('(')
+        (err_class,dot,err_method_name) = left_of_paren.rpartition('.')
+        if err_method_name == "<clinit>":
+          # A class initializer is on the stack...
+          class_fail_class[err_class] = immediate_class
+          class_fail_method[err_class] = immediate_method
+          immediate_class = err_class
+          immediate_method = err_method_name
+    except StopIteration:
+      # print('Done')
+      break  # Done
+
+  # Assign IDs.
+  fail_sources = set(class_fail_class.values());
+  all_classes = fail_sources | set(class_fail_class.keys())
+  i = 0
+  class_index = {}
+  for clazz in all_classes:
+    class_index[clazz] = i
+    i = i + 1
+
+  # Now create the nodes.
+  for (r_class, r_id) in class_index.items():
+    error_string = ''
+    if r_class in root_failures:
+      error_string = ',color=Red,tooltip="' + root_errors[r_class] + '",URL="' + root_errors[r_class] + '"'
+    print('  n%d [shape=box,label="%s"%s];' % (r_id, r_class, error_string))
+
+  # Some space.
+  print('')
+
+  # Connections.
+  for (failed_class,error_class) in class_fail_class.items():
+    print('  n%d -> n%d;' % (class_index[failed_class], class_index[error_class]))
+
+
+def main():
+  print('digraph {')
+  print('  overlap=false;')
+  print('  splines=true;')
+  ProcessFile(sys.argv[1])
+  print('}')
+  sys.exit(0)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/art b/tools/art
index 0103071..2408f9f 100644
--- a/tools/art
+++ b/tools/art
@@ -1,5 +1,3 @@
-#!/bin/bash
-#
 # Copyright (C) 2011 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,6 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# This script is used on host and device. It uses a common subset
+# shell dialect that should work on the host (e.g. bash), and
+# Android (e.g. mksh).
+
 function follow_links() {
   if [ z"$BASH_SOURCE" != z ]; then
     file="$BASH_SOURCE"
@@ -28,7 +30,8 @@
 }
 
 function find_libdir() {
-  if [ "$(readlink "$ANDROID_ROOT/bin/$DALVIKVM")" = "dalvikvm64" ]; then
+  # Use realpath instead of readlink because Android does not have a readlink.
+  if [ "$(realpath "$ANDROID_ROOT/bin/$DALVIKVM")" = "$(realpath "$ANDROID_ROOT/bin/dalvikvm64")" ]; then
     echo "lib64"
   else
     echo "lib"
@@ -53,6 +56,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
@@ -64,18 +73,42 @@
 PROG_NAME="$(follow_links)"
 PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
 ANDROID_ROOT=$PROG_DIR/..
-ANDROID_DATA=$PWD/android-data$$
 LIBDIR=$(find_libdir)
 LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBDIR
 
-mkdir -p $ANDROID_DATA/dalvik-cache/{arm,arm64,x86,x86_64}
+DELETE_ANDROID_DATA=false
+# If ANDROID_DATA is the system ANDROID_DATA or is not set, use our own,
+# and ensure we delete it at the end.
+if [ "$ANDROID_DATA" = "/data" ] || [ "$ANDROID_DATA" = "" ]; then
+  ANDROID_DATA=$PWD/android-data$$
+  mkdir -p $ANDROID_DATA/dalvik-cache/{arm,arm64,x86,x86_64}
+  DELETE_ANDROID_DATA=true
+fi
+
+if [ z"$PERF" != z ]; then
+  invoke_with="perf record -o $ANDROID_DATA/perf.data -e cycles:u $invoke_with"
+fi
+
 ANDROID_DATA=$ANDROID_DATA \
   ANDROID_ROOT=$ANDROID_ROOT \
   LD_LIBRARY_PATH=$LD_LIBRARY_PATH \
   $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
+  if [ "$DELETE_ANDROID_DATA" = "true" ]; then
+    rm -rf $ANDROID_DATA
+  fi
+fi
+
 exit $EXIT_STATUS
diff --git a/tools/checker.py b/tools/checker.py
new file mode 100755
index 0000000..55f015e
--- /dev/null
+++ b/tools/checker.py
@@ -0,0 +1,767 @@
+#!/usr/bin/env python2
+#
+# 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.
+
+
+# Checker is a testing tool which compiles a given test file and compares the
+# state of the control-flow graph before and after each optimization pass
+# against a set of assertions specified alongside the tests.
+#
+# Tests are written in Java, turned into DEX and compiled with the Optimizing
+# compiler. "Check lines" are assertions formatted as comments of the Java file.
+# They begin with prefix 'CHECK' followed by a pattern that the engine attempts
+# to match in the compiler-generated output.
+#
+# Assertions are tested in groups which correspond to the individual compiler
+# passes. Each group of check lines therefore must start with a 'CHECK-START'
+# header which specifies the output group it should be tested against. The group
+# name must exactly match one of the groups recognized in the output (they can
+# be listed with the '--list-groups' command-line flag).
+#
+# Matching of check lines is carried out in the order of appearance in the
+# source file. There are three types of check lines:
+#  - CHECK:     Must match an output line which appears in the output group
+#               later than lines matched against any preceeding checks. Output
+#               lines must therefore match the check lines in the same order.
+#               These are referred to as "in-order" checks in the code.
+#  - CHECK-DAG: Must match an output line which appears in the output group
+#               later than lines matched against any preceeding in-order checks.
+#               In other words, the order of output lines does not matter
+#               between consecutive DAG checks.
+#  - CHECK-NOT: Must not match any output line which appears in the output group
+#               later than lines matched against any preceeding checks and
+#               earlier than lines matched against any subsequent checks.
+#               Surrounding non-negative checks (or boundaries of the group)
+#               therefore create a scope within which the assertion is verified.
+#
+# Check-line patterns are treated as plain text rather than regular expressions
+# but are whitespace agnostic.
+#
+# Actual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If
+# curly brackets need to be used inside the body of the regex, they need to be
+# enclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse
+# the invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'.
+#
+# Regex patterns can be named and referenced later. A new variable is defined
+# with '[[name:regex]]' and can be referenced with '[[name]]'. Variables are
+# only valid within the scope of the defining group. Within a group they cannot
+# be redefined or used undefined.
+#
+# Example:
+#   The following assertions can be placed in a Java source file:
+#
+#   // CHECK-START: int MyClass.MyMethod() constant_folding (after)
+#   // CHECK:         [[ID:i[0-9]+]] IntConstant {{11|22}}
+#   // CHECK:                        Return [ [[ID]] ]
+#
+#   The engine will attempt to match the check lines against the output of the
+#   group named on the first line. Together they verify that the CFG after
+#   constant folding returns an integer constant with value either 11 or 22.
+#
+
+from __future__ import print_function
+import argparse
+import os
+import re
+import shutil
+import sys
+import tempfile
+
+class Logger(object):
+
+  class Level(object):
+    NoOutput, Error, Info = range(3)
+
+  class Color(object):
+    Default, Blue, Gray, Purple, Red = range(5)
+
+    @staticmethod
+    def terminalCode(color, out=sys.stdout):
+      if not out.isatty():
+        return ''
+      elif color == Logger.Color.Blue:
+        return '\033[94m'
+      elif color == Logger.Color.Gray:
+        return '\033[37m'
+      elif color == Logger.Color.Purple:
+        return '\033[95m'
+      elif color == Logger.Color.Red:
+        return '\033[91m'
+      else:
+        return '\033[0m'
+
+  Verbosity = Level.Info
+
+  @staticmethod
+  def log(text, level=Level.Info, color=Color.Default, newLine=True, out=sys.stdout):
+    if level <= Logger.Verbosity:
+      text = Logger.Color.terminalCode(color, out) + text + \
+             Logger.Color.terminalCode(Logger.Color.Default, out)
+      if newLine:
+        print(text, flush=True, file=out)
+      else:
+        print(text, end="", flush=True, file=out)
+
+  @staticmethod
+  def fail(msg, file=None, line=-1):
+    location = ""
+    if file:
+      location += file + ":"
+    if line > 0:
+      location += str(line) + ":"
+    if location:
+      location += " "
+
+    Logger.log(location, Logger.Level.Error, color=Logger.Color.Gray, newLine=False, out=sys.stderr)
+    Logger.log("error: ", Logger.Level.Error, color=Logger.Color.Red, newLine=False, out=sys.stderr)
+    Logger.log(msg, Logger.Level.Error, out=sys.stderr)
+    sys.exit(1)
+
+  @staticmethod
+  def startTest(name):
+    Logger.log("TEST ", color=Logger.Color.Purple, newLine=False)
+    Logger.log(name + "... ", newLine=False)
+
+  @staticmethod
+  def testPassed():
+    Logger.log("PASS", color=Logger.Color.Blue)
+
+  @staticmethod
+  def testFailed(msg, file=None, line=-1):
+    Logger.log("FAIL", color=Logger.Color.Red)
+    Logger.fail(msg, file, line)
+
+class CommonEqualityMixin:
+  """Mixin for class equality as equality of the fields."""
+  def __eq__(self, other):
+    return (isinstance(other, self.__class__)
+           and self.__dict__ == other.__dict__)
+
+  def __ne__(self, other):
+    return not self.__eq__(other)
+
+  def __repr__(self):
+    return "<%s: %s>" % (type(self).__name__, str(self.__dict__))
+
+
+class CheckElement(CommonEqualityMixin):
+  """Single element of the check line."""
+
+  class Variant(object):
+    """Supported language constructs."""
+    Text, Pattern, VarRef, VarDef = range(4)
+
+  rStartOptional = r"("
+  rEndOptional = r")?"
+
+  rName = r"([a-zA-Z][a-zA-Z0-9]*)"
+  rRegex = r"(.+?)"
+  rPatternStartSym = r"(\{\{)"
+  rPatternEndSym = r"(\}\})"
+  rVariableStartSym = r"(\[\[)"
+  rVariableEndSym = r"(\]\])"
+  rVariableSeparator = r"(:)"
+
+  regexPattern = rPatternStartSym + rRegex + rPatternEndSym
+  regexVariable = rVariableStartSym + \
+                    rName + \
+                    (rStartOptional + rVariableSeparator + rRegex + rEndOptional) + \
+                  rVariableEndSym
+
+  def __init__(self, variant, name, pattern):
+    self.variant = variant
+    self.name = name
+    self.pattern = pattern
+
+  @staticmethod
+  def parseText(text):
+    return CheckElement(CheckElement.Variant.Text, None, re.escape(text))
+
+  @staticmethod
+  def parsePattern(patternElem):
+    return CheckElement(CheckElement.Variant.Pattern, None, patternElem[2:-2])
+
+  @staticmethod
+  def parseVariable(varElem):
+    colonPos = varElem.find(":")
+    if colonPos == -1:
+      # Variable reference
+      name = varElem[2:-2]
+      return CheckElement(CheckElement.Variant.VarRef, name, None)
+    else:
+      # Variable definition
+      name = varElem[2:colonPos]
+      body = varElem[colonPos+1:-2]
+      return CheckElement(CheckElement.Variant.VarDef, name, body)
+
+class CheckLine(CommonEqualityMixin):
+  """Representation of a single assertion in the check file formed of one or
+     more regex elements. Matching against an output line is successful only
+     if all regex elements can be matched in the given order."""
+
+  class Variant(object):
+    """Supported types of assertions."""
+    InOrder, DAG, Not = range(3)
+
+  def __init__(self, content, variant=Variant.InOrder, fileName=None, lineNo=-1):
+    self.fileName = fileName
+    self.lineNo = lineNo
+    self.content = content.strip()
+
+    self.variant = variant
+    self.lineParts = self.__parse(self.content)
+    if not self.lineParts:
+      Logger.fail("Empty check line", self.fileName, self.lineNo)
+
+    if self.variant == CheckLine.Variant.Not:
+      for elem in self.lineParts:
+        if elem.variant == CheckElement.Variant.VarDef:
+          Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
+
+  def __eq__(self, other):
+    return (isinstance(other, self.__class__) and
+            self.variant == other.variant and
+            self.lineParts == other.lineParts)
+
+  # Returns True if the given Match object was at the beginning of the line.
+  def __isMatchAtStart(self, match):
+    return (match is not None) and (match.start() == 0)
+
+  # Takes in a list of Match objects and returns the minimal start point among
+  # them. If there aren't any successful matches it returns the length of
+  # the searched string.
+  def __firstMatch(self, matches, string):
+    starts = map(lambda m: len(string) if m is None else m.start(), matches)
+    return min(starts)
+
+  # This method parses the content of a check line stripped of the initial
+  # comment symbol and the CHECK keyword.
+  def __parse(self, line):
+    lineParts = []
+    # Loop as long as there is something to parse.
+    while line:
+      # Search for the nearest occurrence of the special markers.
+      matchWhitespace = re.search(r"\s+", line)
+      matchPattern = re.search(CheckElement.regexPattern, line)
+      matchVariable = re.search(CheckElement.regexVariable, line)
+
+      # If one of the above was identified at the current position, extract them
+      # from the line, parse them and add to the list of line parts.
+      if self.__isMatchAtStart(matchWhitespace):
+        # We want to be whitespace-agnostic so whenever a check line contains
+        # a whitespace, we add a regex pattern for an arbitrary non-zero number
+        # of whitespaces.
+        line = line[matchWhitespace.end():]
+        lineParts.append(CheckElement.parsePattern(r"{{\s+}}"))
+      elif self.__isMatchAtStart(matchPattern):
+        pattern = line[0:matchPattern.end()]
+        line = line[matchPattern.end():]
+        lineParts.append(CheckElement.parsePattern(pattern))
+      elif self.__isMatchAtStart(matchVariable):
+        var = line[0:matchVariable.end()]
+        line = line[matchVariable.end():]
+        lineParts.append(CheckElement.parseVariable(var))
+      else:
+        # If we're not currently looking at a special marker, this is a plain
+        # text match all the way until the first special marker (or the end
+        # of the line).
+        firstMatch = self.__firstMatch([ matchWhitespace, matchPattern, matchVariable ], line)
+        text = line[0:firstMatch]
+        line = line[firstMatch:]
+        lineParts.append(CheckElement.parseText(text))
+    return lineParts
+
+  # Returns the regex pattern to be matched in the output line. Variable
+  # references are substituted with their current values provided in the
+  # 'varState' argument.
+  # An exception is raised if a referenced variable is undefined.
+  def __generatePattern(self, linePart, varState):
+    if linePart.variant == CheckElement.Variant.VarRef:
+      try:
+        return re.escape(varState[linePart.name])
+      except KeyError:
+        Logger.testFailed("Use of undefined variable \"" + linePart.name + "\"",
+                          self.fileName, self.lineNo)
+    else:
+      return linePart.pattern
+
+  # Attempts to match the check line against a line from the output file with
+  # the given initial variable values. It returns the new variable state if
+  # successful and None otherwise.
+  def match(self, outputLine, initialVarState):
+    initialSearchFrom = 0
+    initialPattern = self.__generatePattern(self.lineParts[0], initialVarState)
+    while True:
+      # Search for the first element on the regex parts list. This will mark
+      # the point on the line from which we will attempt to match the rest of
+      # the check pattern. If this iteration produces only a partial match,
+      # the next iteration will start searching further in the output.
+      firstMatch = re.search(initialPattern, outputLine[initialSearchFrom:])
+      if firstMatch is None:
+        return None
+      matchStart = initialSearchFrom + firstMatch.start()
+      initialSearchFrom += firstMatch.start() + 1
+
+      # Do the full matching on a shadow copy of the variable state. If the
+      # matching fails half-way, we will not need to revert the state.
+      varState = dict(initialVarState)
+
+      # Now try to parse all of the parts of the check line in the right order.
+      # Variable values are updated on-the-fly, meaning that a variable can
+      # be referenced immediately after its definition.
+      fullyMatched = True
+      for part in self.lineParts:
+        pattern = self.__generatePattern(part, varState)
+        match = re.match(pattern, outputLine[matchStart:])
+        if match is None:
+          fullyMatched = False
+          break
+        matchEnd = matchStart + match.end()
+        if part.variant == CheckElement.Variant.VarDef:
+          if part.name in varState:
+            Logger.testFailed("Multiple definitions of variable \"" + part.name + "\"",
+                              self.fileName, self.lineNo)
+          varState[part.name] = outputLine[matchStart:matchEnd]
+        matchStart = matchEnd
+
+      # Return the new variable state if all parts were successfully matched.
+      # Otherwise loop and try to find another start point on the same line.
+      if fullyMatched:
+        return varState
+
+
+class CheckGroup(CommonEqualityMixin):
+  """Represents a named collection of check lines which are to be matched
+     against an output group of the same name."""
+
+  def __init__(self, name, lines, fileName=None, lineNo=-1):
+    self.fileName = fileName
+    self.lineNo = lineNo
+
+    if not name:
+      Logger.fail("Check group does not have a name", self.fileName, self.lineNo)
+    if not lines:
+      Logger.fail("Check group does not have a body", self.fileName, self.lineNo)
+
+    self.name = name
+    self.lines = lines
+
+  def __eq__(self, other):
+    return (isinstance(other, self.__class__) and
+            self.name == other.name and
+            self.lines == other.lines)
+
+  def __headAndTail(self, list):
+    return list[0], list[1:]
+
+  # Splits a list of check lines at index 'i' such that lines[i] is the first
+  # element whose variant is not equal to the given parameter.
+  def __splitByVariant(self, lines, variant):
+    i = 0
+    while i < len(lines) and lines[i].variant == variant:
+      i += 1
+    return lines[:i], lines[i:]
+
+  # Extracts the first sequence of check lines which are independent of each
+  # other's match location, i.e. either consecutive DAG lines or a single
+  # InOrder line. Any Not lines preceeding this sequence are also extracted.
+  def __nextIndependentChecks(self, checkLines):
+    notChecks, checkLines = self.__splitByVariant(checkLines, CheckLine.Variant.Not)
+    if not checkLines:
+      return notChecks, [], []
+
+    head, tail = self.__headAndTail(checkLines)
+    if head.variant == CheckLine.Variant.InOrder:
+      return notChecks, [head], tail
+    else:
+      assert head.variant == CheckLine.Variant.DAG
+      independentChecks, checkLines = self.__splitByVariant(checkLines, CheckLine.Variant.DAG)
+      return notChecks, independentChecks, checkLines
+
+  # If successful, returns the line number of the first output line matching the
+  # check line and the updated variable state. Otherwise returns -1 and None,
+  # respectively. The 'lineFilter' parameter can be used to supply a list of
+  # line numbers (counting from 1) which should be skipped.
+  def __findFirstMatch(self, checkLine, outputLines, startLineNo, lineFilter, varState):
+    matchLineNo = startLineNo
+    for outputLine in outputLines:
+      if matchLineNo not in lineFilter:
+        newVarState = checkLine.match(outputLine, varState)
+        if newVarState is not None:
+          return matchLineNo, newVarState
+      matchLineNo += 1
+    return -1, None
+
+  # Matches the given positive check lines against the output in order of
+  # appearance. Variable state is propagated but the scope of the search remains
+  # the same for all checks. Each output line can only be matched once.
+  # If all check lines are matched, the resulting variable state is returned
+  # together with the remaining output. The function also returns output lines
+  # which appear before either of the matched lines so they can be tested
+  # against Not checks.
+  def __matchIndependentChecks(self, checkLines, outputLines, startLineNo, varState):
+    # If no checks are provided, skip over the entire output.
+    if not checkLines:
+      return outputLines, [], startLineNo + len(outputLines), varState
+
+    # Keep track of which lines have been matched.
+    matchedLines = []
+
+    # Find first unused output line which matches each check line.
+    for checkLine in checkLines:
+      matchLineNo, varState = \
+        self.__findFirstMatch(checkLine, outputLines, startLineNo, matchedLines, varState)
+      if varState is None:
+        Logger.testFailed("Could not match check line \"" + checkLine.content + "\" " +
+                          "starting from output line " + str(startLineNo),
+                          self.fileName, checkLine.lineNo)
+      matchedLines.append(matchLineNo)
+
+    # Return new variable state and the output lines which lie outside the
+    # match locations of this independent group.
+    minMatchLineNo = min(matchedLines)
+    maxMatchLineNo = max(matchedLines)
+    preceedingLines = outputLines[:minMatchLineNo - startLineNo]
+    remainingLines = outputLines[maxMatchLineNo - startLineNo + 1:]
+    return preceedingLines, remainingLines, maxMatchLineNo + 1, varState
+
+  # Makes sure that the given check lines do not match any of the given output
+  # lines. Variable state does not change.
+  def __matchNotLines(self, checkLines, outputLines, startLineNo, varState):
+    for checkLine in checkLines:
+      assert checkLine.variant == CheckLine.Variant.Not
+      matchLineNo, matchVarState = \
+        self.__findFirstMatch(checkLine, outputLines, startLineNo, [], varState)
+      if matchVarState is not None:
+        Logger.testFailed("CHECK-NOT line \"" + checkLine.content + "\" matches output line " + \
+                          str(matchLineNo), self.fileName, checkLine.lineNo)
+
+  # Matches the check lines in this group against an output group. It is
+  # responsible for running the checks in the right order and scope, and
+  # for propagating the variable state between the check lines.
+  def match(self, outputGroup):
+    varState = {}
+    checkLines = self.lines
+    outputLines = outputGroup.body
+    startLineNo = outputGroup.lineNo
+
+    while checkLines:
+      # Extract the next sequence of location-independent checks to be matched.
+      notChecks, independentChecks, checkLines = self.__nextIndependentChecks(checkLines)
+
+      # Match the independent checks.
+      notOutput, outputLines, newStartLineNo, newVarState = \
+        self.__matchIndependentChecks(independentChecks, outputLines, startLineNo, varState)
+
+      # Run the Not checks against the output lines which lie between the last
+      # two independent groups or the bounds of the output.
+      self.__matchNotLines(notChecks, notOutput, startLineNo, varState)
+
+      # Update variable state.
+      startLineNo = newStartLineNo
+      varState = newVarState
+
+class OutputGroup(CommonEqualityMixin):
+  """Represents a named part of the test output against which a check group of
+     the same name is to be matched."""
+
+  def __init__(self, name, body, fileName=None, lineNo=-1):
+    if not name:
+      Logger.fail("Output group does not have a name", fileName, lineNo)
+    if not body:
+      Logger.fail("Output group does not have a body", fileName, lineNo)
+
+    self.name = name
+    self.body = body
+    self.lineNo = lineNo
+
+  def __eq__(self, other):
+    return (isinstance(other, self.__class__) and
+            self.name == other.name and
+            self.body == other.body)
+
+
+class FileSplitMixin(object):
+  """Mixin for representing text files which need to be split into smaller
+     chunks before being parsed."""
+
+  def _parseStream(self, stream):
+    lineNo = 0
+    allGroups = []
+    currentGroup = None
+
+    for line in stream:
+      lineNo += 1
+      line = line.strip()
+      if not line:
+        continue
+
+      # Let the child class process the line and return information about it.
+      # The _processLine method can modify the content of the line (or delete it
+      # entirely) and specify whether it starts a new group.
+      processedLine, newGroupName = self._processLine(line, lineNo)
+      if newGroupName is not None:
+        currentGroup = (newGroupName, [], lineNo)
+        allGroups.append(currentGroup)
+      if processedLine is not None:
+        if currentGroup is not None:
+          currentGroup[1].append(processedLine)
+        else:
+          self._exceptionLineOutsideGroup(line, lineNo)
+
+    # Finally, take the generated line groups and let the child class process
+    # each one before storing the final outcome.
+    return list(map(lambda group: self._processGroup(group[0], group[1], group[2]), allGroups))
+
+
+class CheckFile(FileSplitMixin):
+  """Collection of check groups extracted from the input test file."""
+
+  def __init__(self, prefix, checkStream, fileName=None):
+    self.fileName = fileName
+    self.prefix = prefix
+    self.groups = self._parseStream(checkStream)
+
+  # Attempts to parse a check line. The regex searches for a comment symbol
+  # followed by the CHECK keyword, given attribute and a colon at the very
+  # beginning of the line. Whitespaces are ignored.
+  def _extractLine(self, prefix, line):
+    rIgnoreWhitespace = r"\s*"
+    rCommentSymbols = [r"//", r"#"]
+    regexPrefix = rIgnoreWhitespace + \
+                  r"(" + r"|".join(rCommentSymbols) + r")" + \
+                  rIgnoreWhitespace + \
+                  prefix + r":"
+
+    # The 'match' function succeeds only if the pattern is matched at the
+    # beginning of the line.
+    match = re.match(regexPrefix, line)
+    if match is not None:
+      return line[match.end():].strip()
+    else:
+      return None
+
+  # This function is invoked on each line of the check file and returns a pair
+  # which instructs the parser how the line should be handled. If the line is to
+  # be included in the current check group, it is returned in the first value.
+  # If the line starts a new check group, the name of the group is returned in
+  # the second value.
+  def _processLine(self, line, lineNo):
+    # Lines beginning with 'CHECK-START' start a new check group.
+    startLine = self._extractLine(self.prefix + "-START", line)
+    if startLine is not None:
+      return None, startLine
+
+    # Lines starting only with 'CHECK' are matched in order.
+    plainLine = self._extractLine(self.prefix, line)
+    if plainLine is not None:
+      return (plainLine, CheckLine.Variant.InOrder, lineNo), None
+
+    # 'CHECK-DAG' lines are no-order assertions.
+    dagLine = self._extractLine(self.prefix + "-DAG", line)
+    if dagLine is not None:
+      return (dagLine, CheckLine.Variant.DAG, lineNo), None
+
+    # 'CHECK-NOT' lines are no-order negative assertions.
+    notLine = self._extractLine(self.prefix + "-NOT", line)
+    if notLine is not None:
+      return (notLine, CheckLine.Variant.Not, lineNo), None
+
+    # Other lines are ignored.
+    return None, None
+
+  def _exceptionLineOutsideGroup(self, line, lineNo):
+    Logger.fail("Check line not inside a group", self.fileName, lineNo)
+
+  # Constructs a check group from the parser-collected check lines.
+  def _processGroup(self, name, lines, lineNo):
+    checkLines = list(map(lambda line: CheckLine(line[0], line[1], self.fileName, line[2]), lines))
+    return CheckGroup(name, checkLines, self.fileName, lineNo)
+
+  def match(self, outputFile):
+    for checkGroup in self.groups:
+      # TODO: Currently does not handle multiple occurrences of the same group
+      # name, e.g. when a pass is run multiple times. It will always try to
+      # match a check group against the first output group of the same name.
+      outputGroup = outputFile.findGroup(checkGroup.name)
+      if outputGroup is None:
+        Logger.fail("Group \"" + checkGroup.name + "\" not found in the output",
+                    self.fileName, checkGroup.lineNo)
+      Logger.startTest(checkGroup.name)
+      checkGroup.match(outputGroup)
+      Logger.testPassed()
+
+
+class OutputFile(FileSplitMixin):
+  """Representation of the output generated by the test and split into groups
+     within which the checks are performed.
+
+     C1visualizer format is parsed with a state machine which differentiates
+     between the 'compilation' and 'cfg' blocks. The former marks the beginning
+     of a method. It is parsed for the method's name but otherwise ignored. Each
+     subsequent CFG block represents one stage of the compilation pipeline and
+     is parsed into an output group named "<method name> <pass name>".
+     """
+
+  class ParsingState:
+    OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4)
+
+  def __init__(self, outputStream, fileName=None):
+    self.fileName = fileName
+
+    # Initialize the state machine
+    self.lastMethodName = None
+    self.state = OutputFile.ParsingState.OutsideBlock
+    self.groups = self._parseStream(outputStream)
+
+  # This function is invoked on each line of the output file and returns a pair
+  # which instructs the parser how the line should be handled. If the line is to
+  # be included in the current group, it is returned in the first value. If the
+  # line starts a new output group, the name of the group is returned in the
+  # second value.
+  def _processLine(self, line, lineNo):
+    if self.state == OutputFile.ParsingState.StartingCfgBlock:
+      # Previous line started a new 'cfg' block which means that this one must
+      # contain the name of the pass (this is enforced by C1visualizer).
+      if re.match("name\s+\"[^\"]+\"", line):
+        # Extract the pass name, prepend it with the name of the method and
+        # return as the beginning of a new group.
+        self.state = OutputFile.ParsingState.InsideCfgBlock
+        return (None, self.lastMethodName + " " + line.split("\"")[1])
+      else:
+        Logger.fail("Expected output group name", self.fileName, lineNo)
+
+    elif self.state == OutputFile.ParsingState.InsideCfgBlock:
+      if line == "end_cfg":
+        self.state = OutputFile.ParsingState.OutsideBlock
+        return (None, None)
+      else:
+        return (line, None)
+
+    elif self.state == OutputFile.ParsingState.InsideCompilationBlock:
+      # Search for the method's name. Format: method "<name>"
+      if re.match("method\s+\"[^\"]*\"", line):
+        methodName = line.split("\"")[1].strip()
+        if not methodName:
+          Logger.fail("Empty method name in output", self.fileName, lineNo)
+        self.lastMethodName = methodName
+      elif line == "end_compilation":
+        self.state = OutputFile.ParsingState.OutsideBlock
+      return (None, None)
+
+    else:
+      assert self.state == OutputFile.ParsingState.OutsideBlock
+      if line == "begin_cfg":
+        # The line starts a new group but we'll wait until the next line from
+        # which we can extract the name of the pass.
+        if self.lastMethodName is None:
+          Logger.fail("Expected method header", self.fileName, lineNo)
+        self.state = OutputFile.ParsingState.StartingCfgBlock
+        return (None, None)
+      elif line == "begin_compilation":
+        self.state = OutputFile.ParsingState.InsideCompilationBlock
+        return (None, None)
+      else:
+        Logger.fail("Output line not inside a group", self.fileName, lineNo)
+
+  # Constructs an output group from the parser-collected output lines.
+  def _processGroup(self, name, lines, lineNo):
+    return OutputGroup(name, lines, self.fileName, lineNo + 1)
+
+  def findGroup(self, name):
+    for group in self.groups:
+      if group.name == name:
+        return group
+    return None
+
+
+def ParseArguments():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("tested_file",
+                      help="text file the checks should be verified against")
+  parser.add_argument("source_path", nargs="?",
+                      help="path to file/folder with checking annotations")
+  parser.add_argument("--check-prefix", dest="check_prefix", default="CHECK", metavar="PREFIX",
+                      help="prefix of checks in the test files (default: CHECK)")
+  parser.add_argument("--list-groups", dest="list_groups", action="store_true",
+                      help="print a list of all groups found in the tested file")
+  parser.add_argument("--dump-group", dest="dump_group", metavar="GROUP",
+                      help="print the contents of an output group")
+  parser.add_argument("-q", "--quiet", action="store_true",
+                      help="print only errors")
+  return parser.parse_args()
+
+
+def ListGroups(outputFilename):
+  outputFile = OutputFile(open(outputFilename, "r"))
+  for group in outputFile.groups:
+    Logger.log(group.name)
+
+
+def DumpGroup(outputFilename, groupName):
+  outputFile = OutputFile(open(outputFilename, "r"))
+  group = outputFile.findGroup(groupName)
+  if group:
+    lineNo = group.lineNo
+    maxLineNo = lineNo + len(group.body)
+    lenLineNo = len(str(maxLineNo)) + 2
+    for line in group.body:
+      Logger.log((str(lineNo) + ":").ljust(lenLineNo) + line)
+      lineNo += 1
+  else:
+    Logger.fail("Group \"" + groupName + "\" not found in the output")
+
+
+# Returns a list of files to scan for check annotations in the given path. Path
+# to a file is returned as a single-element list, directories are recursively
+# traversed and all '.java' files returned.
+def FindCheckFiles(path):
+  if not path:
+    Logger.fail("No source path provided")
+  elif os.path.isfile(path):
+    return [ path ]
+  elif os.path.isdir(path):
+    foundFiles = []
+    for root, dirs, files in os.walk(path):
+      for file in files:
+        if os.path.splitext(file)[1] == ".java":
+          foundFiles.append(os.path.join(root, file))
+    return foundFiles
+  else:
+    Logger.fail("Source path \"" + path + "\" not found")
+
+
+def RunChecks(checkPrefix, checkPath, outputFilename):
+  outputBaseName = os.path.basename(outputFilename)
+  outputFile = OutputFile(open(outputFilename, "r"), outputBaseName)
+
+  for checkFilename in FindCheckFiles(checkPath):
+    checkBaseName = os.path.basename(checkFilename)
+    checkFile = CheckFile(checkPrefix, open(checkFilename, "r"), checkBaseName)
+    checkFile.match(outputFile)
+
+
+if __name__ == "__main__":
+  args = ParseArguments()
+
+  if args.quiet:
+    Logger.Verbosity = Logger.Level.Error
+
+  if args.list_groups:
+    ListGroups(args.tested_file)
+  elif args.dump_group:
+    DumpGroup(args.tested_file, args.dump_group)
+  else:
+    RunChecks(args.check_prefix, args.source_path, args.tested_file)
diff --git a/tools/checker_test.py b/tools/checker_test.py
new file mode 100755
index 0000000..18152b5
--- /dev/null
+++ b/tools/checker_test.py
@@ -0,0 +1,465 @@
+#!/usr/bin/env python2
+#
+# 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.
+
+# This is a test file which exercises all feautres supported by the domain-
+# specific markup language implemented by Checker.
+
+import checker
+import io
+import unittest
+
+# The parent type of exception expected to be thrown by Checker during tests.
+# It must be specific enough to not cover exceptions thrown due to actual flaws
+# in Checker.
+CheckerException = SystemExit
+
+
+class TestCheckFile_PrefixExtraction(unittest.TestCase):
+  def __tryParse(self, string):
+    checkFile = checker.CheckFile(None, [])
+    return checkFile._extractLine("CHECK", string)
+
+  def test_InvalidFormat(self):
+    self.assertIsNone(self.__tryParse("CHECK"))
+    self.assertIsNone(self.__tryParse(":CHECK"))
+    self.assertIsNone(self.__tryParse("CHECK:"))
+    self.assertIsNone(self.__tryParse("//CHECK"))
+    self.assertIsNone(self.__tryParse("#CHECK"))
+
+    self.assertIsNotNone(self.__tryParse("//CHECK:foo"))
+    self.assertIsNotNone(self.__tryParse("#CHECK:bar"))
+
+  def test_InvalidLabel(self):
+    self.assertIsNone(self.__tryParse("//ACHECK:foo"))
+    self.assertIsNone(self.__tryParse("#ACHECK:foo"))
+
+  def test_NotFirstOnTheLine(self):
+    self.assertIsNone(self.__tryParse("A// CHECK: foo"))
+    self.assertIsNone(self.__tryParse("A # CHECK: foo"))
+    self.assertIsNone(self.__tryParse("// // CHECK: foo"))
+    self.assertIsNone(self.__tryParse("# # CHECK: foo"))
+
+  def test_WhitespaceAgnostic(self):
+    self.assertIsNotNone(self.__tryParse("  //CHECK: foo"))
+    self.assertIsNotNone(self.__tryParse("//  CHECK: foo"))
+    self.assertIsNotNone(self.__tryParse("    //CHECK: foo"))
+    self.assertIsNotNone(self.__tryParse("//    CHECK: foo"))
+
+
+class TestCheckLine_Parse(unittest.TestCase):
+  def __getRegex(self, checkLine):
+    return "".join(map(lambda x: "(" + x.pattern + ")", checkLine.lineParts))
+
+  def __tryParse(self, string):
+    return checker.CheckLine(string)
+
+  def __parsesTo(self, string, expected):
+    self.assertEqual(expected, self.__getRegex(self.__tryParse(string)))
+
+  def __tryParseNot(self, string):
+    return checker.CheckLine(string, checker.CheckLine.Variant.Not)
+
+  def __parsesPattern(self, string, pattern):
+    line = self.__tryParse(string)
+    self.assertEqual(1, len(line.lineParts))
+    self.assertEqual(checker.CheckElement.Variant.Pattern, line.lineParts[0].variant)
+    self.assertEqual(pattern, line.lineParts[0].pattern)
+
+  def __parsesVarRef(self, string, name):
+    line = self.__tryParse(string)
+    self.assertEqual(1, len(line.lineParts))
+    self.assertEqual(checker.CheckElement.Variant.VarRef, line.lineParts[0].variant)
+    self.assertEqual(name, line.lineParts[0].name)
+
+  def __parsesVarDef(self, string, name, body):
+    line = self.__tryParse(string)
+    self.assertEqual(1, len(line.lineParts))
+    self.assertEqual(checker.CheckElement.Variant.VarDef, line.lineParts[0].variant)
+    self.assertEqual(name, line.lineParts[0].name)
+    self.assertEqual(body, line.lineParts[0].pattern)
+
+  def __doesNotParse(self, string, partType):
+    line = self.__tryParse(string)
+    self.assertEqual(1, len(line.lineParts))
+    self.assertNotEqual(partType, line.lineParts[0].variant)
+
+  # Test that individual parts of the line are recognized
+
+  def test_TextOnly(self):
+    self.__parsesTo("foo", "(foo)")
+    self.__parsesTo("  foo  ", "(foo)")
+    self.__parsesTo("f$o^o", "(f\$o\^o)")
+
+  def test_TextWithWhitespace(self):
+    self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
+    self.__parsesTo("foo   bar", "(foo)(\s+)(bar)")
+
+  def test_RegexOnly(self):
+    self.__parsesPattern("{{a?b.c}}", "a?b.c")
+
+  def test_VarRefOnly(self):
+    self.__parsesVarRef("[[ABC]]", "ABC")
+
+  def test_VarDefOnly(self):
+    self.__parsesVarDef("[[ABC:a?b.c]]", "ABC", "a?b.c")
+
+  def test_TextWithRegex(self):
+    self.__parsesTo("foo{{abc}}bar", "(foo)(abc)(bar)")
+
+  def test_TextWithVar(self):
+    self.__parsesTo("foo[[ABC:abc]]bar", "(foo)(abc)(bar)")
+
+  def test_PlainWithRegexAndWhitespaces(self):
+    self.__parsesTo("foo {{abc}}bar", "(foo)(\s+)(abc)(bar)")
+    self.__parsesTo("foo{{abc}} bar", "(foo)(abc)(\s+)(bar)")
+    self.__parsesTo("foo {{abc}} bar", "(foo)(\s+)(abc)(\s+)(bar)")
+
+  def test_PlainWithVarAndWhitespaces(self):
+    self.__parsesTo("foo [[ABC:abc]]bar", "(foo)(\s+)(abc)(bar)")
+    self.__parsesTo("foo[[ABC:abc]] bar", "(foo)(abc)(\s+)(bar)")
+    self.__parsesTo("foo [[ABC:abc]] bar", "(foo)(\s+)(abc)(\s+)(bar)")
+
+  def test_AllKinds(self):
+    self.__parsesTo("foo [[ABC:abc]]{{def}}bar", "(foo)(\s+)(abc)(def)(bar)")
+    self.__parsesTo("foo[[ABC:abc]] {{def}}bar", "(foo)(abc)(\s+)(def)(bar)")
+    self.__parsesTo("foo [[ABC:abc]] {{def}} bar", "(foo)(\s+)(abc)(\s+)(def)(\s+)(bar)")
+
+  # Test that variables and patterns are parsed correctly
+
+  def test_ValidPattern(self):
+    self.__parsesPattern("{{abc}}", "abc")
+    self.__parsesPattern("{{a[b]c}}", "a[b]c")
+    self.__parsesPattern("{{(a{bc})}}", "(a{bc})")
+
+  def test_ValidRef(self):
+    self.__parsesVarRef("[[ABC]]", "ABC")
+    self.__parsesVarRef("[[A1BC2]]", "A1BC2")
+
+  def test_ValidDef(self):
+    self.__parsesVarDef("[[ABC:abc]]", "ABC", "abc")
+    self.__parsesVarDef("[[ABC:ab:c]]", "ABC", "ab:c")
+    self.__parsesVarDef("[[ABC:a[b]c]]", "ABC", "a[b]c")
+    self.__parsesVarDef("[[ABC:(a[bc])]]", "ABC", "(a[bc])")
+
+  def test_Empty(self):
+    self.__doesNotParse("{{}}", checker.CheckElement.Variant.Pattern)
+    self.__doesNotParse("[[]]", checker.CheckElement.Variant.VarRef)
+    self.__doesNotParse("[[:]]", checker.CheckElement.Variant.VarDef)
+
+  def test_InvalidVarName(self):
+    self.__doesNotParse("[[0ABC]]", checker.CheckElement.Variant.VarRef)
+    self.__doesNotParse("[[AB=C]]", checker.CheckElement.Variant.VarRef)
+    self.__doesNotParse("[[ABC=]]", checker.CheckElement.Variant.VarRef)
+    self.__doesNotParse("[[0ABC:abc]]", checker.CheckElement.Variant.VarDef)
+    self.__doesNotParse("[[AB=C:abc]]", checker.CheckElement.Variant.VarDef)
+    self.__doesNotParse("[[ABC=:abc]]", checker.CheckElement.Variant.VarDef)
+
+  def test_BodyMatchNotGreedy(self):
+    self.__parsesTo("{{abc}}{{def}}", "(abc)(def)")
+    self.__parsesTo("[[ABC:abc]][[DEF:def]]", "(abc)(def)")
+
+  def test_NoVarDefsInNotChecks(self):
+    with self.assertRaises(CheckerException):
+      self.__tryParseNot("[[ABC:abc]]")
+
+class TestCheckLine_Match(unittest.TestCase):
+  def __matchSingle(self, checkString, outputString, varState={}):
+    checkLine = checker.CheckLine(checkString)
+    newVarState = checkLine.match(outputString, varState)
+    self.assertIsNotNone(newVarState)
+    return newVarState
+
+  def __notMatchSingle(self, checkString, outputString, varState={}):
+    checkLine = checker.CheckLine(checkString)
+    self.assertIsNone(checkLine.match(outputString, varState))
+
+  def test_TextAndWhitespace(self):
+    self.__matchSingle("foo", "foo")
+    self.__matchSingle("foo", "XfooX")
+    self.__matchSingle("foo", "foo bar")
+    self.__notMatchSingle("foo", "zoo")
+
+    self.__matchSingle("foo bar", "foo   bar")
+    self.__matchSingle("foo bar", "abc foo bar def")
+    self.__matchSingle("foo bar", "foo foo bar bar")
+    self.__notMatchSingle("foo bar", "foo abc bar")
+
+  def test_Pattern(self):
+    self.__matchSingle("foo{{A|B}}bar", "fooAbar")
+    self.__matchSingle("foo{{A|B}}bar", "fooBbar")
+    self.__notMatchSingle("foo{{A|B}}bar", "fooCbar")
+
+  def test_VariableReference(self):
+    self.__matchSingle("foo[[X]]bar", "foobar", {"X": ""})
+    self.__matchSingle("foo[[X]]bar", "fooAbar", {"X": "A"})
+    self.__matchSingle("foo[[X]]bar", "fooBbar", {"X": "B"})
+    self.__notMatchSingle("foo[[X]]bar", "foobar", {"X": "A"})
+    self.__notMatchSingle("foo[[X]]bar", "foo bar", {"X": "A"})
+    with self.assertRaises(CheckerException):
+      self.__matchSingle("foo[[X]]bar", "foobar", {})
+
+  def test_VariableDefinition(self):
+    self.__matchSingle("foo[[X:A|B]]bar", "fooAbar")
+    self.__matchSingle("foo[[X:A|B]]bar", "fooBbar")
+    self.__notMatchSingle("foo[[X:A|B]]bar", "fooCbar")
+
+    env = self.__matchSingle("foo[[X:A.*B]]bar", "fooABbar", {})
+    self.assertEqual(env, {"X": "AB"})
+    env = self.__matchSingle("foo[[X:A.*B]]bar", "fooAxxBbar", {})
+    self.assertEqual(env, {"X": "AxxB"})
+
+    self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarAbaz")
+    self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooBbarBbaz")
+    self.__notMatchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarBbaz")
+
+  def test_NoVariableRedefinition(self):
+    with self.assertRaises(CheckerException):
+      self.__matchSingle("[[X:...]][[X]][[X:...]][[X]]", "foofoobarbar")
+
+  def test_EnvNotChangedOnPartialMatch(self):
+    env = {"Y": "foo"}
+    self.__notMatchSingle("[[X:A]]bar", "Abaz", env)
+    self.assertFalse("X" in env.keys())
+
+  def test_VariableContentEscaped(self):
+    self.__matchSingle("[[X:..]]foo[[X]]", ".*foo.*")
+    self.__notMatchSingle("[[X:..]]foo[[X]]", ".*fooAAAA")
+
+
+CheckVariant = checker.CheckLine.Variant
+
+def prepareSingleCheck(line):
+  if isinstance(line, str):
+    return checker.CheckLine(line)
+  else:
+    return checker.CheckLine(line[0], line[1])
+
+def prepareChecks(lines):
+  if isinstance(lines, str):
+    lines = lines.splitlines()
+  return list(map(lambda line: prepareSingleCheck(line), lines))
+
+
+class TestCheckGroup_Match(unittest.TestCase):
+  def __matchMulti(self, checkLines, outputString):
+    checkGroup = checker.CheckGroup("MyGroup", prepareChecks(checkLines))
+    outputGroup = checker.OutputGroup("MyGroup", outputString.splitlines())
+    return checkGroup.match(outputGroup)
+
+  def __notMatchMulti(self, checkString, outputString):
+    with self.assertRaises(CheckerException):
+      self.__matchMulti(checkString, outputString)
+
+  def test_TextAndPattern(self):
+    self.__matchMulti("""foo bar
+                         abc {{def}}""",
+                      """foo bar
+                         abc def""");
+    self.__matchMulti("""foo bar
+                         abc {{de.}}""",
+                      """=======
+                         foo bar
+                         =======
+                         abc de#
+                         =======""");
+    self.__notMatchMulti("""//XYZ: foo bar
+                            //XYZ: abc {{def}}""",
+                         """=======
+                            foo bar
+                            =======
+                            abc de#
+                            =======""");
+
+  def test_Variables(self):
+    self.__matchMulti("""foo[[X:.]]bar
+                         abc[[X]]def""",
+                      """foo bar
+                         abc def""");
+    self.__matchMulti("""foo[[X:([0-9]+)]]bar
+                         abc[[X]]def
+                         ### [[X]] ###""",
+                      """foo1234bar
+                         abc1234def
+                         ### 1234 ###""");
+
+  def test_Ordering(self):
+    self.__matchMulti([("foo", CheckVariant.InOrder),
+                       ("bar", CheckVariant.InOrder)],
+                      """foo
+                         bar""")
+    self.__notMatchMulti([("foo", CheckVariant.InOrder),
+                          ("bar", CheckVariant.InOrder)],
+                         """bar
+                            foo""")
+    self.__matchMulti([("abc", CheckVariant.DAG),
+                       ("def", CheckVariant.DAG)],
+                      """abc
+                         def""")
+    self.__matchMulti([("abc", CheckVariant.DAG),
+                       ("def", CheckVariant.DAG)],
+                      """def
+                         abc""")
+    self.__matchMulti([("foo", CheckVariant.InOrder),
+                       ("abc", CheckVariant.DAG),
+                       ("def", CheckVariant.DAG),
+                       ("bar", CheckVariant.InOrder)],
+                      """foo
+                         def
+                         abc
+                         bar""")
+    self.__notMatchMulti([("foo", CheckVariant.InOrder),
+                          ("abc", CheckVariant.DAG),
+                          ("def", CheckVariant.DAG),
+                          ("bar", CheckVariant.InOrder)],
+                         """foo
+                            abc
+                            bar""")
+    self.__notMatchMulti([("foo", CheckVariant.InOrder),
+                          ("abc", CheckVariant.DAG),
+                          ("def", CheckVariant.DAG),
+                          ("bar", CheckVariant.InOrder)],
+                         """foo
+                            def
+                            bar""")
+
+  def test_NotAssertions(self):
+    self.__matchMulti([("foo", CheckVariant.Not)],
+                      """abc
+                         def""")
+    self.__notMatchMulti([("foo", CheckVariant.Not)],
+                         """abc foo
+                            def""")
+    self.__notMatchMulti([("foo", CheckVariant.Not),
+                          ("bar", CheckVariant.Not)],
+                         """abc
+                            def bar""")
+
+  def test_LineOnlyMatchesOnce(self):
+    self.__matchMulti([("foo", CheckVariant.DAG),
+                       ("foo", CheckVariant.DAG)],
+                       """foo
+                          foo""")
+    self.__notMatchMulti([("foo", CheckVariant.DAG),
+                          ("foo", CheckVariant.DAG)],
+                          """foo
+                             bar""")
+
+class TestOutputFile_Parse(unittest.TestCase):
+  def __parsesTo(self, string, expected):
+    if isinstance(string, str):
+      string = unicode(string)
+    outputStream = io.StringIO(string)
+    return self.assertEqual(checker.OutputFile(outputStream).groups, expected)
+
+  def test_NoInput(self):
+    self.__parsesTo(None, [])
+    self.__parsesTo("", [])
+
+  def test_SingleGroup(self):
+    self.__parsesTo("""begin_compilation
+                         method "MyMethod"
+                       end_compilation
+                       begin_cfg
+                         name "pass1"
+                         foo
+                         bar
+                       end_cfg""",
+                    [ checker.OutputGroup("MyMethod pass1", [ "foo", "bar" ]) ])
+
+  def test_MultipleGroups(self):
+    self.__parsesTo("""begin_compilation
+                         name "xyz1"
+                         method "MyMethod1"
+                         date 1234
+                       end_compilation
+                       begin_cfg
+                         name "pass1"
+                         foo
+                         bar
+                       end_cfg
+                       begin_cfg
+                         name "pass2"
+                         abc
+                         def
+                       end_cfg""",
+                    [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
+                      checker.OutputGroup("MyMethod1 pass2", [ "abc", "def" ]) ])
+
+    self.__parsesTo("""begin_compilation
+                         name "xyz1"
+                         method "MyMethod1"
+                         date 1234
+                       end_compilation
+                       begin_cfg
+                         name "pass1"
+                         foo
+                         bar
+                       end_cfg
+                       begin_compilation
+                         name "xyz2"
+                         method "MyMethod2"
+                         date 5678
+                       end_compilation
+                       begin_cfg
+                         name "pass2"
+                         abc
+                         def
+                       end_cfg""",
+                    [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
+                      checker.OutputGroup("MyMethod2 pass2", [ "abc", "def" ]) ])
+
+class TestCheckFile_Parse(unittest.TestCase):
+  def __parsesTo(self, string, expected):
+    if isinstance(string, str):
+      string = unicode(string)
+    checkStream = io.StringIO(string)
+    return self.assertEqual(checker.CheckFile("CHECK", checkStream).groups, expected)
+
+  def test_NoInput(self):
+    self.__parsesTo(None, [])
+    self.__parsesTo("", [])
+
+  def test_SingleGroup(self):
+    self.__parsesTo("""// CHECK-START: Example Group
+                       // CHECK:  foo
+                       // CHECK:    bar""",
+                    [ checker.CheckGroup("Example Group", prepareChecks([ "foo", "bar" ])) ])
+
+  def test_MultipleGroups(self):
+    self.__parsesTo("""// CHECK-START: Example Group1
+                       // CHECK: foo
+                       // CHECK: bar
+                       // CHECK-START: Example Group2
+                       // CHECK: abc
+                       // CHECK: def""",
+                    [ checker.CheckGroup("Example Group1", prepareChecks([ "foo", "bar" ])),
+                      checker.CheckGroup("Example Group2", prepareChecks([ "abc", "def" ])) ])
+
+  def test_CheckVariants(self):
+    self.__parsesTo("""// CHECK-START: Example Group
+                       // CHECK:     foo
+                       // CHECK-NOT: bar
+                       // CHECK-DAG: abc
+                       // CHECK-DAG: def""",
+                    [ checker.CheckGroup("Example Group",
+                                         prepareChecks([ ("foo", CheckVariant.InOrder),
+                                                         ("bar", CheckVariant.Not),
+                                                         ("abc", CheckVariant.DAG),
+                                                         ("def", CheckVariant.DAG) ])) ])
+
+if __name__ == '__main__':
+  checker.Logger.Verbosity = checker.Logger.Level.NoOutput
+  unittest.main()
diff --git a/tools/dexfuzz/Android.mk b/tools/dexfuzz/Android.mk
new file mode 100644
index 0000000..d8f5582
--- /dev/null
+++ b/tools/dexfuzz/Android.mk
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# --- dexfuzz.jar ----------------
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAR_MANIFEST := manifest.txt
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE := dexfuzz
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# --- dexfuzz script ----------------
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := dexfuzz
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/dexfuzz $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
diff --git a/tools/dexfuzz/README b/tools/dexfuzz/README
new file mode 100644
index 0000000..c4795f2
--- /dev/null
+++ b/tools/dexfuzz/README
@@ -0,0 +1,130 @@
+DexFuzz
+=======
+
+DexFuzz is primarily a tool for fuzzing DEX files. Fuzzing is the introduction of
+subtle changes ("mutations") to a file to produce a new test case. These test cases
+can be used to test the various modes of execution available to ART (Interpreter,
+Quick compiler, Optimizing compiler) to check for bugs in these modes of execution.
+This is done by differential testing - each test file is executed with each mode of
+execution, and any differences between the resulting outputs may be an indication of
+a bug in one of the modes.
+
+For a wider overview of DexFuzz, see:
+
+http://community.arm.com/groups/android-community/blog/2014/11/26/the-art-of-fuzz-testing
+
+In typical operation, you provide DexFuzz with a set of DEX files that are the "seeds"
+for mutation - e.g. some tests taken from the ART test suite - and point it at an
+ADB-connected Android device, and it will fuzz these seed files, and execute the
+resulting new tests on the Android device.
+
+How to run DexFuzz
+==================
+
+1. Build dexfuzz with mmm tools/dexfuzz from within art/.
+2. Make sure you have an Android device connected via ADB, that is capable of
+   having DEX files pushed to it and executed with the dalvikvm command.
+3. Make sure you're in the Android build environment!
+   (That is, . build/envsetup.sh && lunch)
+4. Create a new directory, and place some DEX files in here. These are the seed files
+   that are mutated to form new tests.
+5. Create a directory on your device that mutated test files can be pushed to and
+   executed in, using dalvikvm. For example, /data/art-test/
+6. If you currently have multiple devices connected via ADB, find out the name of
+   your device using "adb devices -l".
+7. Run this command:
+
+dexfuzz --inputs=<seeds dir> --execute --repeat=<attempts> \
+    --dump-output <combination of ISA(s) and and backend(s)>
+
+You MUST specify one of the following ISAs:
+  --arm
+  --arm64
+  --x86
+  --x86_64
+  --mips
+  --mips64
+
+And also at least two of the following backends:
+  --interpreter
+  --quick
+  --optimizing
+
+Note that if you wanted to test both ARM and ARM64 on an ARM64 device, you can use
+--allarm. Also in this case only one backend is needed, if i.e., you wanted to test
+ARM Quick Backend vs. ARM64 Quick Backend.
+
+Some legal examples:
+  --arm --quick --optimizing
+  --x86 --quick --optimizing --interpreter
+  --allarm --quick
+
+Add in --device=<device name, e.g. device:generic> if you want to specify a device.
+Add in --execute-dir=<dir on device> if you want to specify an execution directory.
+  (The default is /data/art-test/)
+
+As the fuzzer works, you'll see output like:
+
+|-----------------------------------------------------------------|
+|Iterations|VerifyFail|MutateFail|Timed Out |Successful|Divergence|
+|-----------------------------------------------------------------|
+| 48       | 37       | 4        | 0        | 6        | 1        |
+
+Iterations - number of attempts we've made to mutate DEX files.
+VerifyFail - the number of mutated files that ended up failing to verify, either
+             on the host, or the target.
+MutateFail - because mutation is a random process, and has attempt thresholds to
+             avoid attempting to mutate a file indefinitely, it is possible that
+             an attempt to mutate a file doesn't actually mutate it. This counts
+             those occurrences.
+Timed Out  - mutated files that timed out for one or more backends.
+             Current timeouts are:
+               Quick - 5 seconds
+               Optimizing - 5 seconds
+               Intepreter - 30 seconds
+              (use --short-timeouts to set all backends to 2 seconds.)
+Successful - mutated files that executed and all backends agreed on the resulting
+             output. NB: if all backends crashed with the same output, this would
+             be considered a success - proper detection of crashes is still to come.
+Divergence - mutated files that executed and some backend disagreed about the
+             resulting output. Divergent programs are run multiple times with a
+             single backend, to check if they diverge from themselves, and these are
+             not included in the count. If multiple architectures are being used
+             (ARM/ARM64), and the divergences align with different architectures,
+             these are also not included in the count.
+
+8. Check report.log for the full report, including input file and RNG seed for each
+   test program. This allows you to recreate a bad program with, e.g.:
+
+dexfuzz --input=<input file> --seed=<seed value>
+
+Check dexfuzz --help for the full list of options.
+
+NOTE: DEX files with unicode strings are not fully supported yet, and DEX files with
+JNI elements are not supported at all currently.
+
+Mutation Likelihoods
+====================
+
+Each bytecode mutation has a chance out of 100% of firing. Following is the listing
+of each mutation's probability. If you wish to easily adjust these values, copy
+these values into a file called likelihoods.txt, and run dexfuzz with
+--likelihoods=likelihoods.txt.
+
+ArithOpChanger 75
+BranchShifter 30
+CmpBiasChanger 30
+ConstantValueChanger 70
+ConversionRepeater 50
+FieldFlagChanger 40
+InstructionDeleter 40
+InstructionDuplicator 80
+InstructionSwapper 80
+NewMethodCaller 10
+NonsenseStringPrinter 10
+PoolIndexChanger 30
+RandomInstructionGenerator 30
+SwitchBranchShifter 30
+TryBlockShifter 40
+ValuePrinter 40
+VRegChanger 60
diff --git a/tools/dexfuzz/dexfuzz b/tools/dexfuzz/dexfuzz
new file mode 100755
index 0000000..cd47008
--- /dev/null
+++ b/tools/dexfuzz/dexfuzz
@@ -0,0 +1,24 @@
+#!/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.
+#
+
+#
+# Wrapper script for calling dexfuzz.jar.
+#
+DEBUG=
+#DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8888,server=y,suspend=n -XX:+HeapDumpOnOutOfMemoryError -ea"
+
+java ${DEBUG} -jar ${ANDROID_HOST_OUT}/framework/dexfuzz.jar "$@"
diff --git a/tools/dexfuzz/manifest.txt b/tools/dexfuzz/manifest.txt
new file mode 100644
index 0000000..9e4c214
--- /dev/null
+++ b/tools/dexfuzz/manifest.txt
@@ -0,0 +1 @@
+Main-Class: dexfuzz.DexFuzz
diff --git a/tools/dexfuzz/src/dexfuzz/DexFuzz.java b/tools/dexfuzz/src/dexfuzz/DexFuzz.java
new file mode 100644
index 0000000..2fb9663
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/DexFuzz.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+import dexfuzz.fuzzers.Fuzzer;
+import dexfuzz.fuzzers.FuzzerMultipleExecute;
+import dexfuzz.fuzzers.FuzzerMultipleNoExecute;
+import dexfuzz.fuzzers.FuzzerSingleExecute;
+import dexfuzz.fuzzers.FuzzerSingleNoExecute;
+import dexfuzz.listeners.BaseListener;
+import dexfuzz.listeners.ConsoleLoggerListener;
+import dexfuzz.listeners.LogFileListener;
+import dexfuzz.listeners.MultiplexerListener;
+import dexfuzz.listeners.UniqueProgramTrackerListener;
+import dexfuzz.listeners.UpdatingConsoleListener;
+
+/**
+ * Entrypoint class for dexfuzz.
+ */
+public class DexFuzz {
+  private static int majorVersion = 1;
+  private static int minorVersion = 0;
+  private static int seedChangeVersion = 0;
+
+  /**
+   * Entrypoint to dexfuzz.
+   */
+  public static void main(String[] args) {
+    // Report the version number, which should be incremented every time something will cause
+    // the same input seed to produce a different result than before.
+    Log.always(String.format("DexFuzz v%d.%d.%d",
+        majorVersion, minorVersion, seedChangeVersion));
+    Log.always("");
+
+    if (!Options.readOptions(args)) {
+      Log.error("Failed to validate options.");
+      Options.usage();
+    }
+
+    // Create the Listener, which will listen for events and report them.
+    BaseListener listener = null;
+    if (Options.repeat > 1 && Options.execute) {
+      // Create a Listener that is responsible for multiple Listeners.
+      MultiplexerListener multipleListener = new MultiplexerListener();
+      multipleListener.setup();
+      // Add the live updating listener, but only if we're not printing out lots of logs.
+      if (!Log.likelyToLog()) {
+        multipleListener.addListener(new UpdatingConsoleListener());
+      } else {
+        // If we are dumping out lots of logs, then use the ConsoleLogger instead.
+        multipleListener.addListener(new ConsoleLoggerListener());
+      }
+      // Add the file logging listener.
+      multipleListener.addListener(new LogFileListener(Options.reportLogFile));
+      // Add the unique program tracker.
+      multipleListener.addListener(new UniqueProgramTrackerListener(Options.uniqueDatabaseFile));
+      listener = multipleListener;
+    } else {
+      // Just use the basic listener.
+      listener = new ConsoleLoggerListener();
+    }
+
+    // Create the Fuzzer that uses a particular strategy for fuzzing.
+    Fuzzer fuzzer = null;
+    if ((Options.repeat > 1) && Options.execute) {
+      fuzzer = new FuzzerMultipleExecute(listener);
+    } else if ((Options.repeat > 1) && !Options.execute) {
+      fuzzer = new FuzzerMultipleNoExecute(listener);
+    } else if ((Options.repeat == 1) && Options.execute) {
+      fuzzer = new FuzzerSingleExecute(listener);
+    } else if ((Options.repeat == 1) && !Options.execute) {
+      fuzzer = new FuzzerSingleNoExecute(listener);
+    } else {
+      Log.errorAndQuit("Invalid options provided, desired fuzzer unknown.");
+    }
+    // TODO: Implement FuzzerFindMinimalMutations.
+    // TODO: Implement FuzzerGenerational.
+
+    // Actually run the Fuzzer.
+    fuzzer.run();
+    fuzzer.printTimingInfo();
+    fuzzer.shutdown();
+
+    // Cleanup the Listener.
+    listener.shutdown();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/ExecutionResult.java b/tools/dexfuzz/src/dexfuzz/ExecutionResult.java
new file mode 100644
index 0000000..3a8c6cb
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/ExecutionResult.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+import java.util.List;
+
+/**
+ * Stores the output of an executed command.
+ */
+public class ExecutionResult {
+  public List<String> output;
+  public List<String> error;
+  public int returnValue;
+
+  private String flattenedOutput;
+  private String flattenedOutputWithNewlines;
+  private String flattenedError;
+  private String flattenedErrorWithNewlines;
+  private String flattenedAll;
+
+  private static final int TIMEOUT_RETURN_VALUE = 124;
+  private static final int SIGABORT_RETURN_VALUE = 134;
+
+  /**
+   * Get only the output, with all lines concatenated together, excluding newline characters.
+   */
+  public String getFlattenedOutput() {
+    if (flattenedOutput == null) {
+      StringBuilder builder = new StringBuilder();
+      for (String line : output) {
+        builder.append(line);
+      }
+      flattenedOutput = builder.toString();
+    }
+    return flattenedOutput;
+  }
+
+  /**
+   * Get only the output, with all lines concatenated together, including newline characters.
+   */
+  public String getFlattenedOutputWithNewlines() {
+    if (flattenedOutputWithNewlines == null) {
+      StringBuilder builder = new StringBuilder();
+      for (String line : output) {
+        builder.append(line).append("\n");
+      }
+      flattenedOutputWithNewlines = builder.toString();
+    }
+    return flattenedOutputWithNewlines;
+  }
+
+  /**
+   * Get only the error, with all lines concatenated together, excluding newline characters.
+   */
+  public String getFlattenedError() {
+    if (flattenedError == null) {
+      StringBuilder builder = new StringBuilder();
+      for (String line : error) {
+        builder.append(line);
+      }
+      flattenedError = builder.toString();
+    }
+    return flattenedError;
+  }
+
+  /**
+   * Get only the error, with all lines concatenated together, including newline characters.
+   */
+  public String getFlattenedErrorWithNewlines() {
+    if (flattenedErrorWithNewlines == null) {
+      StringBuilder builder = new StringBuilder();
+      for (String line : error) {
+        builder.append(line).append("\n");
+      }
+      flattenedErrorWithNewlines = builder.toString();
+    }
+    return flattenedErrorWithNewlines;
+  }
+
+  /**
+   * Get both the output and error, concatenated together, excluding newline characters.
+   */
+  public String getFlattenedAll() {
+    if (flattenedAll == null) {
+      flattenedAll = getFlattenedOutput() + getFlattenedError();
+    }
+    return flattenedAll;
+  }
+
+  public boolean isTimeout() {
+    return (returnValue == TIMEOUT_RETURN_VALUE);
+  }
+
+  public boolean isSigabort() {
+    return (returnValue == SIGABORT_RETURN_VALUE);
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/Log.java b/tools/dexfuzz/src/dexfuzz/Log.java
new file mode 100644
index 0000000..853550b
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/Log.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+/**
+ * Provides access to the logging facilities of dexfuzz.
+ */
+public class Log {
+  private static LogTag threshold = LogTag.ERROR;
+
+  // Disable the constructor for this class.
+  private Log() { }
+
+  public static enum LogTag {
+    DEBUG,
+    INFO,
+    WARN,
+    ERROR,
+    ALWAYS
+  }
+
+  public static void setLoggingLevel(LogTag tag) {
+    threshold = tag;
+  }
+
+  public static boolean likelyToLog() {
+    return (threshold.ordinal() < LogTag.ERROR.ordinal());
+  }
+
+  public static void debug(String msg) {
+    log(LogTag.DEBUG, msg);
+  }
+
+  public static void info(String msg) {
+    log(LogTag.INFO, msg);
+  }
+
+  public static void warn(String msg) {
+    log(LogTag.WARN, msg);
+  }
+
+  public static void error(String msg) {
+    log(LogTag.ERROR, msg);
+  }
+
+  public static void always(String msg) {
+    System.out.println(msg);
+  }
+
+  private static void log(LogTag tag, String msg) {
+    if (tag.ordinal() >= threshold.ordinal()) {
+      System.out.println("[" + tag.toString() + "] " + msg);
+    }
+  }
+
+  /**
+   * Reports error and then terminates the program.
+   */
+  public static void errorAndQuit(String msg) {
+    error(msg);
+    // TODO: Signal sleeping threads.
+    System.exit(1);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/MutationStats.java b/tools/dexfuzz/src/dexfuzz/MutationStats.java
new file mode 100644
index 0000000..c65b4f2
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/MutationStats.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A wrapper for a dictionary tracking what mutations have been performed.
+ */
+public class MutationStats {
+
+  public static class StatNotFoundException extends RuntimeException {
+    private static final long serialVersionUID = -7038515184655168470L;
+  }
+
+  private Map<String,Long> stats;
+  private List<String> statsOrder;
+
+  public MutationStats() {
+    stats = new HashMap<String,Long>();
+    statsOrder = new ArrayList<String>();
+  }
+
+  public void incrementStat(String statName) {
+    increaseStat(statName, 1);
+  }
+
+  /**
+   * Increase the named stat by the specified amount.
+   */
+  public void increaseStat(String statName, long amt) {
+    if (!stats.containsKey(statName)) {
+      stats.put(statName, 0L);
+      statsOrder.add(statName);
+    }
+    stats.put(statName, stats.get(statName) + amt);
+  }
+
+  /**
+   * Get a string representing the collected stats - looks like a JSON dictionary.
+   */
+  public String getStatsString() {
+    StringBuilder builder = new StringBuilder();
+    builder.append("{");
+    boolean first = true;
+    for (String statName : statsOrder) {
+      if (!first) {
+        builder.append(", ");
+      } else {
+        first = false;
+      }
+      builder.append("\"").append(statName).append("\": ").append(stats.get(statName));
+    }
+    builder.append("}");
+    return builder.toString();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/Options.java b/tools/dexfuzz/src/dexfuzz/Options.java
new file mode 100644
index 0000000..1ae7b5e
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/Options.java
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+import dexfuzz.Log.LogTag;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores options for dexfuzz.
+ */
+public class Options {
+  /**
+   * Constructor has been disabled for this class, which should only be used statically.
+   */
+  private Options() { }
+
+  // KEY VALUE OPTIONS
+  public static final List<String> inputFileList = new ArrayList<String>();
+  public static String outputFile = "";
+  public static long rngSeed = -1;
+  public static boolean usingProvidedSeed = false;
+  public static int methodMutations = 3;
+  public static int minMethods = 2;
+  public static int maxMethods = 10;
+  public static final Map<String,Integer> mutationLikelihoods = new HashMap<String,Integer>();
+  public static String executeClass = "Main";
+  public static String deviceName = "";
+  public static boolean usingSpecificDevice = false;
+  public static int repeat = 1;
+  public static String executeDirectory = "/data/art-test";
+  public static String dumpMutationsFile = "mutations.dump";
+  public static String loadMutationsFile = "mutations.dump";
+  public static String reportLogFile = "report.log";
+  public static String uniqueDatabaseFile = "unique_progs.db";
+
+  // FLAG OPTIONS
+  public static boolean execute;
+  public static boolean local;
+  public static boolean noBootImage;
+  public static boolean useInterpreter;
+  public static boolean useQuick;
+  public static boolean useOptimizing;
+  public static boolean useArchArm;
+  public static boolean useArchArm64;
+  public static boolean useArchX86;
+  public static boolean useArchX86_64;
+  public static boolean useArchMips;
+  public static boolean useArchMips64;
+  public static boolean skipHostVerify;
+  public static boolean shortTimeouts;
+  public static boolean dumpOutput;
+  public static boolean dumpVerify;
+  public static boolean mutateLimit;
+  public static boolean reportUnique;
+  public static boolean skipMutation;
+  public static boolean dumpMutations;
+  public static boolean loadMutations;
+
+  /**
+   * Print out usage information about dexfuzz, and then exit.
+   */
+  public static void usage() {
+    Log.always("DexFuzz Usage:");
+    Log.always("  --input=<file>         : Seed DEX file to be fuzzed");
+    Log.always("                           (Can specify multiple times.)");
+    Log.always("  --inputs=<file>        : Directory containing DEX files to be fuzzed.");
+    Log.always("  --output=<file>        : Output DEX file to be produced");
+    Log.always("");
+    Log.always("  --execute              : Execute the resulting fuzzed program");
+    Log.always("    --local              : Execute on host (Not available yet.)");
+    Log.always("    --device=<device>    : Execute on an ADB-connected-device, where <device> is");
+    Log.always("                           the argument given to adb -s. Default execution mode.");
+    Log.always("    --execute-dir=<dir>  : Push tests to this directory to execute them.");
+    Log.always("                           (Default: /data/art-test)");
+    Log.always("    --no-boot-image      : Use this flag when boot.art is not available.");
+    Log.always("    --skip-host-verify   : When executing, skip host-verification stage");
+    Log.always("    --execute-class=<c>  : When executing, execute this class (default: Main)");
+    Log.always("");
+    Log.always("    --interpreter        : Include the Interpreter in comparisons");
+    Log.always("    --quick              : Include the Quick Compiler in comparisons");
+    Log.always("    --optimizing         : Include the Optimizing Compiler in comparisons");
+    Log.always("");
+    Log.always("    --arm                : Include ARM backends in comparisons");
+    Log.always("    --arm64              : Include ARM64 backends in comparisons");
+    Log.always("    --allarm             : Short for --arm --arm64");
+    Log.always("    --x86                : Include x86 backends in comparisons");
+    Log.always("    --x86-64             : Include x86-64 backends in comparisons");
+    Log.always("    --mips               : Include MIPS backends in comparisons");
+    Log.always("    --mips64             : Include MIPS64 backends in comparisons");
+    Log.always("");
+    Log.always("    --dump-output        : Dump outputs of executed programs");
+    Log.always("    --dump-verify        : Dump outputs of verification");
+    Log.always("    --repeat=<n>         : Fuzz N programs, executing each one.");
+    Log.always("    --short-timeouts     : Shorten timeouts (faster; use if");
+    Log.always("                           you want to focus on output divergences)");
+    Log.always("  --seed=<seed>          : RNG seed to use");
+    Log.always("  --method-mutations=<n> : Maximum number of mutations to perform on each method.");
+    Log.always("                           (Default: 3)");
+    Log.always("  --min-methods=<n>      : Minimum number of methods to mutate. (Default: 2)");
+    Log.always("  --max-methods=<n>      : Maximum number of methods to mutate. (Default: 10)");
+    Log.always("  --one-mutation         : Short for --method-mutations=1 ");
+    Log.always("                             --min-methods=1 --max-methods=1");
+    Log.always("  --likelihoods=<file>   : A file containing a table of mutation likelihoods");
+    Log.always("  --mutate-limit         : Mutate only methods whose names end with _MUTATE");
+    Log.always("  --skip-mutation        : Do not actually mutate the input, just output it");
+    Log.always("                           after parsing");
+    Log.always("");
+    Log.always("  --dump-mutations[=<file>] : Dump an editable set of mutations applied");
+    Log.always("                              to <file> (default: mutations.dump)");
+    Log.always("  --load-mutations[=<file>] : Load and apply a set of mutations");
+    Log.always("                              from <file> (default: mutations.dump)");
+    Log.always("  --log=<tag>            : Set more verbose logging level: DEBUG, INFO, WARN");
+    Log.always("  --report=<file>        : Use <file> to report results when using --repeat");
+    Log.always("                           (Default: report.log)");
+    Log.always("  --report-unique        : Print out information about unique programs generated");
+    Log.always("  --unique-db=<file>     : Use <file> store results about unique programs");
+    Log.always("                           (Default: unique_progs.db)");
+    Log.always("");
+    System.exit(0);
+  }
+
+  /**
+   * Given a flag option (one that does not feature an =), handle it
+   * accordingly. Report an error and print usage info if the flag is not
+   * recognised.
+   */
+  private static void handleFlagOption(String flag) {
+    if (flag.equals("execute")) {
+      execute = true;
+    } else if (flag.equals("local")) {
+      local = true;
+    } else if (flag.equals("no-boot-image")) {
+      noBootImage = true;
+    } else if (flag.equals("skip-host-verify")) {
+      skipHostVerify = true;
+    } else if (flag.equals("interpreter")) {
+      useInterpreter = true;
+    } else if (flag.equals("quick")) {
+      useQuick = true;
+    } else if (flag.equals("optimizing")) {
+      useOptimizing = true;
+    } else if (flag.equals("arm")) {
+      useArchArm = true;
+    } else if (flag.equals("arm64")) {
+      useArchArm64 = true;
+    } else if (flag.equals("allarm")) {
+      useArchArm = true;
+      useArchArm64 = true;
+    } else if (flag.equals("x86")) {
+      useArchX86 = true;
+    } else if (flag.equals("x86-64")) {
+      useArchX86_64 = true;
+    } else if (flag.equals("mips")) {
+      useArchMips = true;
+    } else if (flag.equals("mips64")) {
+      useArchMips64 = true;
+    } else if (flag.equals("mutate-limit")) {
+      mutateLimit = true;
+    } else if (flag.equals("report-unique")) {
+      reportUnique = true;
+    } else if (flag.equals("dump-output")) {
+      dumpOutput = true;
+    } else if (flag.equals("dump-verify")) {
+      dumpVerify = true;
+    } else if (flag.equals("short-timeouts")) {
+      shortTimeouts = true;
+    } else if (flag.equals("skip-mutation")) {
+      skipMutation = true;
+    } else if (flag.equals("dump-mutations")) {
+      dumpMutations = true;
+    } else if (flag.equals("load-mutations")) {
+      loadMutations = true;
+    } else if (flag.equals("one-mutation")) {
+      methodMutations = 1;
+      minMethods = 1;
+      maxMethods = 1;
+    } else if (flag.equals("help")) {
+      usage();
+    } else {
+      Log.error("Unrecognised flag: --" + flag);
+      usage();
+    }
+  }
+
+  /**
+   * Given a key-value option (one that features an =), handle it
+   * accordingly. Report an error and print usage info if the key is not
+   * recognised.
+   */
+  private static void handleKeyValueOption(String key, String value) {
+    if (key.equals("input")) {
+      inputFileList.add(value);
+    } else if (key.equals("inputs")) {
+      File folder = new File(value);
+      if (folder.listFiles() == null) {
+        Log.errorAndQuit("Specified argument to --inputs is not a directory!");
+      }
+      for (File file : folder.listFiles()) {
+        String inputName = value + "/" + file.getName();
+        Log.always("Adding " + inputName + " to input seed files.");
+        inputFileList.add(inputName);
+      }
+    } else if (key.equals("output")) {
+      outputFile = value;
+    } else if (key.equals("seed")) {
+      rngSeed = Long.parseLong(value);
+      usingProvidedSeed = true;
+    } else if (key.equals("method-mutations")) {
+      methodMutations = Integer.parseInt(value);
+    } else if (key.equals("min-methods")) {
+      minMethods = Integer.parseInt(value);
+    } else if (key.equals("max-methods")) {
+      maxMethods = Integer.parseInt(value);
+    } else if (key.equals("repeat")) {
+      repeat = Integer.parseInt(value);
+    } else if (key.equals("log")) {
+      Log.setLoggingLevel(LogTag.valueOf(value.toUpperCase()));
+    } else if (key.equals("likelihoods")) {
+      setupMutationLikelihoodTable(value);
+    } else if (key.equals("dump-mutations")) {
+      dumpMutations = true;
+      dumpMutationsFile = value;
+    } else if (key.equals("load-mutations")) {
+      loadMutations = true;
+      loadMutationsFile = value;
+    } else if (key.equals("report")) {
+      reportLogFile = value;
+    } else if (key.equals("unique-db")) {
+      uniqueDatabaseFile = value;
+    } else if (key.equals("execute-class")) {
+      executeClass = value;
+    } else if (key.equals("device")) {
+      deviceName = value;
+      usingSpecificDevice = true;
+    } else if (key.equals("execute-dir")) {
+      executeDirectory = value;
+    } else {
+      Log.error("Unrecognised key: --" + key);
+      usage();
+    }
+  }
+
+  private static void setupMutationLikelihoodTable(String tableFilename) {
+    try {
+      BufferedReader reader = new BufferedReader(new FileReader(tableFilename));
+      String line = reader.readLine();
+      while (line != null) {
+        line = line.replaceAll("\\s+", " ");
+        String[] entries = line.split(" ");
+        String name = entries[0].toLowerCase();
+        int likelihood = Integer.parseInt(entries[1]);
+        if (likelihood > 100) {
+          likelihood = 100;
+        }
+        if (likelihood < 0) {
+          likelihood = 0;
+        }
+        mutationLikelihoods.put(name, likelihood);
+        line = reader.readLine();
+      }
+      reader.close();
+    } catch (FileNotFoundException e) {
+      Log.error("Unable to open mutation probability table file: " + tableFilename);
+    } catch (IOException e) {
+      Log.error("Unable to read mutation probability table file: " + tableFilename);
+    }
+  }
+
+  /**
+   * Called by the DexFuzz class during program initialisation to parse
+   * the program's command line arguments.
+   * @return If options were successfully read and validated.
+   */
+  public static boolean readOptions(String[] args) {
+    for (String arg : args) {
+      if (!(arg.startsWith("--"))) {
+        Log.error("Unrecognised option: " + arg);
+        usage();
+      }
+
+      // cut off the --
+      arg = arg.substring(2);
+
+      // choose between a --X=Y option (keyvalue) and a --X option (flag)
+      if (arg.contains("=")) {
+        String[] split = arg.split("=");
+        handleKeyValueOption(split[0], split[1]);
+      } else {
+        handleFlagOption(arg);
+      }
+    }
+
+    return validateOptions();
+  }
+
+  /**
+   * Checks if the current options settings are valid, called after reading
+   * all options.
+   * @return If the options are valid or not.
+   */
+  private static boolean validateOptions() {
+    // Deal with option assumptions.
+    if (inputFileList.isEmpty()) {
+      File seedFile = new File("fuzzingseed.dex");
+      if (seedFile.exists()) {
+        Log.always("Assuming --input=fuzzingseed.dex");
+        inputFileList.add("fuzzingseed.dex");
+      } else {
+        Log.errorAndQuit("No input given, and couldn't find fuzzingseed.dex!");
+        return false;
+      }
+    }
+
+    if (outputFile.equals("")) {
+      Log.always("Assuming --output=fuzzingseed_fuzzed.dex");
+      outputFile = "fuzzingseed_fuzzed.dex";
+    }
+
+
+    if (mutationLikelihoods.isEmpty()) {
+      File likelihoodsFile = new File("likelihoods.txt");
+      if (likelihoodsFile.exists()) {
+        Log.always("Assuming --likelihoods=likelihoods.txt ");
+        setupMutationLikelihoodTable("likelihoods.txt");
+      } else {
+        Log.always("Using default likelihoods (see README for values)");
+      }
+    }
+
+    // Now check for hard failures.
+    if (repeat < 1) {
+      Log.error("--repeat must be at least 1!");
+      return false;
+    }
+    if (usingProvidedSeed && repeat > 1) {
+      Log.error("Cannot use --repeat with --seed");
+      return false;
+    }
+    if (loadMutations && dumpMutations) {
+      Log.error("Cannot both load and dump mutations");
+      return false;
+    }
+    if (repeat == 1 && inputFileList.size() > 1) {
+      Log.error("Must use --repeat if you have provided more than one input");
+      return false;
+    }
+    if (methodMutations < 0) {
+      Log.error("Cannot use --method-mutations with a negative value.");
+      return false;
+    }
+    if (minMethods < 0) {
+      Log.error("Cannot use --min-methods with a negative value.");
+      return false;
+    }
+    if (maxMethods < 0) {
+      Log.error("Cannot use --max-methods with a negative value.");
+      return false;
+    }
+    if (maxMethods < minMethods) {
+      Log.error("Cannot use --max-methods that's smaller than --min-methods");
+      return false;
+    }
+    if (local && usingSpecificDevice) {
+      Log.error("Cannot use --local and --device!");
+      return false;
+    }
+    if (execute) {
+      if (!(useArchArm
+          || useArchArm64
+          || useArchX86
+          || useArchX86_64
+          || useArchMips
+          || useArchMips64)) {
+        Log.error("No architecture to execute on was specified!");
+        return false;
+      }
+      if ((useArchArm || useArchArm64) && (useArchX86 || useArchX86_64)) {
+        Log.error("Did you mean to specify ARM and x86?");
+        return false;
+      }
+      if ((useArchArm || useArchArm64) && (useArchMips || useArchMips64)) {
+        Log.error("Did you mean to specify ARM and MIPS?");
+        return false;
+      }
+      if ((useArchX86 || useArchX86_64) && (useArchMips || useArchMips64)) {
+        Log.error("Did you mean to specify x86 and MIPS?");
+        return false;
+      }
+      int backends = 0;
+      if (useInterpreter) {
+        backends++;
+      }
+      if (useQuick) {
+        backends++;
+      }
+      if (useOptimizing) {
+        backends++;
+      }
+      if (useArchArm && useArchArm64) {
+        // Could just be comparing quick-ARM versus quick-ARM64?
+        backends++;
+      }
+      if (backends < 2) {
+        Log.error("Not enough backends specified! Try --quick --interpreter!");
+        return false;
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/StreamConsumer.java b/tools/dexfuzz/src/dexfuzz/StreamConsumer.java
new file mode 100644
index 0000000..cd93374
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/StreamConsumer.java
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+
+/**
+ * process.waitFor() can block if its output buffers are not drained.
+ * These threads are used to keep the buffers drained, and provide the final
+ * output once the command has finished executing. Each Executor has its own
+ * output and error StreamConsumers.
+ */
+public class StreamConsumer extends Thread {
+  private List<String> output;
+  private BufferedReader reader;
+
+  private State state;
+
+  private Semaphore workToBeDone;
+  private Semaphore outputIsReady;
+
+  enum State {
+    WAITING,
+    CONSUMING,
+    SHOULD_STOP_CONSUMING,
+    FINISHED,
+    ERROR
+  }
+
+  /**
+   * Create a StreamConsumer, will be immediately ready to start consuming.
+   */
+  public StreamConsumer() {
+    output = new ArrayList<String>();
+    workToBeDone = new Semaphore(0);
+    outputIsReady = new Semaphore(0);
+
+    state = State.WAITING;
+  }
+
+  /**
+   * Executor should call this to provide its StreamConsumers with the Streams
+   * for a Process it is about to call waitFor() on.
+   */
+  public void giveStreamAndStartConsuming(InputStream stream) {
+    output.clear();
+
+    reader = new BufferedReader(new InputStreamReader(stream));
+
+    changeState(State.CONSUMING, State.WAITING);
+
+    // Tell consumer there is work to be done.
+    workToBeDone.release();
+  }
+
+  /**
+   * Executor should call this once its call to waitFor() returns.
+   */
+  public void processFinished() {
+    changeState(State.SHOULD_STOP_CONSUMING, State.CONSUMING);
+  }
+
+  /**
+   * Executor should call this to get the captured output of this StreamConsumer.
+   */
+  public List<String> getOutput() {
+
+    try {
+      // Wait until the output is ready.
+      outputIsReady.acquire();
+    } catch (InterruptedException e) {
+      Log.error("Client of StreamConsumer was interrupted while waiting for output?");
+      return null;
+    }
+
+    // Take a copy of the Strings, so when we call output.clear(), we don't
+    // clear the ExecutionResult's list.
+    List<String> copy = new ArrayList<String>(output);
+    return copy;
+  }
+
+  /**
+   * Executor should call this when we're shutting down.
+   */
+  public void shutdown() {
+    changeState(State.FINISHED, State.WAITING);
+
+    // Tell Consumer there is work to be done (it will check first if FINISHED has been set.)
+    workToBeDone.release();
+  }
+
+  private void consume() {
+    try {
+
+      if (checkState(State.SHOULD_STOP_CONSUMING)) {
+        // Caller already called processFinished() before we even started
+        // consuming. Just get what we can and finish.
+        while (reader.ready()) {
+          output.add(reader.readLine());
+        }
+      } else {
+        // Caller's process is still executing, so just loop and consume.
+        while (checkState(State.CONSUMING)) {
+          Thread.sleep(50);
+          while (reader.ready()) {
+            output.add(reader.readLine());
+          }
+        }
+      }
+
+      if (checkState(State.SHOULD_STOP_CONSUMING)) {
+        changeState(State.WAITING, State.SHOULD_STOP_CONSUMING);
+      } else {
+        Log.error("StreamConsumer stopped consuming, but was not told to?");
+        setErrorState();
+      }
+
+      reader.close();
+
+    } catch (IOException e) {
+      Log.error("StreamConsumer caught IOException while consuming");
+      setErrorState();
+    } catch (InterruptedException e) {
+      Log.error("StreamConsumer caught InterruptedException while consuming");
+      setErrorState();
+    }
+
+    // Tell client of Consumer that the output is ready.
+    outputIsReady.release();
+  }
+
+  @Override
+  public void run() {
+    while (checkState(State.WAITING)) {
+      try {
+        // Wait until there is work to be done
+        workToBeDone.acquire();
+      } catch (InterruptedException e) {
+        Log.error("StreamConsumer caught InterruptedException while waiting for work");
+        setErrorState();
+        break;
+      }
+
+      // Check first if we're done
+      if (checkState(State.FINISHED)) {
+        break;
+      }
+
+      // Make sure we're either supposed to be consuming
+      // or supposed to be finishing up consuming
+      if (!(checkState(State.CONSUMING) || checkState(State.SHOULD_STOP_CONSUMING))) {
+        Log.error("invalid state: StreamConsumer told about work, but not CONSUMING?");
+        Log.error("state was: " + getCurrentState());
+        setErrorState();
+        break;
+      }
+
+      consume();
+    }
+  }
+
+  private synchronized boolean checkState(State expectedState) {
+    return (expectedState == state);
+  }
+
+  private synchronized void changeState(State newState, State previousState) {
+    if (state != previousState) {
+      Log.error("StreamConsumer Unexpected state: " + state + ", expected " + previousState);
+      state = State.ERROR;
+    } else {
+      state = newState;
+    }
+  }
+
+  private synchronized void setErrorState() {
+    state = State.ERROR;
+  }
+
+  private synchronized State getCurrentState() {
+    return state;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/Timer.java b/tools/dexfuzz/src/dexfuzz/Timer.java
new file mode 100644
index 0000000..8979b8a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/Timer.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package dexfuzz;
+
+import dexfuzz.listeners.BaseListener;
+
+/**
+ * For timing splits of program execution.
+ */
+public class Timer {
+  /**
+   * The name of the timer, the phase of the program it is intended to time.
+   */
+  private String name;
+
+  /**
+   * A point in time remembered when start() is called.
+   */
+  private long startPoint;
+
+  /**
+   * A cumulative count of how much time has elapsed. Updated each time
+   * stop() is called.
+   */
+  private long elapsedTime;
+
+  /**
+   * Initialise a new timer with the provided name.
+   */
+  public Timer(String name) {
+    this.name = name;
+    this.elapsedTime = 0L;
+  }
+
+  /**
+   * Start timing.
+   */
+  public void start() {
+    startPoint = System.currentTimeMillis();
+  }
+
+  /**
+   * Stop timing, update how much time has elapsed.
+   */
+  public void stop() {
+    long endPoint = System.currentTimeMillis();
+    elapsedTime += (endPoint - startPoint);
+  }
+
+  /**
+   * Log the elapsed time this timer has recorded.
+   */
+  public void printTime(BaseListener listener) {
+    listener.handleTiming(name, ((float)elapsedTime) / 1000.0f);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Architecture.java b/tools/dexfuzz/src/dexfuzz/executors/Architecture.java
new file mode 100644
index 0000000..5cdabc3
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Architecture.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+/**
+ * Every Executor must specify an Architecture. It is important that when reduced
+ * to lower case, these match the ISA string that ART would produce. For example,
+ * the architecture directory used for /data/dalvik-cache/${ISA}
+ */
+public enum Architecture {
+  ARM,
+  ARM64,
+  X86,
+  X86_64,
+  MIPS,
+  MIPS64
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java
new file mode 100644
index 0000000..a945283
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64InterpreterExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class Arm64InterpreterExecutor extends Executor {
+
+  public Arm64InterpreterExecutor(BaseListener listener, Device device) {
+    super("ARM64 Interpreter", 30, listener, Architecture.ARM64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 -Xint ");
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
+    }
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/arm64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java
new file mode 100644
index 0000000..2204ba8
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class Arm64OptimizingBackendExecutor extends Executor {
+
+  public Arm64OptimizingBackendExecutor(BaseListener listener, Device device) {
+    super("ARM64 Optimizing Backend", 5, listener, Architecture.ARM64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing ");
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
+    }
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/arm64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java
new file mode 100644
index 0000000..55c9c7a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class Arm64QuickBackendExecutor extends Executor {
+
+  public Arm64QuickBackendExecutor(BaseListener listener, Device device) {
+    super("ARM64 Quick Backend", 5, listener, Architecture.ARM64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 ");
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
+    }
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/arm64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java
new file mode 100644
index 0000000..68ce2e0
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/ArmInterpreterExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class ArmInterpreterExecutor extends Executor {
+
+  public ArmInterpreterExecutor(BaseListener listener, Device device) {
+    super("ARM Interpreter", 30, listener, Architecture.ARM, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 -Xint ");
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
+    }
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/arm/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java
new file mode 100644
index 0000000..78cf652
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class ArmOptimizingBackendExecutor extends Executor {
+
+  public ArmOptimizingBackendExecutor(BaseListener listener, Device device) {
+    super("ARM Optimizing Backend", 5, listener, Architecture.ARM, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing ");
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
+    }
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/arm/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java
new file mode 100644
index 0000000..8f026b2
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class ArmQuickBackendExecutor extends Executor {
+
+  public ArmQuickBackendExecutor(BaseListener listener, Device device) {
+    super("ARM Quick Backend", 5, listener, Architecture.ARM, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 ");
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
+    }
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/arm/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Device.java b/tools/dexfuzz/src/dexfuzz/executors/Device.java
new file mode 100644
index 0000000..8c03103
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Device.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+/**
+ * Handles execution either on a remote device, or locally.
+ * Currently only remote execution, on an ADB-connected device, is supported.
+ */
+public class Device {
+  private boolean isLocal;
+  private String deviceName;
+  private boolean usingSpecificDevice;
+  private boolean noBootImage;
+
+  /**
+   * The constructor for a local "device". Not yet supported.
+   */
+  public Device() {
+    this.isLocal = true;
+    throw new UnsupportedOperationException("Currently local execution is not supported.");
+  }
+
+  /**
+   * The constructor for an ADB connected device.
+   */
+  public Device(String deviceName, boolean noBootImage) {
+    if (!deviceName.isEmpty()) {
+      this.deviceName = deviceName;
+      this.usingSpecificDevice = true;
+    }
+    this.noBootImage = noBootImage;
+  }
+
+  /**
+   * Get the name that would be provided to adb -s to communicate specifically with this device.
+   */
+  public String getName() {
+    if (isLocal) {
+      return "LOCAL DEVICE";
+    }
+    return deviceName;
+  }
+
+  public boolean isLocal() {
+    return isLocal;
+  }
+
+  /**
+   * Certain AOSP builds of Android may not have a full boot.art built. This will be set if
+   * we use --no-boot-image, and is used by Executors when deciding the arguments for dalvikvm
+   * and dex2oat when performing host-side verification.
+   */
+  public boolean noBootImageAvailable() {
+    return noBootImage;
+  }
+
+  /**
+   * Get the command prefix for this device if we want to use adb shell.
+   */
+  public String getExecutionShellPrefix() {
+    if (isLocal) {
+      return "";
+    }
+    return getExecutionPrefixWithAdb("shell");
+  }
+
+  /**
+   * Get the command prefix for this device if we want to use adb push.
+   */
+  public String getExecutionPushPrefix() {
+    if (isLocal) {
+      return "";
+    }
+    return getExecutionPrefixWithAdb("push");
+  }
+
+  private String getExecutionPrefixWithAdb(String command) {
+    if (usingSpecificDevice) {
+      return String.format("adb -s %s %s ", deviceName, command);
+    } else {
+      return String.format("adb %s ", command);
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Executor.java b/tools/dexfuzz/src/dexfuzz/executors/Executor.java
new file mode 100644
index 0000000..7cc584d
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Executor.java
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.ExecutionResult;
+import dexfuzz.Log;
+import dexfuzz.Options;
+import dexfuzz.StreamConsumer;
+import dexfuzz.listeners.BaseListener;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Base class containing the common methods for executing a particular backend of ART.
+ */
+public abstract class Executor {
+  private String androidHostOut;
+  private String androidProductOut;
+
+  private StreamConsumer outputConsumer;
+  private StreamConsumer errorConsumer;
+
+  protected ExecutionResult executionResult;
+  protected String executeClass;
+
+  // Set by subclasses.
+  protected String name;
+  protected int timeout;
+  protected BaseListener listener;
+  protected String testLocation;
+  protected Architecture architecture;
+  protected Device device;
+
+  protected Executor(String name, int timeout, BaseListener listener, Architecture architecture,
+      Device device) {
+    executeClass = Options.executeClass;
+
+    if (Options.shortTimeouts) {
+      this.timeout = 2;
+    } else {
+      this.timeout = timeout;
+    }
+
+    this.name = name;
+    this.listener = listener;
+    this.architecture = architecture;
+    this.device = device;
+
+    this.testLocation = Options.executeDirectory;
+
+    Map<String, String> envVars = System.getenv();
+    androidProductOut = checkForEnvVar(envVars, "ANDROID_PRODUCT_OUT");
+    androidHostOut = checkForEnvVar(envVars, "ANDROID_HOST_OUT");
+
+    outputConsumer = new StreamConsumer();
+    outputConsumer.start();
+    errorConsumer = new StreamConsumer();
+    errorConsumer.start();
+
+    if (!device.isLocal()) {
+      // Check for ADB.
+      try {
+        ProcessBuilder pb = new ProcessBuilder();
+        pb.command("adb", "devices");
+        Process process = pb.start();
+        int exitValue = process.waitFor();
+        if (exitValue != 0) {
+          Log.errorAndQuit("Problem executing ADB - is it in your $PATH?");
+        }
+      } catch (IOException e) {
+        Log.errorAndQuit("IOException when executing ADB, is it working?");
+      } catch (InterruptedException e) {
+        Log.errorAndQuit("InterruptedException when executing ADB, is it working?");
+      }
+
+      // Check we can run something on ADB.
+      ExecutionResult result = executeOnDevice("true", true);
+      if (result.getFlattenedAll().contains("device not found")) {
+        Log.errorAndQuit("Couldn't connect to specified ADB device: " + device.getName());
+      }
+    }
+  }
+
+  private String checkForEnvVar(Map<String, String> envVars, String key) {
+    if (!envVars.containsKey(key)) {
+      Log.errorAndQuit("Cannot run a fuzzed program if $" + key + " is not set!");
+    }
+    return envVars.get(key);
+  }
+
+  private ExecutionResult executeCommand(String command, boolean captureOutput) {
+    ExecutionResult result = new ExecutionResult();
+
+    Log.info("Executing: " + command);
+
+    try {
+      ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
+      processBuilder.environment().put("ANDROID_ROOT", androidHostOut);
+      Process process = processBuilder.start();
+
+      if (captureOutput) {
+        // Give the streams to the StreamConsumers.
+        outputConsumer.giveStreamAndStartConsuming(process.getInputStream());
+        errorConsumer.giveStreamAndStartConsuming(process.getErrorStream());
+      }
+
+      // Wait until the process is done - the StreamConsumers will keep the
+      // buffers drained, so this shouldn't block indefinitely.
+      // Get the return value as well.
+      result.returnValue = process.waitFor();
+
+      Log.info("Return value: " + result.returnValue);
+
+      if (captureOutput) {
+        // Tell the StreamConsumers to stop consuming, and wait for them to finish
+        // so we know we have all of the output.
+        outputConsumer.processFinished();
+        errorConsumer.processFinished();
+        result.output = outputConsumer.getOutput();
+        result.error = errorConsumer.getOutput();
+
+        // Always explicitly indicate the return code in the text output now.
+        // NB: adb shell doesn't actually return exit codes currently, but this will
+        // be useful if/when it does.
+        result.output.add("RETURN CODE: " + result.returnValue);
+      }
+
+    } catch (IOException e) {
+      Log.errorAndQuit("ExecutionResult.execute() caught an IOException");
+    } catch (InterruptedException e) {
+      Log.errorAndQuit("ExecutionResult.execute() caught an InterruptedException");
+    }
+
+    return result;
+  }
+
+  /**
+   * Called by subclass Executors in their execute() implementations.
+   */
+  protected ExecutionResult executeOnDevice(String command, boolean captureOutput) {
+    String timeoutString = "timeout " + timeout + " ";
+    return executeCommand(timeoutString + device.getExecutionShellPrefix() + command,
+        captureOutput);
+  }
+
+  private ExecutionResult pushToDevice(String command) {
+    return executeCommand(device.getExecutionPushPrefix() + command, false);
+  }
+
+  /**
+   * Call this to make sure the StreamConsumer threads are stopped.
+   */
+  public void shutdown() {
+    outputConsumer.shutdown();
+    errorConsumer.shutdown();
+  }
+
+  /**
+   * Called by the Fuzzer after each execution has finished, to clear the results.
+   */
+  public void reset() {
+    executionResult = null;
+  }
+
+  /**
+   * Called by the Fuzzer to verify the mutated program using the host-side dex2oat.
+   */
+  public boolean verifyOnHost(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dex2oat ");
+
+    // This assumes that the Architecture enum's name, when reduced to lower-case,
+    // matches what dex2oat would expect.
+    commandBuilder.append("--instruction-set=").append(architecture.toString().toLowerCase());
+    commandBuilder.append(" --instruction-set-features=default ");
+
+    // Select the correct boot image.
+    commandBuilder.append("--boot-image=").append(androidProductOut);
+    if (device.noBootImageAvailable()) {
+      commandBuilder.append("/data/art-test/core.art ");
+    } else {
+      commandBuilder.append("/system/framework/boot.art ");
+    }
+
+    commandBuilder.append("--oat-file=output.oat ");
+    commandBuilder.append("--android-root=").append(androidHostOut).append(" ");
+    commandBuilder.append("--runtime-arg -classpath ");
+    commandBuilder.append("--runtime-arg ").append(programName).append(" ");
+    commandBuilder.append("--dex-file=").append(programName).append(" ");
+    commandBuilder.append("--compiler-filter=interpret-only --runtime-arg -Xnorelocate ");
+
+    ExecutionResult verificationResult = executeCommand(commandBuilder.toString(), true);
+
+    boolean success = true;
+
+    if (verificationResult.isSigabort()) {
+      listener.handleHostVerificationSigabort(verificationResult);
+      success = false;
+    }
+
+    if (success) {
+      // Search for a keyword that indicates verification was not successful.
+      // TODO: Determine if dex2oat crashed?
+      for (String line : verificationResult.error) {
+        if (line.contains("Verification error")
+            || line.contains("Failure to verify dex file")) {
+          success = false;
+        }
+        if (Options.dumpVerify) {
+          // Strip out the start of the log lines.
+          listener.handleDumpVerify(line.replaceFirst(".*(cc|h):\\d+] ",  ""));
+        }
+      }
+    }
+
+    if (!success) {
+      listener.handleFailedHostVerification(verificationResult);
+    }
+
+    executeCommand("rm output.oat", false);
+
+    return success;
+  }
+
+  /**
+   * Called by the Fuzzer to upload the program to the target device.
+   * TODO: Check if we're executing on a local device, and don't do this?
+   */
+  public void uploadToTarget(String programName) {
+    pushToDevice(programName + " " + testLocation);
+  }
+
+  /**
+   * Executor subclasses need to override this, to construct their arguments for dalvikvm
+   * invocation correctly.
+   */
+  public abstract void execute(String programName);
+
+  /**
+   * Executor subclasses need to override this, to delete their generated OAT file correctly.
+   */
+  public abstract void deleteGeneratedOatFile(String programName);
+
+  /**
+   * Executor subclasses need to override this, to report if they need a cleaned code cache.
+   */
+  public abstract boolean needsCleanCodeCache();
+
+  /**
+   * Fuzzer.checkForArchitectureSplit() will use this determine the architecture of the Executor.
+   */
+  public Architecture getArchitecture() {
+    return architecture;
+  }
+
+  /**
+   * Used in each subclass of Executor's deleteGeneratedOatFile() method, to know what to delete.
+   */
+  protected String getOatFileName(String programName) {
+    // Converts e.g. /data/art-test/file.dex to data@art-test@file.dex
+    return (testLocation.replace("/", "@").substring(1) + "@" + programName);
+  }
+
+  /**
+   * Used by the Fuzzer to get result of execution.
+   */
+  public ExecutionResult getResult() {
+    return executionResult;
+  }
+
+  /**
+   * Because dex2oat can accept a program with soft errors on the host, and then fail after
+   * performing hard verification on the target, we need to check if the Executor detected
+   * a target verification failure, before doing anything else with the resulting output.
+   * Used by the Fuzzer.
+   */
+  public boolean verifyOnTarget() {
+    // TODO: Remove this once host-verification can be forced to always fail?
+    if (executionResult.getFlattenedOutput().contains("VerifyError")) {
+      return false;
+    }
+    return true;
+  }
+
+  public String getName() {
+    return name;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java
new file mode 100644
index 0000000..9f27b5e
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64InterpreterExecutor.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class Mips64InterpreterExecutor extends Executor {
+
+  public Mips64InterpreterExecutor(BaseListener listener, Device device) {
+    super("MIPS64 Interpreter", 30, listener, Architecture.MIPS64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 -Xint ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/mips64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return false;
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java
new file mode 100644
index 0000000..b30240d
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class Mips64OptimizingBackendExecutor extends Executor {
+
+  public Mips64OptimizingBackendExecutor(BaseListener listener, Device device) {
+    super("MIPS64 Optimizing Backend", 5, listener, Architecture.MIPS64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/mips64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java
new file mode 100644
index 0000000..42ccd1e
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class Mips64QuickBackendExecutor extends Executor {
+
+  public Mips64QuickBackendExecutor(BaseListener listener, Device device) {
+    super("MIPS64 Quick Backend", 5, listener, Architecture.MIPS64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/mips64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java
new file mode 100644
index 0000000..524eaa9
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/MipsInterpreterExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class MipsInterpreterExecutor extends Executor {
+
+  public MipsInterpreterExecutor(BaseListener listener, Device device) {
+    super("MIPS Interpreter", 30, listener, Architecture.MIPS, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 -Xint ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/mips/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java
new file mode 100644
index 0000000..fcc92c8
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class MipsOptimizingBackendExecutor extends Executor {
+
+  public MipsOptimizingBackendExecutor(BaseListener listener, Device device) {
+    super("MIPS Optimizing Backend", 5, listener, Architecture.MIPS, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/mips/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java
new file mode 100644
index 0000000..cb442f9
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class MipsQuickBackendExecutor extends Executor {
+
+  public MipsQuickBackendExecutor(BaseListener listener, Device device) {
+    super("MIPS Quick Backend", 5, listener, Architecture.MIPS, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/mips/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java
new file mode 100644
index 0000000..93c14e9
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86InterpreterExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class X86InterpreterExecutor extends Executor {
+
+  public X86InterpreterExecutor(BaseListener listener, Device device) {
+    super("x86 Interpreter", 30, listener, Architecture.X86, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 -Xint ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/x86/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java
new file mode 100644
index 0000000..b27d5ca
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class X86OptimizingBackendExecutor extends Executor {
+
+  public X86OptimizingBackendExecutor(BaseListener listener, Device device) {
+    super("x86 Optimizing Backend", 5, listener, Architecture.X86, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/x86/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java
new file mode 100644
index 0000000..d8ec217
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class X86QuickBackendExecutor extends Executor {
+
+  public X86QuickBackendExecutor(BaseListener listener, Device device) {
+    super("x86 Quick Backend", 5, listener, Architecture.X86, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm32 ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/x86/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java
new file mode 100644
index 0000000..7497322
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64InterpreterExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class X86_64InterpreterExecutor extends Executor {
+
+  public X86_64InterpreterExecutor(BaseListener listener, Device device) {
+    super("x86_64 Interpreter", 30, listener, Architecture.X86_64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 -Xint ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/x86_64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java
new file mode 100644
index 0000000..a978f73
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class X86_64OptimizingBackendExecutor extends Executor {
+
+  public X86_64OptimizingBackendExecutor(BaseListener listener, Device device) {
+    super("x86_64 Optimizing Backend", 5, listener, Architecture.X86_64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/x86_64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java
new file mode 100644
index 0000000..85532d8
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.executors;
+
+import dexfuzz.listeners.BaseListener;
+
+public class X86_64QuickBackendExecutor extends Executor {
+
+  public X86_64QuickBackendExecutor(BaseListener listener, Device device) {
+    super("x86_64 Quick Backend", 5, listener, Architecture.X86_64, device);
+  }
+
+  @Override
+  public void execute(String programName) {
+    StringBuilder commandBuilder = new StringBuilder();
+    commandBuilder.append("dalvikvm64 ");
+    commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
+    commandBuilder.append(executeClass);
+    executionResult = executeOnDevice(commandBuilder.toString(), true);
+  }
+
+  @Override
+  public void deleteGeneratedOatFile(String programName) {
+    String command = "rm -f /data/dalvik-cache/x86_64/" + getOatFileName(programName);
+    executeOnDevice(command, false);
+  }
+
+  @Override
+  public boolean needsCleanCodeCache() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java b/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java
new file mode 100644
index 0000000..4c1acdb
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.Log;
+import dexfuzz.Options;
+import dexfuzz.Timer;
+import dexfuzz.executors.Architecture;
+import dexfuzz.executors.Arm64InterpreterExecutor;
+import dexfuzz.executors.Arm64OptimizingBackendExecutor;
+import dexfuzz.executors.Arm64QuickBackendExecutor;
+import dexfuzz.executors.ArmInterpreterExecutor;
+import dexfuzz.executors.ArmOptimizingBackendExecutor;
+import dexfuzz.executors.ArmQuickBackendExecutor;
+import dexfuzz.executors.Device;
+import dexfuzz.executors.Executor;
+import dexfuzz.executors.Mips64InterpreterExecutor;
+import dexfuzz.executors.Mips64OptimizingBackendExecutor;
+import dexfuzz.executors.Mips64QuickBackendExecutor;
+import dexfuzz.executors.MipsInterpreterExecutor;
+import dexfuzz.executors.MipsOptimizingBackendExecutor;
+import dexfuzz.executors.MipsQuickBackendExecutor;
+import dexfuzz.executors.X86InterpreterExecutor;
+import dexfuzz.executors.X86OptimizingBackendExecutor;
+import dexfuzz.executors.X86QuickBackendExecutor;
+import dexfuzz.executors.X86_64InterpreterExecutor;
+import dexfuzz.executors.X86_64OptimizingBackendExecutor;
+import dexfuzz.executors.X86_64QuickBackendExecutor;
+import dexfuzz.listeners.BaseListener;
+import dexfuzz.program.Mutation;
+import dexfuzz.program.Program;
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.OffsetTracker;
+import dexfuzz.rawdex.RawDexFile;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A particular fuzzing strategy, this class provides the common methods
+ * most fuzzing will involve, and subclasses override the run() method, to
+ * employ a particular strategy.
+ */
+public abstract class Fuzzer {
+  private List<Executor> executors;
+  private OffsetTracker offsetTracker;
+
+  /**
+   * This is the executor that we use to test for self-divergent programs.
+   */
+  private Executor goldenExecutor;
+
+  /*
+   * These two flags are set during fuzz(), and then cleared at the end of execute().
+   */
+  private boolean mutatedSuccessfully;
+  private boolean savedSuccessfully;
+
+  private Timer totalTimer = new Timer("Total Time");
+  private Timer timerDexInput = new Timer("DEX Input");
+  private Timer timerProgGen = new Timer("Program Generation");
+  private Timer timerMutation = new Timer("Mutation Time");
+  private Timer timerDexOutput = new Timer("DEX Output");
+  private Timer timerChecksumCalc = new Timer("Checksum Calculation");
+
+  protected BaseListener listener;
+
+  protected Fuzzer(BaseListener listener) {
+    totalTimer.start();
+    executors = new ArrayList<Executor>();
+    this.listener = listener;
+  }
+
+  public abstract void run();
+
+  protected abstract String getNextInputFilename();
+
+  protected abstract String getNextOutputFilename();
+
+  /**
+   * Call this after fuzzer execution to print out timing results.
+   */
+  public void printTimingInfo() {
+    totalTimer.stop();
+    timerDexInput.printTime(listener);
+    timerProgGen.printTime(listener);
+    timerMutation.printTime(listener);
+    timerDexOutput.printTime(listener);
+    timerChecksumCalc.printTime(listener);
+    totalTimer.printTime(listener);
+  }
+
+  /**
+   * Make sure this is called to correctly shutdown each Executor's StreamConsumers.
+   */
+  public void shutdown() {
+    if (executors != null) {
+      for (Executor executor : executors) {
+        executor.shutdown();
+      }
+    }
+  }
+
+  private void addExecutorsForArchitecture(Device device, Class<? extends Executor> quick,
+      Class<? extends Executor> optimizing, Class<? extends Executor> interpreter) {
+    // NB: Currently QuickBackend MUST come immediately before same arch's Interpreter.
+    // This is because intepreter execution relies on there being an OAT file already
+    // created to produce correct debug information. Otherwise we will see
+    // false-positive divergences.
+    try {
+      if (Options.useQuick) {
+        Constructor<? extends Executor> constructor =
+            quick.getConstructor(BaseListener.class, Device.class);
+        executors.add(constructor.newInstance(listener, device));
+      }
+      if (Options.useOptimizing) {
+        Constructor<? extends Executor> constructor =
+            optimizing.getConstructor(BaseListener.class, Device.class);
+        executors.add(constructor.newInstance(listener, device));
+      }
+      if (Options.useInterpreter) {
+        Constructor<? extends Executor> constructor =
+            interpreter.getConstructor(BaseListener.class, Device.class);
+        executors.add(constructor.newInstance(listener, device));
+      }
+    } catch (NoSuchMethodException e) {
+      Log.errorAndQuit("Executor doesn't have correct constructor.");
+    } catch (InstantiationException e) {
+      Log.errorAndQuit("Executor couldn't be instantiated.");
+    } catch (IllegalAccessException e) {
+      Log.errorAndQuit("Executor couldn't be accessed.");
+    } catch (IllegalArgumentException e) {
+      Log.errorAndQuit("Invalid arguments to instantiation of Executor.");
+    } catch (InvocationTargetException e) {
+      Log.errorAndQuit("Instantiation of Executor threw an Exception!");
+    }
+  }
+
+  protected void addExecutors() {
+    Device device = null;
+    if (Options.local) {
+      device = new Device();
+    } else {
+      device = new Device(Options.deviceName, Options.noBootImage);
+    }
+
+    if (Options.useArchArm64) {
+      addExecutorsForArchitecture(device, Arm64QuickBackendExecutor.class,
+          Arm64OptimizingBackendExecutor.class, Arm64InterpreterExecutor.class);
+    }
+
+    if (Options.useArchArm) {
+      addExecutorsForArchitecture(device, ArmQuickBackendExecutor.class,
+          ArmOptimizingBackendExecutor.class, ArmInterpreterExecutor.class);
+    }
+
+    if (Options.useArchX86_64) {
+      addExecutorsForArchitecture(device, X86_64QuickBackendExecutor.class,
+          X86_64OptimizingBackendExecutor.class, X86_64InterpreterExecutor.class);
+    }
+
+    if (Options.useArchX86) {
+      addExecutorsForArchitecture(device, X86QuickBackendExecutor.class,
+          X86OptimizingBackendExecutor.class, X86InterpreterExecutor.class);
+    }
+
+    if (Options.useArchMips64) {
+      addExecutorsForArchitecture(device, Mips64QuickBackendExecutor.class,
+          Mips64OptimizingBackendExecutor.class, Mips64InterpreterExecutor.class);
+    }
+
+    if (Options.useArchMips) {
+      addExecutorsForArchitecture(device, MipsQuickBackendExecutor.class,
+          MipsOptimizingBackendExecutor.class, MipsInterpreterExecutor.class);
+    }
+
+    // Add the first backend as the golden executor for self-divergence tests.
+    goldenExecutor = executors.get(0);
+  }
+
+  /**
+   * Called from each Fuzzer subclass that we can instantiate. Parses the program, fuzzes it,
+   * and then saves it, if mutation was successful. We can use --skip-mutation to bypass
+   * the mutation phase, if we wanted to verify that a test program itself works.
+   */
+  protected Program fuzz() {
+    String inputFile = getNextInputFilename();
+    Program program = loadProgram(inputFile, null);
+    if (program == null) {
+      Log.errorAndQuit("Problem loading seed file.");
+    }
+    // Mutate the program.
+    if (!Options.skipMutation) {
+      timerMutation.start();
+      program.mutateTheProgram();
+
+      mutatedSuccessfully = program.updateRawDexFile();
+      timerMutation.stop();
+      if (!mutatedSuccessfully) {
+        listener.handleMutationFail();
+      }
+    } else {
+      Log.info("Skipping mutation stage as requested.");
+      mutatedSuccessfully = true;
+    }
+    if (mutatedSuccessfully) {
+      savedSuccessfully = saveProgram(program, getNextOutputFilename());
+    }
+    return program;
+  }
+
+  protected boolean safeToExecute() {
+    return mutatedSuccessfully && savedSuccessfully;
+  }
+
+  protected void execute(Program program) {
+    if (!safeToExecute()) {
+      Log.errorAndQuit("Your Fuzzer subclass called execute() "
+          + "without checking safeToExecute()!");
+    }
+
+    String programName = getNextOutputFilename();
+    boolean verified = true;
+    if (!Options.skipHostVerify) {
+      verified = goldenExecutor.verifyOnHost(programName);
+    }
+    if (verified) {
+      boolean skipAnalysis = false;
+      boolean uploadedToTarget = false;
+      if (!Options.skipHostVerify) {
+        listener.handleSuccessfulHostVerification();
+      }
+      for (Executor executor : executors) {
+        executor.reset();
+        if (!uploadedToTarget) {
+          executor.uploadToTarget(programName);
+        } else {
+          uploadedToTarget = true;
+        }
+        if (executor.needsCleanCodeCache()) {
+          executor.deleteGeneratedOatFile(programName);
+        }
+        executor.execute(programName);
+        if (!executor.verifyOnTarget()) {
+          listener.handleFailedTargetVerification();
+          skipAnalysis = true;
+          break;
+        }
+        // Results are saved in the executors until they reset, usually at the
+        // next iteration.
+      }
+
+      if (!skipAnalysis) {
+        listener.handleSuccessfullyFuzzedFile(programName);
+        analyseResults(program, programName);
+      }
+    }
+    mutatedSuccessfully = false;
+    savedSuccessfully = false;
+  }
+
+  /**
+   * Checks if the different outputs we observed align with different architectures.
+   */
+  private boolean checkForArchitectureSplit(Map<String, List<Executor>> outputMap) {
+    if (outputMap.size() != 2) {
+      // Cannot have a two-way split if we don't have 2 kinds of output.
+      return false;
+    }
+
+    Architecture[] architectures = new Architecture[2];
+    int archIdx = 0;
+
+    // For each kind of output we saw, make sure they all
+    // came from the same architecture.
+    for (List<Executor> executorList : outputMap.values()) {
+      architectures[archIdx] = executorList.get(0).getArchitecture();
+      for (int execIdx = 1; execIdx < executorList.size(); execIdx++) {
+        if (executorList.get(execIdx).getArchitecture() != architectures[archIdx]) {
+          // Not every executor with this output shared the same architecture.
+          return false;
+        }
+      }
+      archIdx++;
+    }
+
+    // Now make sure that the two outputs we saw were different architectures.
+    if (architectures[0] == architectures[1]) {
+      return false;
+    }
+    return true;
+  }
+
+  private boolean checkGoldenExecutorForSelfDivergence(String programName) {
+    // Run golden executor 5 times, make sure it always produces
+    // the same output, otherwise report that it is self-divergent.
+
+    // TODO: Instead, produce a list of acceptable outputs, and see if the divergent
+    // outputs of the backends fall within this set of outputs.
+    String seenOutput = null;
+    for (int i = 0; i < 5; i++) {
+      goldenExecutor.reset();
+      goldenExecutor.execute(programName);
+      String output = goldenExecutor.getResult().getFlattenedOutput();
+      if (seenOutput == null) {
+        seenOutput = output;
+      } else if (!seenOutput.equals(output)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void analyseResults(Program program, String programName) {
+    // Check timeouts.
+    // Construct two lists of executors, those who timed out, and those who did not.
+    // Report if we had some timeouts.
+    List<Executor> timedOut = new ArrayList<Executor>();
+    List<Executor> didNotTimeOut = new ArrayList<Executor>();
+    for (Executor executor : executors) {
+      if (executor.getResult().isTimeout()) {
+        timedOut.add(executor);
+      } else {
+        didNotTimeOut.add(executor);
+      }
+    }
+    if (!timedOut.isEmpty()) {
+      listener.handleTimeouts(timedOut, didNotTimeOut);
+      // Do not bother reporting divergence information.
+      return;
+    }
+
+    // Check divergences.
+    // Construct a map {output1: [executor that produced output1, ...], output2: [...]}
+    // If the map has more than one output, we had divergence, report it.
+    Map<String, List<Executor>> outputMap = new HashMap<String, List<Executor>>();
+    for (Executor executor : executors) {
+      String output = executor.getResult().getFlattenedOutput();
+      if (Options.dumpOutput) {
+        listener.handleDumpOutput(
+            executor.getResult().getFlattenedOutputWithNewlines(), executor);
+      }
+      if (outputMap.containsKey(output)) {
+        outputMap.get(output).add(executor);
+      } else {
+        List<Executor> newList = new ArrayList<Executor>();
+        newList.add(executor);
+        outputMap.put(output, newList);
+      }
+    }
+
+    if (outputMap.size() > 1) {
+      // Report that we had divergence.
+      listener.handleDivergences(outputMap);
+      listener.handleMutations(program.getMutations());
+      // If we found divergences, try running the "golden executor"
+      // a few times in succession, to see if the output it produces is different
+      // from run to run. If so, then we're probably executing something with either:
+      //  a) randomness
+      //  b) timing-dependent code
+      //  c) threads
+      // So we will not consider it a "true" divergence, but still useful?
+      if (checkGoldenExecutorForSelfDivergence(programName)) {
+        listener.handleSelfDivergence();
+        return;
+      }
+      // If we found divergences, try checking if the differences
+      // in outputs align with differences in architectures.
+      // For example, if we have: {Output1: [ARM, ARM], Output2: [ARM64, ARM64]}
+      if (checkForArchitectureSplit(outputMap)) {
+        listener.handleArchitectureSplit();
+      }
+    } else {
+      // No problems with execution.
+      listener.handleSuccess(outputMap);
+    }
+  }
+
+  private Program loadProgram(String inputName, List<Mutation> mutations) {
+    Program program = null;
+    try {
+      DexRandomAccessFile input = new DexRandomAccessFile(inputName, "r");
+      offsetTracker = new OffsetTracker();
+      input.setOffsetTracker(offsetTracker);
+      // Read the raw DexFile
+      RawDexFile rawDexFile = new RawDexFile();
+      timerDexInput.start();
+      rawDexFile.read(input);
+      timerDexInput.stop();
+      input.close();
+      // Create the program view.
+      timerProgGen.start();
+      program = new Program(rawDexFile, mutations, listener);
+      timerProgGen.stop();
+    } catch (FileNotFoundException e) {
+      Log.errorAndQuit("Couldn't open a file called " + inputName);
+    } catch (IOException e) {
+      Log.errorAndQuit("IOException when trying to load a DEX test file!");
+    }
+    return program;
+  }
+
+  private boolean saveProgram(Program program, String outputName) {
+    boolean success = false;
+
+    try {
+      // Write out the results of mutation.
+      DexRandomAccessFile output = new DexRandomAccessFile(outputName, "rw");
+      output.setOffsetTracker(offsetTracker);
+      // Delete the contents of the file, in case it already existed.
+      output.setLength(0);
+      // Write out the file.
+      timerDexOutput.start();
+      program.writeRawDexFile(output);
+      timerDexOutput.stop();
+      // Recalculate the header info.
+      timerChecksumCalc.start();
+      program.updateRawDexFileHeader(output);
+      timerChecksumCalc.stop();
+      output.close();
+      success = true;
+    } catch (FileNotFoundException e) {
+      Log.errorAndQuit("Couldn't open a file called " + outputName);
+    } catch (IOException e) {
+      Log.errorAndQuit("IOException when trying to save a DEX test file!");
+    }
+    return success;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultiple.java b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultiple.java
new file mode 100644
index 0000000..8abaeb0
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultiple.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.Options;
+import dexfuzz.listeners.BaseListener;
+
+/**
+ * Superclass for fuzzing strategies that perform multiple fuzzes, and want
+ * their inputs to come from the input list in a round-robin fashion.
+ */
+public abstract class FuzzerMultiple extends Fuzzer {
+  protected int iterations;
+
+  protected FuzzerMultiple(BaseListener listener) {
+    super(listener);
+  }
+
+  @Override
+  protected String getNextInputFilename() {
+    String inputFile = Options.inputFileList.get(0);
+    if (Options.inputFileList.size() > 1) {
+      int nextIndex = iterations % Options.inputFileList.size();
+      inputFile = Options.inputFileList.get(nextIndex);
+    }
+    listener.handleFuzzingFile(inputFile);
+    return inputFile;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultipleExecute.java b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultipleExecute.java
new file mode 100644
index 0000000..0cf6df7
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultipleExecute.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.Options;
+import dexfuzz.listeners.BaseListener;
+import dexfuzz.program.Program;
+
+/**
+ * Fuzz programs multiple times, testing each.
+ */
+public class FuzzerMultipleExecute extends FuzzerMultiple {
+  public FuzzerMultipleExecute(BaseListener listener) {
+    super(listener);
+    addExecutors();
+  }
+
+  @Override
+  protected String getNextOutputFilename() {
+    // In MultipleExecute, always use the same output.
+    return Options.outputFile;
+  }
+
+  @Override
+  public void run() {
+    // TODO: Test that all seed files execute correctly before they are mutated!
+    for (iterations = 0; iterations < Options.repeat; iterations++) {
+      listener.handleIterationStarted(iterations);
+      Program program = fuzz();
+      if (safeToExecute()) {
+        execute(program);
+      }
+      listener.handleIterationFinished(iterations);
+    }
+    listener.handleSummary();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultipleNoExecute.java b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultipleNoExecute.java
new file mode 100644
index 0000000..fea8788
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerMultipleNoExecute.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.Options;
+import dexfuzz.listeners.BaseListener;
+
+/**
+ * Fuzz programs multiple times, writing each one to a new DEX file.
+ */
+public class FuzzerMultipleNoExecute extends FuzzerMultiple {
+  public FuzzerMultipleNoExecute(BaseListener listener) {
+    super(listener);
+  }
+
+  @Override
+  protected String getNextOutputFilename() {
+    // In MultipleNoExecute, produce multiple files, each prefixed
+    // with the iteration value.
+    return String.format("%09d_%s", iterations, Options.outputFile);
+  }
+
+  @Override
+  public void run() {
+    for (iterations = 0; iterations < Options.repeat; iterations++) {
+      listener.handleIterationStarted(iterations);
+      fuzz();
+      listener.handleIterationFinished(iterations);
+    }
+    listener.handleSummary();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingle.java b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingle.java
new file mode 100644
index 0000000..68b47c2
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingle.java
@@ -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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.Options;
+import dexfuzz.listeners.BaseListener;
+
+/**
+ * Superclass for fuzzers that fuzz once.
+ */
+public abstract class FuzzerSingle extends Fuzzer {
+  protected FuzzerSingle(BaseListener listener) {
+    super(listener);
+  }
+
+  @Override
+  protected String getNextInputFilename() {
+    return Options.inputFileList.get(0);
+  }
+
+  protected String getNextOutputFilename() {
+    return Options.outputFile;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingleExecute.java b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingleExecute.java
new file mode 100644
index 0000000..de0c7db
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingleExecute.java
@@ -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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.listeners.BaseListener;
+import dexfuzz.program.Program;
+
+/**
+ * Fuzz a DEX file once, and test it.
+ */
+public class FuzzerSingleExecute extends FuzzerSingle {
+  public FuzzerSingleExecute(BaseListener listener) {
+    super(listener);
+    addExecutors();
+  }
+
+  @Override
+  public void run() {
+    Program program = fuzz();
+    if (safeToExecute()) {
+      execute(program);
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingleNoExecute.java b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingleNoExecute.java
new file mode 100644
index 0000000..6015284
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/FuzzerSingleNoExecute.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.fuzzers;
+
+import dexfuzz.listeners.BaseListener;
+
+/**
+ * Fuzz a DEX file once, but don't test it.
+ */
+public class FuzzerSingleNoExecute extends FuzzerSingle {
+  public FuzzerSingleNoExecute(BaseListener listener) {
+    super(listener);
+  }
+
+  @Override
+  public void run() {
+    fuzz();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/BaseListener.java b/tools/dexfuzz/src/dexfuzz/listeners/BaseListener.java
new file mode 100644
index 0000000..e33fb09
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/BaseListener.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.listeners;
+
+import dexfuzz.ExecutionResult;
+import dexfuzz.executors.Executor;
+import dexfuzz.program.Mutation;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for Listeners, who are notified about certain events in dexfuzz's execution.
+ */
+public abstract class BaseListener {
+  public void setup() { }
+
+  public void shutdown() { }
+
+  public void handleSuccessfulHostVerification() { }
+
+  public void handleFailedHostVerification(ExecutionResult verificationResult) { }
+
+  public void handleFailedTargetVerification() { }
+
+  public void handleIterationStarted(int iteration) { }
+
+  public void handleIterationFinished(int iteration) { }
+
+  public void handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut) { }
+
+  public void handleDivergences(Map<String, List<Executor>> outputMap) { }
+
+  public void handleFuzzingFile(String inputFile) { }
+
+  public void handleSeed(long seed) { }
+
+  public void handleHostVerificationSigabort(ExecutionResult verificationResult) { }
+
+  public void handleSuccess(Map<String, List<Executor>> outputMap) { }
+
+  public void handleDumpOutput(String outputLine, Executor executor) { }
+
+  public void handleDumpVerify(String verifyLine) { }
+
+  public void handleMutationStats(String statsString) { }
+
+  public void handleTiming(String name, float elapsedTime) { }
+
+  public void handleMutationFail() { }
+
+  public void handleSummary() { }
+
+  public void handleSuccessfullyFuzzedFile(String programName) { }
+
+  public void handleSelfDivergence() { }
+
+  public void handleMessage(String msg) { }
+
+  public void handleMutations(List<Mutation> mutations) { }
+
+  public void handleArchitectureSplit() { }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/ConsoleLoggerListener.java b/tools/dexfuzz/src/dexfuzz/listeners/ConsoleLoggerListener.java
new file mode 100644
index 0000000..1ea74d9
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/ConsoleLoggerListener.java
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.listeners;
+
+import dexfuzz.ExecutionResult;
+import dexfuzz.executors.Executor;
+import dexfuzz.program.Mutation;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Logs output to the console, when not using --repeat.
+ */
+public class ConsoleLoggerListener extends BaseListener {
+  @Override
+  public void setup() {
+
+  }
+
+  @Override
+  public void shutdown() {
+
+  }
+
+  private void logToConsole(String msg) {
+    System.out.println("CONSOLE: " + msg);
+  }
+
+  @Override
+  public void handleSuccessfulHostVerification() {
+    logToConsole("Successful host verification");
+  }
+
+  @Override
+  public void handleFailedHostVerification(ExecutionResult verificationResult) {
+    logToConsole("Failed host verification");
+  }
+
+  @Override
+  public void handleMutations(List<Mutation> mutations) {
+    for (Mutation mutation : mutations) {
+      logToConsole("Applied mutation: " + mutation.toString());
+    }
+  }
+
+  @Override
+  public void handleArchitectureSplit() {
+    logToConsole("Detected architectural split.");
+  }
+
+  @Override
+  public void handleFailedTargetVerification() {
+    logToConsole("Failed target verification");
+  }
+
+  @Override
+  public void handleIterationStarted(int iteration) {
+    logToConsole("Starting iteration " + iteration);
+  }
+
+  @Override
+  public void handleIterationFinished(int iteration) {
+    logToConsole("Finished iteration " + iteration);
+  }
+
+  @Override
+  public void handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut) {
+    logToConsole("Timed out: " + timedOut.size() + " Did not time out: " + didNotTimeOut.size());
+  }
+
+  @Override
+  public void handleDivergences(Map<String, List<Executor>> outputMap) {
+    logToConsole("Got divergences!");
+    int outputCount = 1;
+    for (List<Executor> executors : outputMap.values()) {
+      logToConsole("Output " + outputCount + ":");
+      for (Executor executor : executors) {
+        logToConsole("  " + executor.getName());
+      }
+      outputCount++;
+    }
+  }
+
+  @Override
+  public void handleFuzzingFile(String inputFile) {
+    logToConsole("Fuzzing: " + inputFile);
+  }
+
+  @Override
+  public void handleSeed(long seed) {
+    logToConsole("Seed: " + seed);
+  }
+
+  @Override
+  public void handleHostVerificationSigabort(ExecutionResult verificationResult) {
+    logToConsole("Sigaborted host verification");
+  }
+
+  @Override
+  public void handleSuccessfullyFuzzedFile(String programName) {
+    logToConsole("Program " + programName + " successfully fuzzed.");
+  }
+
+  @Override
+  public void handleSuccess(Map<String, List<Executor>> outputMap) {
+    logToConsole("Execution was successful");
+  }
+
+  @Override
+  public void handleDumpOutput(String outputLine, Executor executor) {
+    logToConsole(executor.getName() + " OUTPUT: " + outputLine);
+  }
+
+  @Override
+  public void handleDumpVerify(String verifyLine) {
+    logToConsole("VERIFY: " + verifyLine);
+  }
+
+  @Override
+  public void handleMutationFail() {
+    logToConsole("DEX file was not mutated");
+  }
+
+  @Override
+  public void handleMutationStats(String statsString) {
+    logToConsole("Mutations performed: " + statsString);
+  }
+
+  @Override
+  public void handleTiming(String name, float elapsedTime) {
+    logToConsole(String.format("'%s': %.3fs", name, elapsedTime));
+  }
+
+  @Override
+  public void handleSummary() {
+    logToConsole("--- SUMMARY ---");
+  }
+
+  @Override
+  public void handleSelfDivergence() {
+    logToConsole("Seen self divergence");
+  }
+
+  @Override
+  public void handleMessage(String msg) {
+    logToConsole(msg);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/LogFileListener.java b/tools/dexfuzz/src/dexfuzz/listeners/LogFileListener.java
new file mode 100644
index 0000000..09ee756
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/LogFileListener.java
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.listeners;
+
+import dexfuzz.ExecutionResult;
+import dexfuzz.Log;
+import dexfuzz.executors.Executor;
+import dexfuzz.program.Mutation;
+import dexfuzz.program.MutationSerializer;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Logs events to a file.
+ */
+public class LogFileListener extends BaseListener {
+  private BufferedWriter writer;
+  boolean ready = false;
+
+  long successfulVerification;
+  long failedVerification;
+  long failedMutation;
+  long success;
+  long timedOut;
+  long divergence;
+  long selfDivergent;
+  long architectureSplit;
+  long iterations;
+
+  private String logFile;
+
+  public LogFileListener(String logFile) {
+    this.logFile = logFile;
+  }
+
+  @Override
+  public void setup() {
+    try {
+      writer = new BufferedWriter(new FileWriter(logFile));
+      ready = true;
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  public void shutdown() {
+    try {
+      writer.close();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    Log.always("Full log in " + logFile);
+  }
+
+  private void write(String msg) {
+    if (!ready) {
+      return;
+    }
+    try {
+      writer.write(msg + "\n");
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  public void handleSuccessfulHostVerification() {
+    write("Host verification: SUCCESS");
+    successfulVerification++;
+  }
+
+  @Override
+  public void handleFailedHostVerification(ExecutionResult verificationResult) {
+    write("Host verification: FAILED");
+    failedVerification++;
+  }
+
+  @Override
+  public void handleFailedTargetVerification() {
+    write("Target verification: FAILED");
+    failedVerification++;
+  }
+
+  @Override
+  public void handleIterationStarted(int iteration) {
+    write("--> FUZZ " + (iteration + 1));
+    Date now = new Date(System.currentTimeMillis());
+    write("Time started: " + now.toString());
+    iterations++;
+  }
+
+  @Override
+  public void handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut) {
+    write("Some executors timed out.");
+    write("Timed out:");
+    for (Executor executor : timedOut) {
+      write("  " + executor.getName());
+    }
+    if (!didNotTimeOut.isEmpty()) {
+      write("Did not time out:");
+      for (Executor executor : didNotTimeOut) {
+        write("  " + executor.getName());
+      }
+    }
+    this.timedOut++;
+  }
+
+  @Override
+  public void handleDivergences(Map<String, List<Executor>> outputMap) {
+    write("DIVERGENCE between some executors!");
+    int outputCount = 1;
+    for (List<Executor> executors : outputMap.values()) {
+      write("Output " + outputCount + ":");
+      for (Executor executor : executors) {
+        write("  " + executor.getName());
+      }
+      outputCount++;
+    }
+    divergence++;
+
+    // You are probably interested in reading about these divergences while fuzzing
+    // is taking place, so flush the writer now.
+    try {
+      writer.flush();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  public void handleFuzzingFile(String inputFile) {
+    write("Fuzzing file '" + inputFile + "'");
+  }
+
+  @Override
+  public void handleSeed(long seed) {
+    write("Using " + seed + " for seed.");
+    // Flush the seed as well, so if anything goes wrong we can see what seed lead
+    // to the issue.
+    try {
+      writer.flush();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  public void handleHostVerificationSigabort(ExecutionResult verificationResult) {
+    write("Host verification: SIGABORTED");
+  }
+
+  @Override
+  public void handleSuccess(Map<String, List<Executor>> outputMap) {
+    write("All executors agreed on result.");
+    success++;
+  }
+
+  @Override
+  public void handleDumpOutput(String outputLine, Executor executor) {
+    write(executor.getName() + " OUTPUT:");
+    write(outputLine);
+  }
+
+  @Override
+  public void handleDumpVerify(String verifyLine) {
+    write("VERIFY: " + verifyLine);
+  }
+
+  @Override
+  public void handleMutationStats(String statsString) {
+    write("Mutation Stats: " + statsString);
+  }
+
+  @Override
+  public void handleTiming(String name, float elapsedTime) {
+    write(String.format("'%s': %.3fs", name, elapsedTime));
+  }
+
+  @Override
+  public void handleMutationFail() {
+    write("Mutation process: FAILED");
+    failedMutation++;
+  }
+
+  @Override
+  public void handleSummary() {
+    write("");
+    write("---+++--- SUMMARY ---+++---");
+    write("Fuzzing attempts: " + iterations);
+    write("  Failed verification: " + failedVerification);
+    write("  Failed mutation: " + failedMutation);
+    write("  Timed out: " + timedOut);
+    write("Successful: " + success);
+    write("  Self divergent: " + selfDivergent);
+    write("  Architecture split: " + architectureSplit);
+    write("Produced divergence: " + divergence);
+
+    long truelyDivergent = divergence - (selfDivergent + architectureSplit);
+    long verified = success + timedOut + truelyDivergent;
+
+    write("");
+
+    float verifiedTotalRatio =
+        (((float) (verified)) / iterations) * 100.0f;
+    write(String.format("Percentage Verified/Total: %.3f%%", verifiedTotalRatio));
+
+    float timedOutVerifiedRatio =
+        (((float) timedOut) / (verified)) * 100.0f;
+    write(String.format("Percentage Timed Out/Verified: %.3f%%", timedOutVerifiedRatio));
+
+    float successfulVerifiedRatio =
+        (((float) success) / (verified)) * 100.0f;
+    write(String.format("Percentage Successful/Verified: %.3f%%", successfulVerifiedRatio));
+
+    float divergentVerifiedRatio =
+        (((float) truelyDivergent) / (verified)) * 100.0f;
+    write(String.format("Percentage Divergent/Verified: %.3f%%", divergentVerifiedRatio));
+
+    write("---+++--- SUMMARY ---+++---");
+    write("");
+  }
+
+  @Override
+  public void handleIterationFinished(int iteration) {
+    write("");
+  }
+
+  @Override
+  public void handleSuccessfullyFuzzedFile(String programName) {
+    write("Successfully fuzzed file '" + programName + "'");
+  }
+
+  @Override
+  public void handleSelfDivergence() {
+    write("Golden Executor was self-divergent!");
+    selfDivergent++;
+  }
+
+  @Override
+  public void handleArchitectureSplit() {
+    write("Divergent outputs align with difference in architectures.");
+    architectureSplit++;
+  }
+
+  @Override
+  public void handleMessage(String msg) {
+    write(msg);
+  }
+
+  @Override
+  public void handleMutations(List<Mutation> mutations) {
+    write("Mutations Report");
+    for (Mutation mutation : mutations) {
+      write(MutationSerializer.getMutationString(mutation));
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/MultiplexerListener.java b/tools/dexfuzz/src/dexfuzz/listeners/MultiplexerListener.java
new file mode 100644
index 0000000..28ebce7
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/MultiplexerListener.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.listeners;
+
+import dexfuzz.ExecutionResult;
+import dexfuzz.executors.Executor;
+import dexfuzz.program.Mutation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles situation where multiple Listeners are wanted, passes notifications
+ * onto each Listener it is responsible for.
+ */
+public class MultiplexerListener extends BaseListener {
+
+  private List<BaseListener> listeners;
+
+  @Override
+  public void setup() {
+    listeners = new ArrayList<BaseListener>();
+  }
+
+  public void addListener(BaseListener listener) {
+    listeners.add(listener);
+    listener.setup();
+  }
+
+  @Override
+  public void shutdown() {
+    for (BaseListener listener : listeners) {
+      listener.shutdown();
+    }
+  }
+
+  @Override
+  public void handleSuccessfulHostVerification() {
+    for (BaseListener listener : listeners) {
+      listener.handleSuccessfulHostVerification();
+    }
+  }
+
+  @Override
+  public void handleFailedHostVerification(ExecutionResult verificationResult) {
+    for (BaseListener listener : listeners) {
+      listener.handleFailedHostVerification(verificationResult);
+    }
+  }
+
+  @Override
+  public void handleFailedTargetVerification() {
+    for (BaseListener listener : listeners) {
+      listener.handleFailedTargetVerification();
+    }
+  }
+
+  @Override
+  public void handleIterationStarted(int iteration) {
+    for (BaseListener listener : listeners) {
+      listener.handleIterationStarted(iteration);
+    }
+  }
+
+  @Override
+  public void handleIterationFinished(int iteration) {
+    for (BaseListener listener : listeners) {
+      listener.handleIterationFinished(iteration);
+    }
+  }
+
+  @Override
+  public void handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut) {
+    for (BaseListener listener : listeners) {
+      listener.handleTimeouts(timedOut, didNotTimeOut);
+    }
+  }
+
+  @Override
+  public void handleDivergences(Map<String, List<Executor>> outputMap) {
+    for (BaseListener listener : listeners) {
+      listener.handleDivergences(outputMap);
+    }
+  }
+
+  @Override
+  public void handleFuzzingFile(String inputFile) {
+    for (BaseListener listener : listeners) {
+      listener.handleFuzzingFile(inputFile);
+    }
+  }
+
+  @Override
+  public void handleSeed(long seed) {
+    for (BaseListener listener : listeners) {
+      listener.handleSeed(seed);
+    }
+  }
+
+  @Override
+  public void handleHostVerificationSigabort(ExecutionResult verificationResult) {
+    for (BaseListener listener : listeners) {
+      listener.handleHostVerificationSigabort(verificationResult);
+    }
+  }
+
+  @Override
+  public void handleSuccess(Map<String, List<Executor>> outputMap) {
+    for (BaseListener listener : listeners) {
+      listener.handleSuccess(outputMap);
+    }
+  }
+
+  @Override
+  public void handleDumpOutput(String outputLine, Executor executor) {
+    for (BaseListener listener : listeners) {
+      listener.handleDumpOutput(outputLine, executor);
+    }
+  }
+
+  @Override
+  public void handleDumpVerify(String verifyLine) {
+    for (BaseListener listener : listeners) {
+      listener.handleDumpVerify(verifyLine);
+    }
+  }
+
+  @Override
+  public void handleMutationStats(String statsString) {
+    for (BaseListener listener : listeners) {
+      listener.handleMutationStats(statsString);
+    }
+  }
+
+  @Override
+  public void handleTiming(String name, float elapsedTime) {
+    for (BaseListener listener : listeners) {
+      listener.handleTiming(name, elapsedTime);
+    }
+  }
+
+  @Override
+  public void handleMutationFail() {
+    for (BaseListener listener : listeners) {
+      listener.handleMutationFail();
+    }
+  }
+
+  @Override
+  public void handleSummary() {
+    for (BaseListener listener : listeners) {
+      listener.handleSummary();
+    }
+  }
+
+  @Override
+  public void handleSuccessfullyFuzzedFile(String programName) {
+    for (BaseListener listener : listeners) {
+      listener.handleSuccessfullyFuzzedFile(programName);
+    }
+  }
+
+  @Override
+  public void handleSelfDivergence() {
+    for (BaseListener listener : listeners) {
+      listener.handleSelfDivergence();
+    }
+  }
+
+  @Override
+  public void handleMessage(String msg) {
+    for (BaseListener listener : listeners) {
+      listener.handleMessage(msg);
+    }
+  }
+
+  @Override
+  public void handleMutations(List<Mutation> mutations) {
+    for (BaseListener listener : listeners) {
+      listener.handleMutations(mutations);
+    }
+  }
+
+  @Override
+  public void handleArchitectureSplit() {
+    for (BaseListener listener : listeners) {
+      listener.handleArchitectureSplit();
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/UniqueProgramTrackerListener.java b/tools/dexfuzz/src/dexfuzz/listeners/UniqueProgramTrackerListener.java
new file mode 100644
index 0000000..affaffc
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/UniqueProgramTrackerListener.java
@@ -0,0 +1,259 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.listeners;
+
+import dexfuzz.Log;
+import dexfuzz.Options;
+import dexfuzz.executors.Executor;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tracks unique programs and outputs. Also saves divergent programs!
+ */
+public class UniqueProgramTrackerListener extends BaseListener {
+  /**
+   * Map of unique program MD5 sums, mapped to times seen.
+   */
+  private Map<String, Integer> uniquePrograms;
+
+  /**
+   * Map of unique program outputs (MD5'd), mapped to times seen.
+   */
+  private Map<String, Integer> uniqueOutputs;
+
+  /**
+   * Used to remember the seed used to fuzz the fuzzed file, so we can save it with this
+   * seed as a name, if we find a divergence.
+   */
+  private long currentSeed;
+
+  /**
+   * Used to remember the name of the file we've fuzzed, so we can save it if we
+   * find a divergence.
+   */
+  private String fuzzedFile;
+
+  private MessageDigest digest;
+  private String databaseFile;
+
+  /**
+   * Save the database every X number of iterations.
+   */
+  private static final int saveDatabasePeriod = 20;
+
+  public UniqueProgramTrackerListener(String databaseFile) {
+    this.databaseFile = databaseFile;
+  }
+
+  @Override
+  public void handleSeed(long seed) {
+    currentSeed = seed;
+  }
+
+  /**
+   * Given a program filename, calculate the MD5sum of
+   * this program.
+   */
+  private String getMD5SumOfProgram(String programName) {
+    byte[] buf = new byte[256];
+    try {
+      FileInputStream stream = new FileInputStream(programName);
+      boolean done = false;
+      while (!done) {
+        int bytesRead = stream.read(buf);
+        if (bytesRead == -1) {
+          done = true;
+        } else {
+          digest.update(buf);
+        }
+      }
+      stream.close();
+    } catch (FileNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    return new String(digest.digest());
+  }
+
+  private String getMD5SumOfOutput(String output) {
+    digest.update(output.getBytes());
+    return new String(digest.digest());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void loadUniqueProgsData() {
+    File file = new File(databaseFile);
+    if (!file.exists()) {
+      uniquePrograms = new HashMap<String, Integer>();
+      uniqueOutputs = new HashMap<String, Integer>();
+      return;
+    }
+
+    try {
+      ObjectInputStream objectStream =
+          new ObjectInputStream(new FileInputStream(databaseFile));
+      uniquePrograms = (Map<String, Integer>) objectStream.readObject();
+      uniqueOutputs = (Map<String, Integer>) objectStream.readObject();
+      objectStream.close();
+    } catch (FileNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    } catch (ClassNotFoundException e) {
+      e.printStackTrace();
+    }
+
+  }
+
+  private void saveUniqueProgsData() {
+    // Since we could potentially stop the program while writing out this DB,
+    // copy the old file beforehand, and then delete it if we successfully wrote out the DB.
+    boolean oldWasSaved = false;
+    File file = new File(databaseFile);
+    if (file.exists()) {
+      try {
+        Process process =
+            Runtime.getRuntime().exec(String.format("cp %1$s %1$s.old", databaseFile));
+        // Shouldn't block, cp shouldn't produce output.
+        process.waitFor();
+        oldWasSaved = true;
+      } catch (IOException exception) {
+        exception.printStackTrace();
+      } catch (InterruptedException exception) {
+        exception.printStackTrace();
+      }
+    }
+
+    // Now write out the DB.
+    boolean success = false;
+    try {
+      ObjectOutputStream objectStream =
+          new ObjectOutputStream(new FileOutputStream(databaseFile));
+      objectStream.writeObject(uniquePrograms);
+      objectStream.writeObject(uniqueOutputs);
+      objectStream.close();
+      success = true;
+    } catch (FileNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    // If we get here, and we successfully wrote out the DB, delete the saved one.
+    if (oldWasSaved && success) {
+      try {
+        Process process =
+            Runtime.getRuntime().exec(String.format("rm %s.old", databaseFile));
+        // Shouldn't block, rm shouldn't produce output.
+        process.waitFor();
+      } catch (IOException exception) {
+        exception.printStackTrace();
+      } catch (InterruptedException exception) {
+        exception.printStackTrace();
+      }
+    } else if (oldWasSaved && !success) {
+      Log.error("Failed to successfully write out the unique programs DB!");
+      Log.error("Old DB should be saved in " + databaseFile + ".old");
+    }
+  }
+
+  private void addToMap(String md5sum, Map<String, Integer> map) {
+    if (map.containsKey(md5sum)) {
+      map.put(md5sum, map.get(md5sum) + 1);
+    } else {
+      map.put(md5sum, 1);
+    }
+  }
+
+  private void saveDivergentProgram() {
+    File before = new File(fuzzedFile);
+    File after = new File(String.format("divergent_programs/%d.dex", currentSeed));
+    boolean success = before.renameTo(after);
+    if (!success) {
+      Log.error("Failed to save divergent program! Does divergent_programs/ exist?");
+    }
+  }
+
+  @Override
+  public void setup() {
+    try {
+      digest = MessageDigest.getInstance("MD5");
+      loadUniqueProgsData();
+    } catch (NoSuchAlgorithmException e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  public void handleIterationFinished(int iteration) {
+    if ((iteration % saveDatabasePeriod) == (saveDatabasePeriod - 1)) {
+      saveUniqueProgsData();
+    }
+  }
+
+  @Override
+  public void handleSuccessfullyFuzzedFile(String programName) {
+    String md5sum = getMD5SumOfProgram(programName);
+    addToMap(md5sum, uniquePrograms);
+
+    fuzzedFile = programName;
+  }
+
+  @Override
+  public void handleDivergences(Map<String, List<Executor>> outputMap) {
+    // Just use the first one.
+    String output = (String) outputMap.keySet().toArray()[0];
+    String md5sum = getMD5SumOfOutput(output);
+    addToMap(md5sum, uniqueOutputs);
+
+    saveDivergentProgram();
+  }
+
+  @Override
+  public void handleSuccess(Map<String, List<Executor>> outputMap) {
+    // There's only one, use it.
+    String output = (String) outputMap.keySet().toArray()[0];
+    String md5sum = getMD5SumOfOutput(output);
+    addToMap(md5sum, uniqueOutputs);
+  }
+
+  @Override
+  public void handleSummary() {
+    if (Options.reportUnique) {
+      Log.always("-- UNIQUE PROGRAM REPORT --");
+      Log.always("Unique Programs Seen: " + uniquePrograms.size());
+      Log.always("Unique Outputs Seen: " + uniqueOutputs.size());
+      Log.always("---------------------------");
+    }
+
+    saveUniqueProgsData();
+  }
+
+}
diff --git a/tools/dexfuzz/src/dexfuzz/listeners/UpdatingConsoleListener.java b/tools/dexfuzz/src/dexfuzz/listeners/UpdatingConsoleListener.java
new file mode 100644
index 0000000..39d1d2f
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/listeners/UpdatingConsoleListener.java
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.listeners;
+
+import dexfuzz.ExecutionResult;
+import dexfuzz.executors.Executor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implements the live updating table of results when --repeat is being used.
+ */
+public class UpdatingConsoleListener extends BaseListener {
+  long successfulVerification;
+  long failedVerification;
+  long failedMutation;
+  long success;
+  long timedOut;
+  long divergence;
+  long selfDivergent;
+  long architectureSplit;
+  long iterations;
+
+  @Override
+  public void setup() {
+    System.out.println("|-----------------------------------------------------------------|");
+    System.out.println("|Iterations|VerifyFail|MutateFail|Timed Out |Successful|Divergence|");
+    System.out.println("|-----------------------------------------------------------------|");
+  }
+
+  @Override
+  public void handleSuccessfulHostVerification() {
+    successfulVerification++;
+  }
+
+  @Override
+  public void handleFailedHostVerification(ExecutionResult verificationResult) {
+    failedVerification++;
+  }
+
+  @Override
+  public void handleFailedTargetVerification() {
+    failedVerification++;
+  }
+
+  @Override
+  public void handleIterationStarted(int iteration) {
+    iterations++;
+  }
+
+  @Override
+  public void handleIterationFinished(int iteration) {
+    String output = String.format("| %-9d| %-9d| %-9d| %-9d| %-9d| %-9d|",
+        iterations, failedVerification, failedMutation, timedOut, success,
+        divergence - (selfDivergent + architectureSplit));
+    System.out.print("\r" + output);
+  }
+
+  @Override
+  public void handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut) {
+    this.timedOut++;
+  }
+
+  @Override
+  public void handleDivergences(Map<String, List<Executor>> outputMap) {
+    divergence++;
+  }
+
+  @Override
+  public void handleSelfDivergence() {
+    selfDivergent++;
+  }
+
+  @Override
+  public void handleArchitectureSplit() {
+    architectureSplit++;
+  }
+
+  @Override
+  public void handleSuccess(Map<String, List<Executor>> outputMap) {
+    success++;
+  }
+
+  @Override
+  public void handleMutationFail() {
+    failedMutation++;
+  }
+
+  @Override
+  public void handleSummary() {
+    System.out.println("\n|-----------------------------------------------------------------|");
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java b/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java
new file mode 100644
index 0000000..650501b
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/CodeTranslator.java
@@ -0,0 +1,592 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.Log;
+import dexfuzz.rawdex.CodeItem;
+import dexfuzz.rawdex.EncodedCatchHandler;
+import dexfuzz.rawdex.EncodedTypeAddrPair;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.TryItem;
+import dexfuzz.rawdex.formats.ContainsTarget;
+import dexfuzz.rawdex.formats.RawInsnHelper;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Translates from a CodeItem (the raw list of Instructions) to MutatableCode
+ * (graph of Instructions, using MInsns and subclasses) and vice-versa.
+ */
+public class CodeTranslator {
+
+  /**
+   * Given a raw DEX file's CodeItem, produce a MutatableCode object, that CodeMutators
+   * are designed to operate on.
+   * @param codeItemIdx Used to make sure the correct CodeItem is updated later after mutation.
+   * @return A new MutatableCode object, which contains all relevant information
+   *         obtained from the CodeItem.
+   */
+  public MutatableCode codeItemToMutatableCode(Program program, CodeItem codeItem,
+      int codeItemIdx, int mutatableCodeIdx) {
+    Log.debug("Translating CodeItem " + codeItemIdx
+        + " (" + codeItem.meta.methodName + ") to MutatableCode");
+
+    MutatableCode mutatableCode = new MutatableCode(program);
+
+    codeItem.registerMutatableCode(mutatableCode);
+
+    mutatableCode.name = codeItem.meta.methodName;
+    mutatableCode.shorty = codeItem.meta.shorty;
+    mutatableCode.isStatic = codeItem.meta.isStatic;
+
+    mutatableCode.codeItemIdx = codeItemIdx;
+
+    mutatableCode.mutatableCodeIdx = mutatableCodeIdx;
+
+    mutatableCode.registersSize = codeItem.registersSize;
+    mutatableCode.insSize = codeItem.insSize;
+    mutatableCode.outsSize = codeItem.outsSize;
+    mutatableCode.triesSize = codeItem.triesSize;
+
+    // Temporary map from bytecode offset -> instruction.
+    Map<Integer,MInsn> insnLocationMap = new HashMap<Integer,MInsn>();
+
+    List<Instruction> inputInsns = codeItem.insns;
+
+    // Create the MInsns.
+    int loc = 0;
+    for (Instruction insn : inputInsns) {
+      MInsn mInsn = null;
+
+      if (isInstructionSwitch(insn)) {
+        mInsn = new MSwitchInsn();
+      } else if (isInstructionBranch(insn)) {
+        mInsn = new MBranchInsn();
+      } else if (isInstructionFillArrayData(insn)) {
+        mInsn = new MInsnWithData();
+      } else {
+        mInsn = new MInsn();
+      }
+
+      mInsn.insn = insn;
+
+      // Populate the temporary map.
+      insnLocationMap.put(loc, mInsn);
+
+      // Populate the proper list of mutatable instructions.
+      mutatableCode.addInstructionToEnd(mInsn);
+
+      // Calculate the offsets for each instruction.
+      mInsn.location = loc;
+      mInsn.locationUpdated = false;
+
+      loc += mInsn.insn.getSize();
+    }
+
+    // Now make branch/switch instructions point at the right target instructions.
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MSwitchInsn) {
+        readSwitchInstruction((MSwitchInsn) mInsn, insnLocationMap);
+      } else if (mInsn instanceof MInsnWithData) {
+        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
+        int targetLoc = mInsn.location + (int) containsTarget.getTarget(mInsn.insn);
+        ((MInsnWithData)mInsn).dataTarget = insnLocationMap.get(targetLoc);
+        if (((MInsnWithData)mInsn).dataTarget == null) {
+          Log.errorAndQuit("Bad offset calculation in data-target insn");
+        }
+      } else if (mInsn instanceof MBranchInsn) {
+        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
+        int targetLoc = mInsn.location + (int) containsTarget.getTarget(mInsn.insn);
+        ((MBranchInsn)mInsn).target = insnLocationMap.get(targetLoc);
+        if (((MBranchInsn)mInsn).target == null) {
+          Log.errorAndQuit("Bad offset calculation in branch insn");
+        }
+      }
+    }
+
+    // Now create try blocks.
+    if (mutatableCode.triesSize > 0) {
+      readTryBlocks(codeItem, mutatableCode, insnLocationMap);
+    }
+
+    return mutatableCode;
+  }
+
+  /**
+   * Given a MutatableCode item that may have been mutated, update the original CodeItem
+   * correctly, to allow valid DEX to be written back to the output file.
+   */
+  public void mutatableCodeToCodeItem(CodeItem codeItem, MutatableCode mutatableCode) {
+    Log.debug("Translating MutatableCode " + mutatableCode.name
+        + " to CodeItem " + mutatableCode.codeItemIdx);
+
+    // We must first align any data instructions at the end of the code
+    // before we recalculate any offsets.
+    // This also updates their sizes...
+    alignDataInstructions(mutatableCode);
+
+    // Validate that the tracked locations for instructions are valid.
+    // Also mark locations as no longer being updated.
+    int loc = 0;
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.justRaw) {
+        // All just_raw instructions need alignment!
+        if ((loc % 2) != 0) {
+          loc++;
+        }
+      }
+      if (mInsn.location != loc) {
+        Log.errorAndQuit(String.format("%s does not have expected location 0x%x",
+            mInsn, loc));
+      }
+      mInsn.locationUpdated = false;
+      loc += mInsn.insn.getSize();
+    }
+
+    // This new list will be attached to the CodeItem at the end...
+    List<Instruction> outputInsns = new LinkedList<Instruction>();
+
+    // Go through our new list of MInsns, adding them to the new
+    // list of instructions that will be attached to the CodeItem.
+    // Also recalculate offsets for branches.
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MSwitchInsn) {
+        updateSwitchInstruction((MSwitchInsn)mInsn, mutatableCode);
+      } else if (mInsn instanceof MInsnWithData) {
+        MInsn target = ((MInsnWithData) mInsn).dataTarget;
+        int dataOffset = target.location - mInsn.location;
+        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
+        containsTarget.setTarget(mInsn.insn, dataOffset);
+      } else if (mInsn instanceof MBranchInsn) {
+        MInsn target = ((MBranchInsn) mInsn).target;
+        int branchOffset = target.location - mInsn.location;
+        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
+        containsTarget.setTarget(mInsn.insn, branchOffset);
+      }
+      outputInsns.add(mInsn.insn);
+    }
+
+    // Calculate the new insns_size.
+    int newInsnsSize = 0;
+    for (Instruction insn : outputInsns) {
+      newInsnsSize += insn.getSize();
+    }
+
+    if (mutatableCode.triesSize > 0) {
+      updateTryBlocks(codeItem, mutatableCode);
+    }
+
+    codeItem.insnsSize = newInsnsSize;
+    codeItem.insns = outputInsns;
+    codeItem.registersSize = mutatableCode.registersSize;
+    codeItem.insSize = mutatableCode.insSize;
+    codeItem.outsSize = mutatableCode.outsSize;
+    codeItem.triesSize = mutatableCode.triesSize;
+  }
+
+  /**
+   * The TryItem specifies an offset into the EncodedCatchHandlerList for a given CodeItem,
+   * but we only have an array of the EncodedCatchHandlers that the List contains.
+   * This function produces a map that offers a way to find out the index into our array,
+   * from the try handler's offset.
+   */
+  private Map<Short,Integer> createTryHandlerOffsetToIndexMap(CodeItem codeItem) {
+    // Create a sorted set of offsets.
+    List<Short> uniqueOffsets = new ArrayList<Short>();
+    for (TryItem tryItem : codeItem.tries) {
+      int index = 0;
+      while (true) {
+        if ((index == uniqueOffsets.size())
+            || (uniqueOffsets.get(index) > tryItem.handlerOff)) {
+          // First condition means we're at the end of the set (or we're inserting
+          //   into an empty set)
+          // Second condition means that the offset belongs here
+          // ...so insert it here, pushing the element currently in this position to the
+          //    right, if it exists
+          uniqueOffsets.add(index, tryItem.handlerOff);
+          break;
+        } else if (uniqueOffsets.get(index) == tryItem.handlerOff) {
+          // We've already seen it, and we're making a set, not a list.
+          break;
+        } else {
+          // Keep searching.
+          index++;
+        }
+      }
+    }
+    // Now we have an (implicit) index -> offset mapping!
+
+    // Now create the reverse mapping.
+    Map<Short,Integer> offsetIndexMap = new HashMap<Short,Integer>();
+    for (int i = 0; i < uniqueOffsets.size(); i++) {
+      offsetIndexMap.put(uniqueOffsets.get(i), i);
+    }
+
+    return offsetIndexMap;
+  }
+
+  private void readTryBlocks(CodeItem codeItem, MutatableCode mutatableCode,
+      Map<Integer,MInsn> insnLocationMap) {
+    mutatableCode.mutatableTries = new LinkedList<MTryBlock>();
+
+    Map<Short,Integer> offsetIndexMap = createTryHandlerOffsetToIndexMap(codeItem);
+
+    // Read each TryItem into a MutatableTryBlock.
+    for (TryItem tryItem : codeItem.tries) {
+      MTryBlock mTryBlock = new MTryBlock();
+
+      // Get the MInsns that form the start and end of the try block.
+      int startLocation = tryItem.startAddr;
+      mTryBlock.startInsn = insnLocationMap.get(startLocation);
+      int endLocation = tryItem.startAddr + tryItem.insnCount;
+      mTryBlock.endInsn = insnLocationMap.get(endLocation);
+
+      // Sanity checks.
+      if (mTryBlock.startInsn == null) {
+        Log.errorAndQuit(String.format(
+            "Couldn't find a mutatable insn at start offset 0x%x",
+            startLocation));
+      }
+      if (mTryBlock.endInsn == null) {
+        Log.errorAndQuit(String.format(
+            "Couldn't find a mutatable insn at end offset 0x%x",
+            endLocation));
+      }
+
+      // Get the EncodedCatchHandler.
+      int handlerIdx = offsetIndexMap.get(tryItem.handlerOff);
+      EncodedCatchHandler encodedCatchHandler = codeItem.handlers.list[handlerIdx];
+
+      // Do we have a catch all? If so, associate the MInsn that's there.
+      if (encodedCatchHandler.size <= 0) {
+        mTryBlock.catchAllHandler =
+            insnLocationMap.get(encodedCatchHandler.catchAllAddr);
+        // Sanity check.
+        if (mTryBlock.catchAllHandler == null) {
+          Log.errorAndQuit(
+              String.format("Couldn't find a mutatable insn at catch-all offset 0x%x",
+                  encodedCatchHandler.catchAllAddr));
+        }
+      }
+      // Do we have explicitly-typed handlers? This will remain empty if not.
+      mTryBlock.handlers = new LinkedList<MInsn>();
+
+      // Associate all the explicitly-typed handlers.
+      for (int i = 0; i < Math.abs(encodedCatchHandler.size); i++) {
+        EncodedTypeAddrPair handler = encodedCatchHandler.handlers[i];
+        MInsn handlerInsn = insnLocationMap.get(handler.addr);
+        // Sanity check.
+        if (handlerInsn == null) {
+          Log.errorAndQuit(String.format(
+              "Couldn't find a mutatable instruction at handler offset 0x%x",
+              handler.addr));
+        }
+        mTryBlock.handlers.add(handlerInsn);
+      }
+
+      // Now finally add the new MutatableTryBlock into this MutatableCode's list!
+      mutatableCode.mutatableTries.add(mTryBlock);
+    }
+  }
+
+  private void updateTryBlocks(CodeItem codeItem, MutatableCode mutatableCode) {
+
+    // TODO: Support ability to add extra try blocks/handlers?
+
+    for (MTryBlock mTryBlock : mutatableCode.mutatableTries) {
+      if (mTryBlock.startInsn.location > mTryBlock.endInsn.location) {
+        // Mutation has put this try block's end insn before its start insn. Fix this.
+        MInsn tempInsn = mTryBlock.startInsn;
+        mTryBlock.startInsn = mTryBlock.endInsn;
+        mTryBlock.endInsn = tempInsn;
+      }
+    }
+
+    // First, manipulate the try blocks if they overlap.
+    for (int i = 0; i < mutatableCode.mutatableTries.size() - 1; i++) {
+      MTryBlock first = mutatableCode.mutatableTries.get(i);
+      MTryBlock second = mutatableCode.mutatableTries.get(i + 1);
+
+      // Do they overlap?
+      if (first.endInsn.location > second.startInsn.location) {
+
+        Log.debug("Found overlap in TryBlocks, moving 2nd TryBlock...");
+        Log.debug("1st TryBlock goes from " + first.startInsn + " to "  + first.endInsn);
+        Log.debug("2nd TryBlock goes from " + second.startInsn + " to "  + second.endInsn);
+
+        // Find the first instruction that comes after that does not overlap
+        // with the first try block.
+        MInsn newInsn = second.startInsn;
+        int ptr = mutatableCode.getInstructionIndex(newInsn);
+        while (first.endInsn.location > newInsn.location) {
+          ptr++;
+          newInsn = mutatableCode.getInstructionAt(ptr);
+        }
+        second.startInsn = newInsn;
+
+        Log.debug("Now 2nd TryBlock goes from " + second.startInsn + " to "  + second.endInsn);
+      }
+    }
+
+    Map<Short,Integer> offsetIndexMap = createTryHandlerOffsetToIndexMap(codeItem);
+
+    int tryItemIdx = 0;
+    for (MTryBlock mTryBlock : mutatableCode.mutatableTries) {
+      TryItem tryItem = codeItem.tries[tryItemIdx];
+
+      tryItem.startAddr = mTryBlock.startInsn.location;
+      tryItem.insnCount =
+          (short) (mTryBlock.endInsn.location - mTryBlock.startInsn.location);
+
+      // Get the EncodedCatchHandler.
+      EncodedCatchHandler encodedCatchHandler =
+          codeItem.handlers.list[offsetIndexMap.get(tryItem.handlerOff)];
+
+      if (encodedCatchHandler.size <= 0) {
+        encodedCatchHandler.catchAllAddr = mTryBlock.catchAllHandler.location;
+      }
+      for (int i = 0; i < Math.abs(encodedCatchHandler.size); i++) {
+        MInsn handlerInsn = mTryBlock.handlers.get(i);
+        EncodedTypeAddrPair handler = encodedCatchHandler.handlers[i];
+        handler.addr = handlerInsn.location;
+      }
+      tryItemIdx++;
+    }
+  }
+
+  /**
+   * Given a switch instruction, find the associated data's raw[] form, and update
+   * the targets of the switch instruction to point to the correct instructions.
+   */
+  private void readSwitchInstruction(MSwitchInsn switchInsn,
+      Map<Integer,MInsn> insnLocationMap) {
+    // Find the data.
+    ContainsTarget containsTarget = (ContainsTarget) switchInsn.insn.info.format;
+    int dataLocation = switchInsn.location + (int) containsTarget.getTarget(switchInsn.insn);
+    switchInsn.dataTarget = insnLocationMap.get(dataLocation);
+    if (switchInsn.dataTarget == null) {
+      Log.errorAndQuit("Bad offset calculation for data target in switch insn");
+    }
+
+    // Now read the data.
+    Instruction dataInsn = switchInsn.dataTarget.insn;
+
+    int rawPtr = 2;
+
+    int targetsSize = (int) RawInsnHelper.getUnsignedShortFromTwoBytes(dataInsn.rawBytes, rawPtr);
+    rawPtr += 2;
+
+    int[] keys = new int[targetsSize];
+    int[] targets = new int[targetsSize];
+
+    if (dataInsn.rawType == 1) {
+      switchInsn.packed = true;
+      // Dealing with a packed-switch.
+      // Read the first key.
+      keys[0] = (int) RawInsnHelper.getUnsignedIntFromFourBytes(dataInsn.rawBytes, rawPtr);
+      rawPtr += 4;
+      // Calculate the rest of the keys.
+      for (int i = 1; i < targetsSize; i++) {
+        keys[i] = keys[i - 1] + 1;
+      }
+    } else if (dataInsn.rawType == 2) {
+      // Dealing with a sparse-switch.
+      // Read all of the keys.
+      for (int i = 0; i < targetsSize; i++) {
+        keys[i] = (int) RawInsnHelper.getUnsignedIntFromFourBytes(dataInsn.rawBytes,
+            rawPtr);
+        rawPtr += 4;
+      }
+    }
+
+    // Now read the targets.
+    for (int i = 0; i < targetsSize; i++) {
+      targets[i] = (int) RawInsnHelper.getUnsignedIntFromFourBytes(dataInsn.rawBytes,
+          rawPtr);
+      rawPtr += 4;
+    }
+
+    // Store the keys.
+    switchInsn.keys = keys;
+
+    // Convert our targets[] offsets into pointers to MInsns.
+    for (int target : targets) {
+      int targetLocation = switchInsn.location + target;
+      MInsn targetInsn = insnLocationMap.get(targetLocation);
+      switchInsn.targets.add(targetInsn);
+      if (targetInsn == null) {
+        Log.errorAndQuit("Bad offset calculation for target in switch insn");
+      }
+    }
+  }
+
+  /**
+   * Given a mutatable switch instruction, which may have had some of its branch
+   * targets moved, update all the target offsets in the raw[] form of the instruction.
+   */
+  private void updateSwitchInstruction(MSwitchInsn switchInsn, MutatableCode mutatableCode) {
+    // Update the offset to the data instruction
+    MInsn dataTarget = switchInsn.dataTarget;
+    int dataOffset = dataTarget.location - switchInsn.location;
+    ContainsTarget containsTarget = (ContainsTarget) switchInsn.insn.info.format;
+    containsTarget.setTarget(switchInsn.insn, dataOffset);
+
+    int targetsSize = switchInsn.targets.size();
+
+    int[] keys = switchInsn.keys;
+    int[] targets = new int[targetsSize];
+
+    // Calculate the new offsets.
+    int targetIdx = 0;
+    for (MInsn target : switchInsn.targets) {
+      targets[targetIdx] = target.location - switchInsn.location;
+      targetIdx++;
+    }
+
+    // Now write the data back to the raw bytes.
+    Instruction dataInsn = switchInsn.dataTarget.insn;
+
+    int rawPtr = 2;
+
+    // Write out the size.
+    RawInsnHelper.writeUnsignedShortToTwoBytes(dataInsn.rawBytes, rawPtr, targetsSize);
+    rawPtr += 2;
+
+    // Write out the keys.
+    if (switchInsn.packed) {
+      // Only write out one key - the first.
+      RawInsnHelper.writeUnsignedIntToFourBytes(dataInsn.rawBytes, rawPtr, keys[0]);
+      rawPtr += 4;
+    } else {
+      // Write out all the keys.
+      for (int i = 0; i < targetsSize; i++) {
+        RawInsnHelper.writeUnsignedIntToFourBytes(dataInsn.rawBytes, rawPtr, keys[i]);
+        rawPtr += 4;
+      }
+    }
+
+    // Write out all the targets.
+    for (int i = 0; i < targetsSize; i++) {
+      RawInsnHelper.writeUnsignedIntToFourBytes(dataInsn.rawBytes, rawPtr, targets[i]);
+      rawPtr += 4;
+    }
+  }
+
+  /**
+   * After mutation, data instructions may no longer be 4-byte aligned.
+   * If this is the case, insert nops to align them all.
+   * This makes a number of assumptions about data currently:
+   * - data is always at the end of method insns
+   * - all data instructions are stored contiguously
+   */
+  private void alignDataInstructions(MutatableCode mutatableCode) {
+    // Find all the switch data instructions.
+    List<MInsn> dataInsns = new ArrayList<MInsn>();
+
+    // Update raw sizes of the data instructions as well.
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MSwitchInsn) {
+        // Update the raw size of the instruction.
+        MSwitchInsn switchInsn = (MSwitchInsn) mInsn;
+        int targetsSize = switchInsn.targets.size();
+        Instruction dataInsn = switchInsn.dataTarget.insn;
+        if (switchInsn.packed) {
+          dataInsn.rawSize = (targetsSize * 2) + 4;
+        } else {
+          dataInsn.rawSize = (targetsSize * 4) + 2;
+        }
+        dataInsns.add(switchInsn.dataTarget);
+      } else if (mInsn instanceof MInsnWithData) {
+        MInsnWithData insnWithData =
+            (MInsnWithData) mInsn;
+        dataInsns.add(insnWithData.dataTarget);
+      }
+    }
+
+    // Only need to align switch data instructions if there are any!
+    if (!dataInsns.isEmpty()) {
+
+      Log.debug("Found data instructions, checking alignment...");
+
+      // Sort data_insns by location.
+      Collections.sort(dataInsns, new Comparator<MInsn>() {
+        @Override
+        public int compare(MInsn first, MInsn second) {
+          if (first.location < second.location) {
+            return -1;
+          } else if (first.location > second.location) {
+            return 1;
+          }
+          return 0;
+        }
+      });
+
+      boolean performedAlignment = false;
+
+      // Go through all the data insns, and insert an alignment nop if they're unaligned.
+      for (MInsn dataInsn : dataInsns) {
+        if (dataInsn.location % 2 != 0) {
+          Log.debug("Aligning data instruction with a nop.");
+          int alignmentNopIdx = mutatableCode.getInstructionIndex(dataInsn);
+          MInsn nop = new MInsn();
+          nop.insn = new Instruction();
+          nop.insn.info = Instruction.getOpcodeInfo(Opcode.NOP);
+          mutatableCode.insertInstructionAt(nop, alignmentNopIdx);
+          performedAlignment = true;
+        }
+      }
+
+      if (!performedAlignment) {
+        Log.debug("Alignment okay.");
+      }
+    }
+  }
+
+  /**
+   * Determine if a particular instruction is a branch instruction, based on opcode.
+   */
+  private boolean isInstructionBranch(Instruction insn) {
+    Opcode opcode = insn.info.opcode;
+    if (Opcode.isBetween(opcode, Opcode.IF_EQ, Opcode.IF_LEZ)
+        || Opcode.isBetween(opcode, Opcode.GOTO, Opcode.GOTO_32)) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Determine if a particular instruction is a switch instruction, based on opcode.
+   */
+  private boolean isInstructionSwitch(Instruction insn) {
+    Opcode opcode = insn.info.opcode;
+    if (Opcode.isBetween(opcode, Opcode.PACKED_SWITCH, Opcode.SPARSE_SWITCH)) {
+      return true;
+    }
+    return false;
+  }
+
+  private boolean isInstructionFillArrayData(Instruction insn) {
+    return (insn.info.opcode == Opcode.FILL_ARRAY_DATA);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/IdCreator.java b/tools/dexfuzz/src/dexfuzz/program/IdCreator.java
new file mode 100644
index 0000000..c506fa6
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/IdCreator.java
@@ -0,0 +1,804 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.Log;
+import dexfuzz.rawdex.FieldIdItem;
+import dexfuzz.rawdex.MethodIdItem;
+import dexfuzz.rawdex.Offset;
+import dexfuzz.rawdex.Offsettable;
+import dexfuzz.rawdex.ProtoIdItem;
+import dexfuzz.rawdex.RawDexFile;
+import dexfuzz.rawdex.RawDexObject.IndexUpdateKind;
+import dexfuzz.rawdex.StringDataItem;
+import dexfuzz.rawdex.StringIdItem;
+import dexfuzz.rawdex.TypeIdItem;
+import dexfuzz.rawdex.TypeItem;
+import dexfuzz.rawdex.TypeList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Responsible for the finding and creation of TypeIds, MethodIds, FieldIds, and StringIds,
+ * during mutation.
+ */
+public class IdCreator {
+  private RawDexFile rawDexFile;
+
+  public IdCreator(RawDexFile rawDexFile) {
+    this.rawDexFile = rawDexFile;
+  }
+
+  private int findProtoIdInsertionPoint(String signature) {
+    int returnTypeIdx = findTypeId(convertSignatureToReturnType(signature));
+    String[] parameterListStrings = convertSignatureToParameterList(signature);
+    TypeList parameterList = null;
+    if (parameterListStrings.length > 0) {
+      parameterList = findTypeList(parameterListStrings);
+    }
+
+    if (returnTypeIdx < 0) {
+      Log.errorAndQuit("Did not create necessary return type before finding insertion "
+          + "point for new proto!");
+    }
+
+    if (parameterListStrings.length > 0 && parameterList == null) {
+      Log.errorAndQuit("Did not create necessary parameter list before finding insertion "
+          + "point for new proto!");
+    }
+
+    int protoIdIdx = 0;
+    for (ProtoIdItem protoId : rawDexFile.protoIds) {
+      if (returnTypeIdx < protoId.returnTypeIdx) {
+        break;
+      }
+      if (returnTypeIdx == protoId.returnTypeIdx
+          && parameterListStrings.length == 0) {
+        break;
+      }
+      if (returnTypeIdx == protoId.returnTypeIdx
+          && parameterListStrings.length > 0
+          && protoId.parametersOff.pointsToSomething()
+          && parameterList.comesBefore(
+              (TypeList) protoId.parametersOff.getPointedToItem())) {
+        break;
+      }
+      protoIdIdx++;
+    }
+    return protoIdIdx;
+  }
+
+  private int findMethodIdInsertionPoint(String className, String methodName, String signature) {
+    int classIdx = findTypeId(className);
+    int nameIdx = findString(methodName);
+    int protoIdx = findProtoId(signature);
+
+    if (classIdx < 0 || nameIdx < 0 || protoIdx < 0) {
+      Log.errorAndQuit("Did not create necessary class, name or proto strings before finding "
+          + " insertion point for new method!");
+    }
+
+    int methodIdIdx = 0;
+    for (MethodIdItem methodId : rawDexFile.methodIds) {
+      if (classIdx < methodId.classIdx) {
+        break;
+      }
+      if (classIdx == methodId.classIdx && nameIdx < methodId.nameIdx) {
+        break;
+      }
+      if (classIdx == methodId.classIdx && nameIdx == methodId.nameIdx
+          && protoIdx < methodId.protoIdx) {
+        break;
+      }
+      methodIdIdx++;
+    }
+    return methodIdIdx;
+  }
+
+  private int findTypeIdInsertionPoint(String className) {
+    int descriptorIdx = findString(className);
+
+    if (descriptorIdx < 0) {
+      Log.errorAndQuit("Did not create necessary descriptor string before finding "
+          + " insertion point for new type!");
+    }
+
+    int typeIdIdx = 0;
+    for (TypeIdItem typeId : rawDexFile.typeIds) {
+      if (descriptorIdx < typeId.descriptorIdx) {
+        break;
+      }
+      typeIdIdx++;
+    }
+    return typeIdIdx;
+  }
+
+  private int findStringDataInsertionPoint(String string) {
+    int stringDataIdx = 0;
+    for (StringDataItem stringData : rawDexFile.stringDatas) {
+      if (stringData.getSize() > 0 && stringData.getString().compareTo(string) >= 0) {
+        break;
+      }
+      stringDataIdx++;
+    }
+    return stringDataIdx;
+  }
+
+  private int findFieldIdInsertionPoint(String className, String typeName, String fieldName) {
+    int classIdx = findTypeId(className);
+    int typeIdx = findTypeId(typeName);
+    int nameIdx = findString(fieldName);
+
+    if (classIdx < 0 || typeIdx < 0 || nameIdx < 0) {
+      Log.errorAndQuit("Did not create necessary class, type or name strings before finding "
+          + " insertion point for new field!");
+    }
+
+    int fieldIdIdx = 0;
+    for (FieldIdItem fieldId : rawDexFile.fieldIds) {
+      if (classIdx < fieldId.classIdx) {
+        break;
+      }
+      if (classIdx == fieldId.classIdx && nameIdx < fieldId.nameIdx) {
+        break;
+      }
+      if (classIdx == fieldId.classIdx && nameIdx == fieldId.nameIdx
+          && typeIdx < fieldId.typeIdx) {
+        break;
+      }
+      fieldIdIdx++;
+    }
+    return fieldIdIdx;
+  }
+
+  private int createMethodId(String className, String methodName, String signature) {
+    if (rawDexFile.methodIds.size() >= 65536) {
+      Log.errorAndQuit("Referenced too many methods for the DEX file.");
+    }
+
+    // Search for (or create) the prototype.
+    int protoIdx = findOrCreateProtoId(signature);
+
+    // Search for (or create) the owning class.
+    // NB: findOrCreateProtoId could create new types, so this must come
+    //     after it!
+    int typeIdIdx = findOrCreateTypeId(className);
+
+    // Search for (or create) the string representing the method name.
+    // NB: findOrCreateProtoId/TypeId could create new strings, so this must come
+    //     after them!
+    int methodNameStringIdx = findOrCreateString(methodName);
+
+    // Create MethodIdItem.
+    MethodIdItem newMethodId = new MethodIdItem();
+    newMethodId.classIdx = (short) typeIdIdx;
+    newMethodId.protoIdx = (short) protoIdx;
+    newMethodId.nameIdx = methodNameStringIdx;
+
+    // MethodIds must be ordered.
+    int newMethodIdIdx = findMethodIdInsertionPoint(className, methodName, signature);
+
+    rawDexFile.methodIds.add(newMethodIdIdx, newMethodId);
+
+    // Insert into OffsetTracker.
+    if (newMethodIdIdx == 0) {
+      rawDexFile.getOffsetTracker()
+        .insertNewOffsettableAsFirstOfType(newMethodId, rawDexFile);
+    } else {
+      MethodIdItem prevMethodId = rawDexFile.methodIds.get(newMethodIdIdx - 1);
+      rawDexFile.getOffsetTracker().insertNewOffsettableAfter(newMethodId, prevMethodId);
+    }
+
+    Log.info(String.format("Created new MethodIdItem for %s %s %s, index: 0x%04x",
+        className, methodName, signature, newMethodIdIdx));
+
+    // Now that we've potentially moved a lot of method IDs along, all references
+    // to them need to be updated.
+    rawDexFile.incrementIndex(IndexUpdateKind.METHOD_ID, newMethodIdIdx);
+
+    // All done, return the index for the new method.
+    return newMethodIdIdx;
+  }
+
+  private int findMethodId(String className, String methodName, String signature) {
+    int classIdx = findTypeId(className);
+    if (classIdx == -1) {
+      return -1;
+    }
+    int nameIdx = findString(methodName);
+    if (nameIdx == -1) {
+      return -1;
+    }
+    int protoIdx = findProtoId(signature);
+    if (nameIdx == -1) {
+      return -1;
+    }
+
+    int methodIdIdx = 0;
+    for (MethodIdItem methodId : rawDexFile.methodIds) {
+      if (classIdx == methodId.classIdx
+          && nameIdx == methodId.nameIdx
+          && protoIdx == methodId.protoIdx) {
+        return methodIdIdx;
+      }
+      methodIdIdx++;
+    }
+    return -1;
+  }
+
+  /**
+   * Given a fully qualified class name (Ljava/lang/System;), method name (gc) and
+   * and signature (()V), either find the MethodId in our DEX file's table, or create it.
+   */
+  public int findOrCreateMethodId(String className, String methodName, String shorty) {
+    int methodIdIdx = findMethodId(className, methodName, shorty);
+    if (methodIdIdx != -1) {
+      return methodIdIdx;
+    }
+    return createMethodId(className, methodName, shorty);
+  }
+
+  private int createTypeId(String className) {
+    if (rawDexFile.typeIds.size() >= 65536) {
+      Log.errorAndQuit("Referenced too many classes for the DEX file.");
+    }
+
+    // Search for (or create) the string representing the class descriptor.
+    int descriptorStringIdx = findOrCreateString(className);
+
+    // Create TypeIdItem.
+    TypeIdItem newTypeId = new TypeIdItem();
+    newTypeId.descriptorIdx = descriptorStringIdx;
+
+    // TypeIds must be ordered.
+    int newTypeIdIdx = findTypeIdInsertionPoint(className);
+
+    rawDexFile.typeIds.add(newTypeIdIdx, newTypeId);
+
+    // Insert into OffsetTracker.
+    if (newTypeIdIdx == 0) {
+      rawDexFile.getOffsetTracker().insertNewOffsettableAsFirstOfType(newTypeId, rawDexFile);
+    } else {
+      TypeIdItem prevTypeId = rawDexFile.typeIds.get(newTypeIdIdx - 1);
+      rawDexFile.getOffsetTracker().insertNewOffsettableAfter(newTypeId, prevTypeId);
+    }
+
+    Log.info(String.format("Created new ClassIdItem for %s, index: 0x%04x",
+        className, newTypeIdIdx));
+
+    // Now that we've potentially moved a lot of type IDs along, all references
+    // to them need to be updated.
+    rawDexFile.incrementIndex(IndexUpdateKind.TYPE_ID, newTypeIdIdx);
+
+    // All done, return the index for the new class.
+    return newTypeIdIdx;
+  }
+
+  private int findTypeId(String className) {
+    int descriptorIdx = findString(className);
+    if (descriptorIdx == -1) {
+      return -1;
+    }
+
+    // Search for class.
+    int typeIdIdx = 0;
+    for (TypeIdItem typeId : rawDexFile.typeIds) {
+      if (descriptorIdx == typeId.descriptorIdx) {
+        return typeIdIdx;
+      }
+      typeIdIdx++;
+    }
+    return -1;
+  }
+
+  /**
+   * Given a fully qualified class name (Ljava/lang/System;)
+   * either find the TypeId in our DEX file's table, or create it.
+   */
+  public int findOrCreateTypeId(String className) {
+    int typeIdIdx = findTypeId(className);
+    if (typeIdIdx != -1) {
+      return typeIdIdx;
+    }
+    return createTypeId(className);
+  }
+
+  private int createString(String string) {
+    // Didn't find it, create one...
+    int stringsCount = rawDexFile.stringIds.size();
+    if (stringsCount != rawDexFile.stringDatas.size()) {
+      Log.errorAndQuit("Corrupted DEX file, len(StringIDs) != len(StringDatas)");
+    }
+
+    // StringData must be ordered.
+    int newStringIdx = findStringDataInsertionPoint(string);
+
+    // Create StringDataItem.
+    StringDataItem newStringData = new StringDataItem();
+    newStringData.setSize(string.length());
+    newStringData.setString(string);
+
+    rawDexFile.stringDatas.add(newStringIdx, newStringData);
+
+    // Insert into OffsetTracker.
+    // (Need to save the Offsettable, because the StringIdItem will point to it.)
+    Offsettable offsettableStringData = null;
+    if (newStringIdx == 0) {
+      offsettableStringData =
+          rawDexFile.getOffsetTracker()
+          .insertNewOffsettableAsFirstOfType(newStringData, rawDexFile);
+    } else {
+      StringDataItem prevStringData = rawDexFile.stringDatas.get(newStringIdx - 1);
+      offsettableStringData = rawDexFile.getOffsetTracker()
+          .insertNewOffsettableAfter(newStringData, prevStringData);
+    }
+
+    // Create StringIdItem.
+    StringIdItem newStringId = new StringIdItem();
+    newStringId.stringDataOff = new Offset(false);
+    newStringId.stringDataOff.pointToNew(offsettableStringData);
+
+    rawDexFile.stringIds.add(newStringIdx, newStringId);
+
+    // Insert into OffsetTracker.
+    if (newStringIdx == 0) {
+      rawDexFile.getOffsetTracker()
+        .insertNewOffsettableAsFirstOfType(newStringId, rawDexFile);
+    } else {
+      StringIdItem prevStringId = rawDexFile.stringIds.get(newStringIdx - 1);
+      rawDexFile.getOffsetTracker().insertNewOffsettableAfter(newStringId, prevStringId);
+    }
+
+
+    Log.info(String.format("Created new StringIdItem and StringDataItem for %s, index: 0x%04x",
+        string, newStringIdx));
+
+    // Now that we've potentially moved a lot of string IDs along, all references
+    // to them need to be updated.
+    rawDexFile.incrementIndex(IndexUpdateKind.STRING_ID, newStringIdx);
+
+    // All done, return the index for the new string.
+    return newStringIdx;
+  }
+
+  private int findString(String string) {
+    // Search for string.
+    int stringIdx = 0;
+    for (StringDataItem stringDataItem : rawDexFile.stringDatas) {
+      if (stringDataItem.getSize() == 0 && string.isEmpty()) {
+        return stringIdx;
+      } else if (stringDataItem.getSize() > 0 && stringDataItem.getString().equals(string)) {
+        return stringIdx;
+      }
+      stringIdx++;
+    }
+    return -1;
+  }
+
+  /**
+   * Given a string, either find the StringId in our DEX file's table, or create it.
+   */
+  public int findOrCreateString(String string) {
+    int stringIdx = findString(string);
+    if (stringIdx != -1) {
+      return stringIdx;
+    }
+    return createString(string);
+  }
+
+  private int createFieldId(String className, String typeName, String fieldName) {
+    if (rawDexFile.fieldIds.size() >= 65536) {
+      Log.errorAndQuit("Referenced too many fields for the DEX file.");
+    }
+
+    // Search for (or create) the owning class.
+    int classIdx = findOrCreateTypeId(className);
+
+    // Search for (or create) the field's type.
+    int typeIdx = findOrCreateTypeId(typeName);
+
+    // The creation of the typeIdx may have changed the classIdx, search again!
+    classIdx = findOrCreateTypeId(className);
+
+    // Search for (or create) the string representing the field name.
+    int fieldNameStringIdx = findOrCreateString(fieldName);
+
+    // Create FieldIdItem.
+    FieldIdItem newFieldId = new FieldIdItem();
+    newFieldId.classIdx = (short) classIdx;
+    newFieldId.typeIdx = (short) typeIdx;
+    newFieldId.nameIdx = fieldNameStringIdx;
+
+    // FieldIds must be ordered.
+    int newFieldIdIdx = findFieldIdInsertionPoint(className, typeName, fieldName);
+
+    rawDexFile.fieldIds.add(newFieldIdIdx, newFieldId);
+
+    // Insert into OffsetTracker.
+    if (newFieldIdIdx == 0 && rawDexFile.fieldIds.size() == 1) {
+      // Special case: we didn't have any fields before!
+      rawDexFile.getOffsetTracker()
+        .insertNewOffsettableAsFirstEverField(newFieldId, rawDexFile);
+    } else if (newFieldIdIdx == 0) {
+      rawDexFile.getOffsetTracker().insertNewOffsettableAsFirstOfType(newFieldId, rawDexFile);
+    } else {
+      FieldIdItem prevFieldId = rawDexFile.fieldIds.get(newFieldIdIdx - 1);
+      rawDexFile.getOffsetTracker().insertNewOffsettableAfter(newFieldId, prevFieldId);
+    }
+
+    Log.info(String.format("Created new FieldIdItem for %s %s %s, index: 0x%04x",
+        className, typeName, fieldName, newFieldIdIdx));
+
+    // Now that we've potentially moved a lot of field IDs along, all references
+    // to them need to be updated.
+    rawDexFile.incrementIndex(IndexUpdateKind.FIELD_ID, newFieldIdIdx);
+
+    // All done, return the index for the new field.
+    return newFieldIdIdx;
+  }
+
+  private int findFieldId(String className, String typeName, String fieldName) {
+    int classIdx = findTypeId(className);
+    if (classIdx == -1) {
+      return -1;
+    }
+    int typeIdx = findTypeId(typeName);
+    if (typeIdx == -1) {
+      return -1;
+    }
+    int nameIdx = findString(fieldName);
+    if (nameIdx == -1) {
+      return -1;
+    }
+
+    int fieldIdIdx = 0;
+    for (FieldIdItem fieldId : rawDexFile.fieldIds) {
+      if (classIdx == fieldId.classIdx
+          && typeIdx == fieldId.typeIdx
+          && nameIdx == fieldId.nameIdx) {
+        return fieldIdIdx;
+      }
+      fieldIdIdx++;
+    }
+    return -1;
+  }
+
+  /**
+   * Given a field's fully qualified class name, type name, and name,
+   * either find the FieldId in our DEX file's table, or create it.
+   */
+  public int findOrCreateFieldId(String className, String typeName, String fieldName) {
+    int fieldIdx = findFieldId(className, typeName, fieldName);
+    if (fieldIdx != -1) {
+      return fieldIdx;
+    }
+    return createFieldId(className, typeName, fieldName);
+  }
+
+  /**
+   * Returns a 1 or 2 element String[]. If 1 element, the only element is the return type
+   * part of the signature. If 2 elements, the first is the parameters, the second is
+   * the return type.
+   */
+  private String[] convertSignatureToParametersAndReturnType(String signature) {
+    if (signature.charAt(0) != '(' || !signature.contains(")")) {
+      Log.errorAndQuit("Invalid signature: " + signature);
+    }
+    String[] elems = signature.substring(1).split("\\)");
+    return elems;
+  }
+
+  private String[] convertSignatureToParameterList(String signature) {
+    String[] elems = convertSignatureToParametersAndReturnType(signature);
+    String parameters = "";
+    if (elems.length == 2) {
+      parameters = elems[0];
+    }
+
+    List<String> parameterList = new ArrayList<String>();
+
+    int typePointer = 0;
+    while (typePointer != parameters.length()) {
+      if (elems[0].charAt(typePointer) == 'L') {
+        int start = typePointer;
+        // Read up to the next ;
+        while (elems[0].charAt(typePointer) != ';') {
+          typePointer++;
+        }
+        parameterList.add(parameters.substring(start, typePointer + 1));
+      } else {
+        parameterList.add(Character.toString(parameters.charAt(typePointer)));
+      }
+      typePointer++;
+    }
+
+    return parameterList.toArray(new String[]{});
+  }
+
+  private String convertSignatureToReturnType(String signature) {
+    String[] elems = convertSignatureToParametersAndReturnType(signature);
+    String returnType = "";
+    if (elems.length == 1) {
+      returnType = elems[0];
+    } else {
+      returnType = elems[1];
+    }
+
+    return returnType;
+  }
+
+  private String convertSignatureToShorty(String signature) {
+    String[] elems = convertSignatureToParametersAndReturnType(signature);
+
+    StringBuilder shortyBuilder = new StringBuilder();
+
+    String parameters = "";
+    String returnType = "";
+
+    if (elems.length == 1) {
+      shortyBuilder.append("V");
+    } else {
+      parameters = elems[0];
+      returnType = elems[1];
+      char returnChar = returnType.charAt(0);
+      // Arrays are references in shorties.
+      if (returnChar == '[') {
+        returnChar = 'L';
+      }
+      shortyBuilder.append(returnChar);
+    }
+
+    int typePointer = 0;
+    while (typePointer != parameters.length()) {
+      if (parameters.charAt(typePointer) == 'L') {
+        shortyBuilder.append('L');
+        // Read up to the next ;
+        while (parameters.charAt(typePointer) != ';') {
+          typePointer++;
+          if (typePointer == parameters.length()) {
+            Log.errorAndQuit("Illegal type specified in signature - L with no ;!");
+          }
+        }
+      } else if (parameters.charAt(typePointer) == '[') {
+        // Arrays are references in shorties.
+        shortyBuilder.append('L');
+        // Read past all the [s
+        while (parameters.charAt(typePointer) == '[') {
+          typePointer++;
+        }
+        if (parameters.charAt(typePointer) == 'L') {
+          // Read up to the next ;
+          while (parameters.charAt(typePointer) != ';') {
+            typePointer++;
+            if (typePointer == parameters.length()) {
+              Log.errorAndQuit("Illegal type specified in signature - L with no ;!");
+            }
+          }
+        }
+      } else {
+        shortyBuilder.append(parameters.charAt(typePointer));
+      }
+
+      typePointer++;
+    }
+
+    return shortyBuilder.toString();
+  }
+
+  private Integer[] convertParameterListToTypeIdList(String[] parameterList) {
+    List<Integer> typeIdList = new ArrayList<Integer>();
+    for (String parameter : parameterList) {
+      int typeIdx = findTypeId(parameter);
+      if (typeIdx == -1) {
+        return null;
+      }
+      typeIdList.add(typeIdx);
+    }
+    return typeIdList.toArray(new Integer[]{});
+  }
+
+  private TypeList createTypeList(String[] parameterList) {
+    TypeList typeList = new TypeList();
+    List<TypeItem> typeItemList = new ArrayList<TypeItem>();
+
+    // This must be done as two passes, one to create all the types,
+    // and then one to put them in the type list.
+    for (String parameter : parameterList) {
+      findOrCreateTypeId(parameter);
+    }
+
+    // Now actually put them in the list.
+    for (String parameter : parameterList) {
+      TypeItem typeItem = new TypeItem();
+      typeItem.typeIdx = (short) findOrCreateTypeId(parameter);
+      typeItemList.add(typeItem);
+    }
+    typeList.list = typeItemList.toArray(new TypeItem[]{});
+    typeList.size = typeItemList.size();
+
+    // Insert into OffsetTracker.
+    if (rawDexFile.typeLists == null) {
+      // Special case: we didn't have any fields before!
+      Log.info("Need to create first type list.");
+      rawDexFile.typeLists = new ArrayList<TypeList>();
+      rawDexFile.getOffsetTracker()
+        .insertNewOffsettableAsFirstEverTypeList(typeList, rawDexFile);
+    } else {
+      TypeList prevTypeList =
+          rawDexFile.typeLists.get(rawDexFile.typeLists.size() - 1);
+      rawDexFile.getOffsetTracker().insertNewOffsettableAfter(typeList, prevTypeList);
+    }
+
+    // Finally, add this new TypeList to the list of them.
+    rawDexFile.typeLists.add(typeList);
+
+    return typeList;
+  }
+
+  private TypeList findTypeList(String[] parameterList) {
+    Integer[] typeIdList = convertParameterListToTypeIdList(parameterList);
+    if (typeIdList == null) {
+      return null;
+    }
+
+    if (rawDexFile.typeLists == null) {
+      // There's no type lists yet!
+      return null;
+    }
+
+    for (TypeList typeList : rawDexFile.typeLists) {
+      if (typeList.size != typeIdList.length) {
+        continue;
+      }
+
+      boolean found = true;
+      int idx = 0;
+      for (TypeItem typeItem : typeList.list) {
+        if (typeItem.typeIdx != typeIdList[idx]) {
+          found = false;
+          break;
+        }
+        idx++;
+      }
+      if (found && idx == parameterList.length) {
+        return typeList;
+      }
+    }
+
+    return null;
+  }
+
+  private TypeList findOrCreateTypeList(String[] parameterList) {
+    TypeList typeList = findTypeList(parameterList);
+    if (typeList != null) {
+      return typeList;
+    }
+    return createTypeList(parameterList);
+  }
+
+  private int createProtoId(String signature) {
+    String shorty = convertSignatureToShorty(signature);
+    String returnType = convertSignatureToReturnType(signature);
+    String[] parameterList = convertSignatureToParameterList(signature);
+
+    if (rawDexFile.protoIds.size() >= 65536) {
+      Log.errorAndQuit("Referenced too many protos for the DEX file.");
+    }
+
+    TypeList typeList = null;
+    Offsettable typeListOffsettable = null;
+
+    if (parameterList.length > 0) {
+      // Search for (or create) the parameter list.
+      typeList = findOrCreateTypeList(parameterList);
+
+      typeListOffsettable =
+          rawDexFile.getOffsetTracker().getOffsettableForItem(typeList);
+    }
+
+    // Search for (or create) the return type.
+    int returnTypeIdx = findOrCreateTypeId(returnType);
+
+    // Search for (or create) the shorty string.
+    int shortyIdx = findOrCreateString(shorty);
+
+    // Create ProtoIdItem.
+    ProtoIdItem newProtoId = new ProtoIdItem();
+    newProtoId.shortyIdx = shortyIdx;
+    newProtoId.returnTypeIdx = returnTypeIdx;
+    newProtoId.parametersOff = new Offset(false);
+    if (parameterList.length > 0) {
+      newProtoId.parametersOff.pointToNew(typeListOffsettable);
+    }
+
+    // ProtoIds must be ordered.
+    int newProtoIdIdx = findProtoIdInsertionPoint(signature);
+
+    rawDexFile.protoIds.add(newProtoIdIdx, newProtoId);
+
+    // Insert into OffsetTracker.
+    if (newProtoIdIdx == 0) {
+      rawDexFile.getOffsetTracker().insertNewOffsettableAsFirstOfType(newProtoId, rawDexFile);
+    } else {
+      ProtoIdItem prevProtoId = rawDexFile.protoIds.get(newProtoIdIdx - 1);
+      rawDexFile.getOffsetTracker().insertNewOffsettableAfter(newProtoId, prevProtoId);
+    }
+
+    Log.info(String.format("Created new ProtoIdItem for %s, index: 0x%04x",
+        signature, newProtoIdIdx));
+
+    // Now that we've potentially moved a lot of proto IDs along, all references
+    // to them need to be updated.
+    rawDexFile.incrementIndex(IndexUpdateKind.PROTO_ID, newProtoIdIdx);
+
+    // All done, return the index for the new proto.
+    return newProtoIdIdx;
+  }
+
+  private int findProtoId(String signature) {
+    String shorty = convertSignatureToShorty(signature);
+    String returnType = convertSignatureToReturnType(signature);
+    String[] parameterList = convertSignatureToParameterList(signature);
+
+    int shortyIdx = findString(shorty);
+    if (shortyIdx == -1) {
+      return -1;
+    }
+    int returnTypeIdx = findTypeId(returnType);
+    if (returnTypeIdx == -1) {
+      return -1;
+    }
+
+    // Only look for a TypeList if there's a parameter list.
+    TypeList typeList = null;
+    if (parameterList.length > 0) {
+      typeList = findTypeList(parameterList);
+      if (typeList == null) {
+        return -1;
+      }
+    }
+
+    int protoIdIdx = 0;
+    for (ProtoIdItem protoId : rawDexFile.protoIds) {
+      if (parameterList.length > 0) {
+        // With parameters.
+        if (shortyIdx == protoId.shortyIdx
+            && returnTypeIdx == protoId.returnTypeIdx
+            && typeList.equals(protoId.parametersOff.getPointedToItem())) {
+          return protoIdIdx;
+        }
+      } else {
+        // Without parameters.
+        if (shortyIdx == protoId.shortyIdx
+            && returnTypeIdx == protoId.returnTypeIdx) {
+          return protoIdIdx;
+        }
+      }
+      protoIdIdx++;
+    }
+    return -1;
+  }
+
+  private int findOrCreateProtoId(String signature) {
+    int protoIdx = findProtoId(signature);
+    if (protoIdx != -1) {
+      return protoIdx;
+    }
+    return createProtoId(signature);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/MBranchInsn.java b/tools/dexfuzz/src/dexfuzz/program/MBranchInsn.java
new file mode 100644
index 0000000..ea66844
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MBranchInsn.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+/**
+ * A subclass of the MInsn, that tracks its target instruction.
+ */
+public class MBranchInsn extends MInsn {
+  /**
+   * The MInsn this branch instruction branches to.
+   */
+  public MInsn target;
+
+  /**
+   * Clone this MBranchInsn, and clone the wrapped Instruction.
+   */
+  public MBranchInsn clone() {
+    MBranchInsn newInsn = new MBranchInsn();
+    newInsn.insn = insn.clone();
+    newInsn.target = target;
+    return newInsn;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/MInsn.java b/tools/dexfuzz/src/dexfuzz/program/MInsn.java
new file mode 100644
index 0000000..10f7755
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MInsn.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.rawdex.Instruction;
+
+/**
+ * Base class that is a thin wrapper for Instructions currently, also tracking location
+ * as the instruction is moved around.
+ */
+public class MInsn {
+  /**
+   * The raw DEX instruction that this instruction represents.
+   */
+  public Instruction insn;
+
+
+  /**
+   * The location of this instruction, as an offset in code words from the beginning.
+   * May become invalid if instructions around it are mutated.
+   */
+  public int location;
+
+  /**
+   * Denotes if the currently associated location can be trusted.
+   */
+  public boolean locationUpdated;
+
+  /**
+   * Clone this MInsn, and clone the wrapped Instruction.
+   */
+  public MInsn clone() {
+    MInsn newInsn = new MInsn();
+    newInsn.insn = insn.clone();
+    // It is the responsibility of the cloner to update these values.
+    newInsn.location = location;
+    newInsn.locationUpdated = locationUpdated;
+    return newInsn;
+  }
+
+  /**
+   * Get the String representation of an instruction.
+   */
+  public String toString() {
+    return String.format("{0x%04x%s: %s}",
+        location,
+        (locationUpdated) ? "!" : "",
+            insn.toString());
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/MInsnWithData.java b/tools/dexfuzz/src/dexfuzz/program/MInsnWithData.java
new file mode 100644
index 0000000..ffed883
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MInsnWithData.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+/**
+ * A subclass of the MInsn, that tracks the data instruction.
+ */
+public class MInsnWithData extends MInsn {
+  /**
+   * The MInsn that represents the data this instruction uses.
+   */
+  public MInsn dataTarget;
+
+  /**
+   * Clone this MInsnWithData, and clone the wrapped Instruction.
+   */
+  public MInsnWithData clone() {
+    MInsnWithData newInsn = new MInsnWithData();
+    newInsn.insn = insn.clone();
+    newInsn.dataTarget = dataTarget;
+    return newInsn;
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/program/MSwitchInsn.java b/tools/dexfuzz/src/dexfuzz/program/MSwitchInsn.java
new file mode 100644
index 0000000..d8693fe
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MSwitchInsn.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A subclass of the MInsnWithData, that also has multiple jump targets.
+ */
+public class MSwitchInsn extends MInsnWithData {
+  /**
+   * The MInsns this switch instruction branches to.
+   */
+  public List<MInsn> targets = new LinkedList<MInsn>();
+
+  public boolean packed;
+
+  public int[] keys;
+
+  /**
+   * Clone this MSwitchInsn, and clone the wrapped Instruction.
+   */
+  public MSwitchInsn clone() {
+    MSwitchInsn newInsn = new MSwitchInsn();
+    newInsn.insn = insn.clone();
+    newInsn.dataTarget = dataTarget;
+    newInsn.packed = packed;
+    for (MInsn target : targets) {
+      newInsn.targets.add(target);
+    }
+    newInsn.keys = new int[keys.length];
+    System.arraycopy(keys, 0, newInsn.keys, 0, keys.length);
+    return newInsn;
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/program/MTryBlock.java b/tools/dexfuzz/src/dexfuzz/program/MTryBlock.java
new file mode 100644
index 0000000..a1dc029
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MTryBlock.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import java.util.List;
+
+/**
+ * Tracks where try blocks start and end.
+ */
+public class MTryBlock {
+  public MInsn startInsn;
+  public MInsn endInsn;
+  public List<MInsn> handlers;
+  public MInsn catchAllHandler;
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/MutatableCode.java b/tools/dexfuzz/src/dexfuzz/program/MutatableCode.java
new file mode 100644
index 0000000..c56b1bc
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MutatableCode.java
@@ -0,0 +1,410 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.Log;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A class that represents a CodeItem in a way that is more amenable to mutation.
+ */
+public class MutatableCode {
+  /**
+   * To ensure we update the correct CodeItem in the raw DEX file.
+   */
+  public int codeItemIdx;
+
+  /**
+   * This is an index into the Program's list of MutatableCodes.
+   */
+  public int mutatableCodeIdx;
+
+  /**
+   * Number of registers this code uses.
+   */
+  public short registersSize;
+
+  /**
+   * Number of ins this code has.
+   */
+  public short insSize;
+
+  /**
+   * Number of outs this code has.
+   */
+  public short outsSize;
+
+  /**
+   * Number of tries this code has.
+   */
+  public short triesSize;
+
+  /**
+   * CodeTranslator is responsible for creating this, and
+   * converting it back to a list of Instructions.
+   */
+  private List<MInsn> mutatableInsns;
+
+  /**
+   * CodeTranslator is responsible for creating this, and
+   * converting it back to the correct form for CodeItems.
+   */
+  public List<MTryBlock> mutatableTries;
+
+  /**
+   * The name of the method this code represents.
+   */
+  public String name;
+  public String shorty;
+  public boolean isStatic;
+
+  /**
+   * The Program that owns this MutatableCode.
+   * Currently used to get the size of constant pools for
+   * PoolIndexChanger/RandomInstructionGenerator
+   */
+  public Program program;
+
+  private short originalInVReg;
+  private short tempVRegsAllocated;
+  private short initialTempVReg;
+  private boolean vregsNeedCopying;
+  private int numMoveInsnsGenerated;
+
+  public MutatableCode(Program program) {
+    this.program = program;
+    this.mutatableInsns = new LinkedList<MInsn>();
+  }
+
+  /**
+   * Call this to update all instructions after the provided mInsn, to have their
+   * locations adjusted by the provided offset. It will also mark that they have been updated.
+   */
+  public void updateInstructionLocationsAfter(MInsn mInsn, int offset) {
+    boolean updating = false;
+    for (MInsn mInsnChecking : mutatableInsns) {
+      if (updating) {
+        mInsnChecking.locationUpdated = true;
+        mInsnChecking.location += offset;
+      } else {
+        if (mInsnChecking == mInsn) {
+          updating = true;
+        }
+      }
+
+    }
+  }
+
+  private void recalculateLocations() {
+    int loc = 0;
+    for (MInsn mInsn : mutatableInsns) {
+      mInsn.location = loc;
+      loc += mInsn.insn.getSize();
+    }
+  }
+
+  public List<MInsn> getInstructions() {
+    return Collections.unmodifiableList(mutatableInsns);
+  }
+
+  public int getInstructionCount() {
+    return mutatableInsns.size();
+  }
+
+  public int getInstructionIndex(MInsn mInsn) {
+    return mutatableInsns.indexOf(mInsn);
+  }
+
+  public MInsn getInstructionAt(int idx) {
+    return mutatableInsns.get(idx);
+  }
+
+  public void addInstructionToEnd(MInsn mInsn) {
+    mutatableInsns.add(mInsn);
+  }
+
+  public void insertInstructionAfter(MInsn toBeInserted, int insertionIdx) {
+    if ((insertionIdx + 1) < mutatableInsns.size()) {
+      insertInstructionAt(toBeInserted, insertionIdx + 1);
+    } else {
+      // Appending to end.
+      MInsn finalInsn = mutatableInsns.get(mutatableInsns.size() - 1);
+      toBeInserted.location = finalInsn.location + finalInsn.insn.getSize();
+      mutatableInsns.add(toBeInserted);
+    }
+  }
+
+  /**
+   * Has same semantics as List.add()
+   */
+  public void insertInstructionAt(MInsn toBeInserted, int insertionIdx) {
+    MInsn currentInsn = mutatableInsns.get(insertionIdx);
+    toBeInserted.location = currentInsn.location;
+    mutatableInsns.add(insertionIdx , toBeInserted);
+    updateInstructionLocationsAfter(toBeInserted, toBeInserted.insn.getSize());
+  }
+
+  /**
+   * Checks if any MTryBlock's instruction refs pointed at the 'before' MInsn,
+   * and points them to the 'after' MInsn, if so. 'twoWay' will check if 'after'
+   * was pointed to, and point refs to the 'before' insn.
+   * (one-way is used when deleting instructions,
+   * two-way is used when swapping instructions.)
+   */
+  private void updateTryBlocksWithReplacementInsn(MInsn before, MInsn after,
+      boolean twoWay) {
+    if (triesSize > 0) {
+      for (MTryBlock mTryBlock : mutatableTries) {
+        if (mTryBlock.startInsn == before) {
+          Log.debug("Try block's first instruction was updated");
+          mTryBlock.startInsn = after;
+        } else if (twoWay && mTryBlock.startInsn == after) {
+          Log.debug("Try block's first instruction was updated");
+          mTryBlock.startInsn = before;
+        }
+        if (mTryBlock.endInsn == before) {
+          Log.debug("Try block's last instruction was updated");
+          mTryBlock.endInsn = after;
+        } else if (twoWay && mTryBlock.endInsn == after) {
+          Log.debug("Try block's last instruction was updated");
+          mTryBlock.endInsn = before;
+        }
+        if (mTryBlock.catchAllHandler == before) {
+          Log.debug("Try block's catch-all instruction was updated");
+          mTryBlock.catchAllHandler = after;
+        } else if (twoWay && mTryBlock.catchAllHandler == after) {
+          Log.debug("Try block's catch-all instruction was updated");
+          mTryBlock.catchAllHandler = before;
+        }
+
+        List<Integer> matchesIndicesToChange = new ArrayList<Integer>();
+        List<Integer> replacementIndicesToChange = null;
+        if (twoWay) {
+          replacementIndicesToChange = new ArrayList<Integer>();
+        }
+
+        int idx = 0;
+        for (MInsn handler : mTryBlock.handlers) {
+          if (handler == before) {
+            matchesIndicesToChange.add(idx);
+            Log.debug("Try block's handler instruction was updated");
+          } else if (twoWay && handler == after) {
+            replacementIndicesToChange.add(idx);
+            Log.debug("Try block's handler instruction was updated");
+          }
+          idx++;
+        }
+
+        for (int idxToChange : matchesIndicesToChange) {
+          mTryBlock.handlers.set(idxToChange, after);
+        }
+
+        if (twoWay) {
+          for (int idxToChange : replacementIndicesToChange) {
+            mTryBlock.handlers.set(idxToChange, before);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * The actual implementation of deleteInstruction called by
+   * the single-argument deleteInstructions.
+   */
+  private void deleteInstructionFull(MInsn toBeDeleted, int toBeDeletedIdx) {
+    // Make sure we update all locations afterwards first.
+    updateInstructionLocationsAfter(toBeDeleted, -(toBeDeleted.insn.getSize()));
+
+    // Remove it.
+    mutatableInsns.remove(toBeDeletedIdx);
+
+    // Update any branch instructions that branched to the instruction we just deleted!
+
+    // First, pick the replacement target.
+    int replacementTargetIdx = toBeDeletedIdx;
+    if (replacementTargetIdx == mutatableInsns.size()) {
+      replacementTargetIdx--;
+    }
+    MInsn replacementTarget = mutatableInsns.get(replacementTargetIdx);
+
+    for (MInsn mInsn : mutatableInsns) {
+      if (mInsn instanceof MBranchInsn) {
+        // Check if this branch insn points at the insn we just deleted.
+        MBranchInsn branchInsn = (MBranchInsn) mInsn;
+        MInsn target = branchInsn.target;
+        if (target == toBeDeleted) {
+          Log.debug(branchInsn + " was pointing at the deleted instruction, updated.");
+          branchInsn.target = replacementTarget;
+        }
+      } else if (mInsn instanceof MSwitchInsn) {
+        // Check if any of this switch insn's targets points at the insn we just deleted.
+        MSwitchInsn switchInsn = (MSwitchInsn) mInsn;
+        List<Integer> indicesToChange = new ArrayList<Integer>();
+        int idx = 0;
+        for (MInsn target : switchInsn.targets) {
+          if (target == toBeDeleted) {
+            indicesToChange.add(idx);
+            Log.debug(switchInsn + "[" + idx
+                + "] was pointing at the deleted instruction, updated.");
+          }
+          idx++;
+        }
+        for (int idxToChange : indicesToChange) {
+          switchInsn.targets.remove(idxToChange);
+          switchInsn.targets.add(idxToChange, replacementTarget);
+        }
+      }
+    }
+
+    // Now update the try blocks.
+    updateTryBlocksWithReplacementInsn(toBeDeleted, replacementTarget, false);
+  }
+
+  /**
+   * Delete the provided MInsn.
+   */
+  public void deleteInstruction(MInsn toBeDeleted) {
+    deleteInstructionFull(toBeDeleted, mutatableInsns.indexOf(toBeDeleted));
+  }
+
+  /**
+   * Delete the MInsn at the provided index.
+   */
+  public void deleteInstruction(int toBeDeletedIdx) {
+    deleteInstructionFull(mutatableInsns.get(toBeDeletedIdx), toBeDeletedIdx);
+  }
+
+  public void swapInstructionsByIndex(int aIdx, int bIdx) {
+    MInsn aInsn = mutatableInsns.get(aIdx);
+    MInsn bInsn = mutatableInsns.get(bIdx);
+
+    mutatableInsns.set(aIdx, bInsn);
+    mutatableInsns.set(bIdx, aInsn);
+
+    updateTryBlocksWithReplacementInsn(aInsn, bInsn, true);
+
+    recalculateLocations();
+  }
+
+  /**
+   * Some mutators may require the use of temporary registers. For instance,
+   * to easily add in printing of values without having to look for registers
+   * that aren't currently live.
+   * The idea is to allocate these registers at the top of the set of registers.
+   * Because this will then shift where the arguments to the method are, we then
+   * change the start of the method to copy the arguments to the method
+   * into the place where the rest of the method's code expects them to be.
+   * Call allocateTemporaryVRegs(n), then use getTemporaryVReg(n),
+   * and then make sure finishedUsingTemporaryVRegs() is called!
+   */
+  public void allocateTemporaryVRegs(int count) {
+    if (count > tempVRegsAllocated) {
+      if (tempVRegsAllocated == 0) {
+        Log.info("Allocating temporary vregs for method...");
+        initialTempVReg = registersSize;
+        originalInVReg = (short) (registersSize - insSize);
+      } else {
+        Log.info("Extending allocation of temporary vregs for method...");
+      }
+      registersSize = (short) (initialTempVReg + count);
+      if (outsSize < count) {
+        outsSize = (short) count;
+      }
+      vregsNeedCopying = true;
+      tempVRegsAllocated = (short) count;
+    }
+  }
+
+  public int getTemporaryVReg(int number) {
+    if (number >= tempVRegsAllocated) {
+      Log.errorAndQuit("Not allocated enough temporary vregs!");
+    }
+    return initialTempVReg + number;
+  }
+
+  public void finishedUsingTemporaryVRegs() {
+    if (tempVRegsAllocated > 0 && vregsNeedCopying) {
+      // Just delete all the move instructions and generate again, if we already have some.
+      while (numMoveInsnsGenerated > 0) {
+        deleteInstruction(0);
+        numMoveInsnsGenerated--;
+      }
+
+      Log.info("Moving 'in' vregs to correct locations after allocating temporary vregs");
+
+      int shortyIdx = 0;
+      if (isStatic) {
+        shortyIdx = 1;
+      }
+
+      int insertionCounter = 0;
+
+      // Insert copy insns that move all the in VRs down.
+      for (int i = 0; i < insSize; i++) {
+        MInsn moveInsn = new MInsn();
+        moveInsn.insn = new Instruction();
+        moveInsn.insn.vregA = originalInVReg + i;
+        moveInsn.insn.vregB = originalInVReg + i + tempVRegsAllocated;
+
+        char type = 'L';
+        if (shortyIdx > 0) {
+          type = shorty.charAt(shortyIdx);
+        }
+        shortyIdx++;
+
+        if (type == 'L') {
+          moveInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_OBJECT_16);
+        } else if (type == 'D' || type == 'J') {
+          moveInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_WIDE_16);
+          i++;
+        } else {
+          moveInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_16);
+        }
+
+        insertInstructionAt(moveInsn, insertionCounter);
+        insertionCounter++;
+        Log.info("Temp vregs creation, Added instruction " + moveInsn);
+        numMoveInsnsGenerated++;
+      }
+
+      vregsNeedCopying = false;
+    }
+  }
+
+  /**
+   * When we insert new Field/Type/MethodIds into the DEX file, this may shunt some Ids
+   * into a new position in the table. If this happens, every reference to the Ids must
+   * be updated! Because CodeItems have their Instructions wrapped into a graph of MInsns
+   * during mutation, they don't have a view of all their instructions during mutation,
+   * and so if they are asked to update their instructions' indices into the tables, they
+   * must call this method to get the actual list of instructions they currently own.
+   */
+  public List<Instruction> requestLatestInstructions() {
+    List<Instruction> latestInsns = new ArrayList<Instruction>();
+    for (MInsn mInsn : mutatableInsns) {
+      latestInsns.add(mInsn.insn);
+    }
+    return latestInsns;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/Mutation.java b/tools/dexfuzz/src/dexfuzz/program/Mutation.java
new file mode 100644
index 0000000..2eba718
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/Mutation.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.program.mutators.CodeMutator;
+
+/**
+ * Mutation should be subclassed by an AssociatedMutation in each CodeMutator,
+ * which will describe the parameters of the mutation, and override the getString()
+ * and parseString() methods here to allow serialization of the mutations.
+ */
+public abstract class Mutation {
+
+  public MutatableCode mutatableCode;
+
+  // The first field of any serialized mutation - the mutator that uses it.
+  public Class<? extends CodeMutator> mutatorClass;
+  // The second field of any serialized mutation...
+  // This is an index into the Program's list of MutatableCodes
+  // i.e., it is NOT an index into the DEX file's CodeItems!
+  public int mutatableCodeIdx;
+
+  public void setup(Class<? extends CodeMutator> mutatorClass, MutatableCode mutatableCode) {
+    this.mutatorClass = mutatorClass;
+    this.mutatableCode = mutatableCode;
+    this.mutatableCodeIdx = mutatableCode.mutatableCodeIdx;
+  }
+
+  public abstract String getString();
+
+  public abstract void parseString(String[] elements);
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/program/MutationSerializer.java b/tools/dexfuzz/src/dexfuzz/program/MutationSerializer.java
new file mode 100644
index 0000000..7f79517
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/MutationSerializer.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.Log;
+import dexfuzz.program.mutators.CodeMutator;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+
+/**
+ * Responsible for serializing mutations, allowing replay of mutations, and searching
+ * for a minimal set of mutations.
+ */
+public class MutationSerializer {
+  public static String getMutationString(Mutation mutation) {
+    StringBuilder builder = new StringBuilder();
+    builder.append(mutation.mutatorClass.getCanonicalName()).append(" ");
+    builder.append(mutation.mutatableCodeIdx).append(" ");
+    builder.append(mutation.getString());
+    return builder.toString();
+  }
+
+  public static void writeMutation(BufferedWriter writer, Mutation mutation) throws IOException {
+    // Write out the common fields.
+    writer.write(mutation.mutatorClass.getCanonicalName() + " "
+        + mutation.mutatableCodeIdx + " ");
+
+    // Use the mutation's own function to write out the rest of the fields.
+    writer.write(mutation.getString() + "\n");
+  }
+
+  @SuppressWarnings("unchecked")
+  public static Mutation readMutation(BufferedReader reader) throws IOException {
+    String line = reader.readLine();
+    String[] fields = null;
+    if (line != null) {
+      fields = line.split(" ");
+    } else {
+      Log.errorAndQuit("Could not read line during mutation loading.");
+    }
+
+    // Read the mutator's class name
+    String mutatorClassName = fields[0];
+
+    // Get the class for that mutator
+    Class<? extends CodeMutator> mutatorClass = null;
+    try {
+      mutatorClass = (Class<? extends CodeMutator>) Class.forName(mutatorClassName);
+    } catch (ClassNotFoundException e) {
+      Log.errorAndQuit("Cannot find a mutator class called: " + mutatorClassName);
+    }
+
+    Mutation mutation = null;
+    try {
+      mutation = mutatorClass.newInstance().getNewMutation();
+    } catch (InstantiationException e) {
+      Log.errorAndQuit("Unable to instantiate " + mutatorClassName
+          + " using default constructor.");
+    } catch (IllegalAccessException e) {
+      Log.errorAndQuit("Unable to access methods in " + mutatorClassName + ".");
+    }
+
+    if (mutation == null) {
+      Log.errorAndQuit("Unable to get Mutation for Mutator: " + mutatorClassName);
+    }
+
+    // Populate the common fields of the mutation.
+    mutation.mutatorClass = mutatorClass;
+    // The Program must set this later, using the mutatable_code_idx
+    //   into its list of MutatableCodes.
+    mutation.mutatableCode = null;
+    mutation.mutatableCodeIdx = Integer.parseInt(fields[1]);
+
+    // Use the mutation's own method to read the rest of the fields.
+    mutation.parseString(fields);
+
+    return mutation;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/Program.java b/tools/dexfuzz/src/dexfuzz/program/Program.java
new file mode 100644
index 0000000..286fe52
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/Program.java
@@ -0,0 +1,602 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.Options;
+import dexfuzz.listeners.BaseListener;
+import dexfuzz.program.mutators.ArithOpChanger;
+import dexfuzz.program.mutators.BranchShifter;
+import dexfuzz.program.mutators.CmpBiasChanger;
+import dexfuzz.program.mutators.CodeMutator;
+import dexfuzz.program.mutators.ConstantValueChanger;
+import dexfuzz.program.mutators.ConversionRepeater;
+import dexfuzz.program.mutators.FieldFlagChanger;
+import dexfuzz.program.mutators.InstructionDeleter;
+import dexfuzz.program.mutators.InstructionDuplicator;
+import dexfuzz.program.mutators.InstructionSwapper;
+import dexfuzz.program.mutators.NewMethodCaller;
+import dexfuzz.program.mutators.NonsenseStringPrinter;
+import dexfuzz.program.mutators.PoolIndexChanger;
+import dexfuzz.program.mutators.RandomInstructionGenerator;
+import dexfuzz.program.mutators.SwitchBranchShifter;
+import dexfuzz.program.mutators.TryBlockShifter;
+import dexfuzz.program.mutators.ValuePrinter;
+import dexfuzz.program.mutators.VRegChanger;
+import dexfuzz.rawdex.ClassDataItem;
+import dexfuzz.rawdex.ClassDefItem;
+import dexfuzz.rawdex.CodeItem;
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.EncodedField;
+import dexfuzz.rawdex.EncodedMethod;
+import dexfuzz.rawdex.FieldIdItem;
+import dexfuzz.rawdex.MethodIdItem;
+import dexfuzz.rawdex.ProtoIdItem;
+import dexfuzz.rawdex.RawDexFile;
+import dexfuzz.rawdex.TypeIdItem;
+import dexfuzz.rawdex.formats.ContainsPoolIndex.PoolIndexKind;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * After the raw DEX file has been parsed, it is passed into this class
+ * that represents the program in a mutatable form.
+ * The class uses a CodeTranslator to translate between the raw DEX form
+ * for a method, and the mutatable form. It also controls all CodeMutators,
+ * deciding which ones should be applied to each CodeItem.
+ */
+public class Program {
+  /**
+   * The RNG used during mutation.
+   */
+  private Random rng;
+
+  /**
+   * The seed that was given to the RNG.
+   */
+  public long rngSeed;
+
+  /**
+   * The parsed raw DEX file.
+   */
+  private RawDexFile rawDexFile;
+
+  /**
+   * The system responsible for translating from CodeItems to MutatableCode and vice-versa.
+   */
+  private CodeTranslator translator;
+
+  /**
+   * Responsible for adding new class ID items, method ID items, etc.
+   */
+  private IdCreator idCreator;
+
+  /**
+   * A list of all the MutatableCode that the CodeTranslator produced from
+   * CodeItems that are acceptable to mutate.
+   */
+  private List<MutatableCode> mutatableCodes;
+
+  /**
+   * A list of all MutatableCode items that were mutated when mutateTheProgram()
+   * was called. updateRawDexFile() will update the relevant CodeItems when called,
+   * and then clear this list.
+   */
+  private List<MutatableCode> mutatedCodes;
+
+  /**
+   * A list of all registered CodeMutators that this Program can use to mutate methods.
+   */
+  private List<CodeMutator> mutators;
+
+  /**
+   * Used if we're loading mutations from a file, so we can find the correct mutator.
+   */
+  private Map<Class<? extends CodeMutator>, CodeMutator> mutatorsLookupByClass;
+
+  /**
+   * Tracks mutation stats.
+   */
+  private MutationStats mutationStats;
+
+  /**
+   * A list of all mutations used for loading/dumping mutations from/to a file.
+   */
+  private List<Mutation> mutations;
+
+  /**
+   * The listener who is interested in events.
+   * May be a listener that is responsible for multiple listeners.
+   */
+  private BaseListener listener;
+
+  /**
+   * Given a maximum number of mutations that can be performed on a method, n,
+   * give up after attempting (n * this value) mutations for any method.
+   */
+  private static final int MAXIMUM_MUTATION_ATTEMPT_FACTOR = 10;
+
+  /**
+   * Construct the mutatable Program based on the raw DEX file that was parsed initially.
+   */
+  public Program(RawDexFile rawDexFile, List<Mutation> previousMutations,
+      BaseListener listener) {
+    this.listener = listener;
+
+    idCreator = new IdCreator(rawDexFile);
+
+    // Set up the RNG.
+    rng = new Random();
+    if (Options.usingProvidedSeed) {
+      rng.setSeed(Options.rngSeed);
+      rngSeed = Options.rngSeed;
+    } else {
+      long seed = System.currentTimeMillis();
+      listener.handleSeed(seed);
+      rng.setSeed(seed);
+      rngSeed = seed;
+    }
+
+    if (previousMutations != null) {
+      mutations = previousMutations;
+    } else {
+      // Allocate the mutations list.
+      mutations = new ArrayList<Mutation>();
+
+      // Read in the mutations if we need to.
+      if (Options.loadMutations) {
+        // Allocate the mutators lookup table.
+        mutatorsLookupByClass = new HashMap<Class<? extends CodeMutator>, CodeMutator>();
+        loadMutationsFromDisk(Options.loadMutationsFile);
+      }
+    }
+
+    // Allocate the mutators list.
+    mutators = new ArrayList<CodeMutator>();
+
+    this.rawDexFile = rawDexFile;
+
+    mutatableCodes = new ArrayList<MutatableCode>();
+    mutatedCodes = new ArrayList<MutatableCode>();
+
+    translator = new CodeTranslator();
+
+    mutationStats = new MutationStats();
+
+    // Register all the code mutators here.
+    registerMutator(new ArithOpChanger(rng, mutationStats, mutations));
+    registerMutator(new BranchShifter(rng, mutationStats, mutations));
+    registerMutator(new CmpBiasChanger(rng, mutationStats, mutations));
+    registerMutator(new ConstantValueChanger(rng, mutationStats, mutations));
+    registerMutator(new ConversionRepeater(rng, mutationStats, mutations));
+    registerMutator(new FieldFlagChanger(rng, mutationStats, mutations));
+    registerMutator(new InstructionDeleter(rng, mutationStats, mutations));
+    registerMutator(new InstructionDuplicator(rng, mutationStats, mutations));
+    registerMutator(new InstructionSwapper(rng, mutationStats, mutations));
+    registerMutator(new NewMethodCaller(rng, mutationStats, mutations));
+    registerMutator(new NonsenseStringPrinter(rng, mutationStats, mutations));
+    registerMutator(new PoolIndexChanger(rng, mutationStats, mutations));
+    registerMutator(new RandomInstructionGenerator(rng, mutationStats, mutations));
+    registerMutator(new SwitchBranchShifter(rng, mutationStats, mutations));
+    registerMutator(new TryBlockShifter(rng, mutationStats, mutations));
+    registerMutator(new ValuePrinter(rng, mutationStats, mutations));
+    registerMutator(new VRegChanger(rng, mutationStats, mutations));
+
+    associateClassDefsAndClassData();
+    associateCodeItemsWithMethodNames();
+
+    int codeItemIdx = 0;
+    for (CodeItem codeItem : rawDexFile.codeItems) {
+      if (legalToMutate(codeItem)) {
+        Log.debug("Legal to mutate code item " + codeItemIdx);
+        int mutatableCodeIdx = mutatableCodes.size();
+        mutatableCodes.add(translator.codeItemToMutatableCode(this, codeItem,
+            codeItemIdx, mutatableCodeIdx));
+      } else {
+        Log.debug("Not legal to mutate code item " + codeItemIdx);
+      }
+      codeItemIdx++;
+    }
+  }
+
+  private void registerMutator(CodeMutator mutator) {
+    if (mutator.canBeTriggered()) {
+      Log.debug("Registering mutator " + mutator.getClass().getSimpleName());
+      mutators.add(mutator);
+    }
+    if (Options.loadMutations) {
+      mutatorsLookupByClass.put(mutator.getClass(), mutator);
+    }
+  }
+
+  /**
+   * Associate ClassDefItem to a ClassDataItem and vice-versa.
+   * This is so when we're associating method names with code items,
+   * we can find the name of the class the method belongs to.
+   */
+  private void associateClassDefsAndClassData() {
+    for (ClassDefItem classDefItem : rawDexFile.classDefs) {
+      if (classDefItem.classDataOff.pointsToSomething()) {
+        ClassDataItem classDataItem = (ClassDataItem)
+            classDefItem.classDataOff.getPointedToItem();
+        classDataItem.meta.classDefItem = classDefItem;
+        classDefItem.meta.classDataItem = classDataItem;
+      }
+    }
+  }
+
+  /**
+   * For each CodeItem, find the name of the method the item represents.
+   * This is done to allow the filtering of mutating methods based on if
+   * they have the name *_MUTATE, but also for debugging info.
+   */
+  private void associateCodeItemsWithMethodNames() {
+    // Associate method names with codeItems.
+    for (ClassDataItem classDataItem : rawDexFile.classDatas) {
+
+      String className = "";
+      if (classDataItem.meta.classDefItem != null) {
+        int typeIdx = classDataItem.meta.classDefItem.classIdx;
+        TypeIdItem typeIdItem = rawDexFile.typeIds.get(typeIdx);
+        className = rawDexFile.stringDatas.get(typeIdItem.descriptorIdx).getString() + ".";
+      }
+
+      // Do direct methods...
+      // Track the current method index with this value, since the encoding in
+      // each EncodedMethod is the absolute index for the first EncodedMethod,
+      // and then relative index for the rest...
+      int methodIdx = 0;
+      for (EncodedMethod method : classDataItem.directMethods) {
+        methodIdx = associateMethod(method, methodIdx, className);
+      }
+      // Reset methodIdx for virtual methods...
+      methodIdx = 0;
+      for (EncodedMethod method : classDataItem.virtualMethods) {
+        methodIdx = associateMethod(method, methodIdx, className);
+      }
+    }
+  }
+
+  /**
+   * Associate the name of the provided method with its CodeItem, if it
+   * has one.
+   *
+   * @param methodIdx The method index of the last EncodedMethod that was handled in this class.
+   * @return The method index of the EncodedMethod that has just been handled in this class.
+   */
+  private int associateMethod(EncodedMethod method, int methodIdx, String className) {
+    if (!method.codeOff.pointsToSomething()) {
+      // This method doesn't have a code item, so we won't encounter it later.
+      return methodIdx;
+    }
+
+    // First method index is an absolute index.
+    // The rest are relative to the previous.
+    // (so if methodIdx is initialised to 0, this single line works)
+    methodIdx = methodIdx + method.methodIdxDiff;
+
+    // Get the name.
+    MethodIdItem methodIdItem = rawDexFile.methodIds.get(methodIdx);
+    ProtoIdItem protoIdItem = rawDexFile.protoIds.get(methodIdItem.protoIdx);
+    String shorty = rawDexFile.stringDatas.get(protoIdItem.shortyIdx).getString();
+    String methodName = className
+        + rawDexFile.stringDatas.get(methodIdItem.nameIdx).getString();
+
+    // Get the codeItem.
+    if (method.codeOff.getPointedToItem() instanceof CodeItem) {
+      CodeItem codeItem = (CodeItem) method.codeOff.getPointedToItem();
+      codeItem.meta.methodName = methodName;
+      codeItem.meta.shorty = shorty;
+      codeItem.meta.isStatic = method.isStatic();
+    } else {
+      Log.errorAndQuit("You've got an EncodedMethod that points to an Offsettable"
+          + " that does not contain a CodeItem");
+    }
+
+    return methodIdx;
+  }
+
+  /**
+   * Determine, based on the current options supplied to dexfuzz, as well as
+   * its capabilities, if the provided CodeItem can be mutated.
+   * @param codeItem The CodeItem we may wish to mutate.
+   * @return If the CodeItem can be mutated.
+   */
+  private boolean legalToMutate(CodeItem codeItem) {
+    if (!Options.mutateLimit) {
+      Log.debug("Mutating everything.");
+      return true;
+    }
+    if (codeItem.meta.methodName.endsWith("_MUTATE")) {
+      Log.debug("Code item marked with _MUTATE.");
+      return true;
+    }
+    Log.debug("Code item not marked with _MUTATE, but not mutating all code items.");
+    return false;
+  }
+
+  private int getNumberOfMutationsToPerform() {
+    // We want n mutations to be twice as likely as n+1 mutations.
+    //
+    // So if we have max 3,
+    // then 0 has 8 chances ("tickets"),
+    //      1 has 4 chances
+    //      2 has 2 chances
+    //  and 3 has 1 chance
+
+    // Allocate the tickets
+    // n mutations need (2^(n+1) - 1) tickets
+    // e.g.
+    // 3 mutations => 15 tickets
+    // 4 mutations => 31 tickets
+    int tickets = (2 << Options.methodMutations) - 1;
+
+    // Pick the lucky ticket
+    int luckyTicket = rng.nextInt(tickets);
+
+    // The tickets are put into buckets with accordance with log-base-2.
+    // have to make sure it's luckyTicket + 1, because log(0) is undefined
+    // so:
+    // log_2(1) => 0
+    // log_2(2) => 1
+    // log_2(3) => 1
+    // log_2(4) => 2
+    // log_2(5) => 2
+    // log_2(6) => 2
+    // log_2(7) => 2
+    // log_2(8) => 3
+    // ...
+    // so to make the highest mutation value the rarest,
+    //   subtract log_2(luckyTicket+1) from the maximum number
+    // log2(x) <=> 31 - Integer.numberOfLeadingZeros(x)
+    int luckyMutation = Options.methodMutations
+        - (31 - Integer.numberOfLeadingZeros(luckyTicket + 1));
+
+    return luckyMutation;
+  }
+
+  /**
+   * Returns true if we completely failed to mutate this method's mutatable code after
+   * attempting to.
+   */
+  private boolean mutateAMutatableCode(MutatableCode mutatableCode) {
+    int mutations = getNumberOfMutationsToPerform();
+
+    Log.info("Attempting " + mutations + " mutations for method " + mutatableCode.name);
+
+    int mutationsApplied = 0;
+
+    int maximumMutationAttempts = Options.methodMutations * MAXIMUM_MUTATION_ATTEMPT_FACTOR;
+    int mutationAttempts = 0;
+    boolean hadToBail = false;
+
+    while (mutationsApplied < mutations) {
+      int mutatorIdx = rng.nextInt(mutators.size());
+      CodeMutator mutator = mutators.get(mutatorIdx);
+      Log.info("Running mutator " + mutator.getClass().getSimpleName());
+      if (mutator.attemptToMutate(mutatableCode)) {
+        mutationsApplied++;
+      }
+      mutationAttempts++;
+      if (mutationAttempts > maximumMutationAttempts) {
+        Log.info("Bailing out on mutation for this method, tried too many times...");
+        hadToBail = true;
+        break;
+      }
+    }
+
+    // If any of them actually mutated it, excellent!
+    if (mutationsApplied > 0) {
+      Log.info("Method was mutated.");
+      mutatedCodes.add(mutatableCode);
+    } else {
+      Log.info("Method was not mutated.");
+    }
+
+    return ((mutationsApplied == 0) && hadToBail);
+  }
+
+  /**
+   * Go through each mutatable method in turn, and attempt to mutate it.
+   * Afterwards, call updateRawDexFile() to apply the results of mutation to the
+   * original code.
+   */
+  public void mutateTheProgram() {
+    if (Options.loadMutations) {
+      applyMutationsFromList();
+      return;
+    }
+
+    // Typically, this is 2 to 10...
+    int methodsToMutate = Options.minMethods
+        + rng.nextInt((Options.maxMethods - Options.minMethods) + 1);
+
+    // Check we aren't trying to mutate more methods than we have.
+    if (methodsToMutate > mutatableCodes.size()) {
+      methodsToMutate = mutatableCodes.size();
+    }
+
+    // Check if we're going to end up mutating all the methods.
+    if (methodsToMutate == mutatableCodes.size()) {
+      // Just do them all in order.
+      Log.info("Mutating all possible methods.");
+      for (MutatableCode mutatableCode : mutatableCodes) {
+        if (mutatableCode == null) {
+          Log.errorAndQuit("Why do you have a null MutatableCode?");
+        }
+        mutateAMutatableCode(mutatableCode);
+      }
+      Log.info("Finished mutating all possible methods.");
+    } else {
+      // Pick them at random.
+      Log.info("Randomly selecting " + methodsToMutate + " methods to mutate.");
+      while (mutatedCodes.size() < methodsToMutate) {
+        int randomMethodIdx = rng.nextInt(mutatableCodes.size());
+        MutatableCode mutatableCode = mutatableCodes.get(randomMethodIdx);
+        if (mutatableCode == null) {
+          Log.errorAndQuit("Why do you have a null MutatableCode?");
+        }
+        if (!mutatedCodes.contains(mutatableCode)) {
+          boolean completelyFailedToMutate = mutateAMutatableCode(mutatableCode);
+          if (completelyFailedToMutate) {
+            methodsToMutate--;
+          }
+        }
+      }
+      Log.info("Finished mutating the methods.");
+    }
+
+    listener.handleMutationStats(mutationStats.getStatsString());
+
+    if (Options.dumpMutations) {
+      writeMutationsToDisk(Options.dumpMutationsFile);
+    }
+  }
+
+  private void writeMutationsToDisk(String fileName) {
+    Log.debug("Writing mutations to disk.");
+    try {
+      BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
+      for (Mutation mutation : mutations) {
+        MutationSerializer.writeMutation(writer, mutation);
+      }
+      writer.close();
+    } catch (IOException e) {
+      Log.errorAndQuit("IOException while writing mutations to disk...");
+    }
+  }
+
+  private void loadMutationsFromDisk(String fileName) {
+    Log.debug("Loading mutations from disk.");
+    try {
+      BufferedReader reader = new BufferedReader(new FileReader(fileName));
+      while (reader.ready()) {
+        Mutation mutation = MutationSerializer.readMutation(reader);
+        mutations.add(mutation);
+      }
+      reader.close();
+    } catch (IOException e) {
+      Log.errorAndQuit("IOException while loading mutations from disk...");
+    }
+  }
+
+  private void applyMutationsFromList() {
+    Log.info("Applying preloaded list of mutations...");
+    for (Mutation mutation : mutations) {
+      // Repopulate the MutatableCode field from the recorded index into the Program's list.
+      mutation.mutatableCode = mutatableCodes.get(mutation.mutatableCodeIdx);
+
+      // Get the right mutator.
+      CodeMutator mutator = mutatorsLookupByClass.get(mutation.mutatorClass);
+
+      // Apply the mutation.
+      mutator.forceMutate(mutation);
+
+      // Add this mutatable code to the list of mutated codes, if we haven't already.
+      if (!mutatedCodes.contains(mutation.mutatableCode)) {
+        mutatedCodes.add(mutation.mutatableCode);
+      }
+    }
+    Log.info("...finished applying preloaded list of mutations.");
+  }
+
+  public List<Mutation> getMutations() {
+    return mutations;
+  }
+
+  /**
+   * Updates any CodeItems that need to be updated after mutation.
+   */
+  public boolean updateRawDexFile() {
+    boolean anythingMutated = !(mutatedCodes.isEmpty());
+    for (MutatableCode mutatedCode : mutatedCodes) {
+      translator.mutatableCodeToCodeItem(rawDexFile.codeItems
+          .get(mutatedCode.codeItemIdx), mutatedCode);
+    }
+    mutatedCodes.clear();
+    return anythingMutated;
+  }
+
+  public void writeRawDexFile(DexRandomAccessFile file) throws IOException {
+    rawDexFile.write(file);
+  }
+
+  public void updateRawDexFileHeader(DexRandomAccessFile file) throws IOException {
+    rawDexFile.updateHeader(file);
+  }
+
+  /**
+   * Used by the CodeMutators to determine legal index values.
+   */
+  public int getTotalPoolIndicesByKind(PoolIndexKind poolIndexKind) {
+    switch (poolIndexKind) {
+      case Type:
+        return rawDexFile.typeIds.size();
+      case Field:
+        return rawDexFile.fieldIds.size();
+      case String:
+        return rawDexFile.stringIds.size();
+      case Method:
+        return rawDexFile.methodIds.size();
+      case Invalid:
+        return 0;
+      default:
+    }
+    return 0;
+  }
+
+  /**
+   * Used by the CodeMutators to lookup and/or create Ids.
+   */
+  public IdCreator getNewItemCreator() {
+    return idCreator;
+  }
+
+  /**
+   * Used by FieldFlagChanger, to find an EncodedField for a specified field in an insn,
+   * if that field is actually defined in this DEX file. If not, null is returned.
+   */
+  public EncodedField getEncodedField(int fieldIdx) {
+    if (fieldIdx >= rawDexFile.fieldIds.size()) {
+      Log.debug(String.format("Field idx 0x%x specified is not defined in this DEX file.",
+          fieldIdx));
+      return null;
+    }
+    FieldIdItem fieldId = rawDexFile.fieldIds.get(fieldIdx);
+
+    for (ClassDefItem classDef : rawDexFile.classDefs) {
+      if (classDef.classIdx == fieldId.classIdx) {
+        ClassDataItem classData = classDef.meta.classDataItem;
+        return classData.getEncodedFieldWithIndex(fieldIdx);
+      }
+    }
+
+    Log.debug(String.format("Field idx 0x%x specified is not defined in this DEX file.",
+        fieldIdx));
+    return null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/ArithOpChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/ArithOpChanger.java
new file mode 100644
index 0000000..4c69694
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/ArithOpChanger.java
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class ArithOpChanger extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int arithmeticInsnIdx;
+    public int newOpcode;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(arithmeticInsnIdx).append(" ");
+      builder.append(newOpcode);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      arithmeticInsnIdx = Integer.parseInt(elements[2]);
+      newOpcode = Integer.parseInt(elements[3]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public ArithOpChanger() { }
+
+  public ArithOpChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 75;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> arithmeticInsns = null;
+
+  private void generateCachedArithmeticInsns(MutatableCode mutatableCode) {
+    if (arithmeticInsns != null) {
+      return;
+    }
+
+    arithmeticInsns = new ArrayList<MInsn>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isArithmeticOperation(mInsn)) {
+        arithmeticInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isArithmeticOperation(mInsn)) {
+        return true;
+      }
+    }
+
+    Log.debug("No arithmetic operations in method, skipping...");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedArithmeticInsns(mutatableCode);
+
+    int arithmeticInsnIdx = rng.nextInt(arithmeticInsns.size());
+
+    MInsn randomInsn = arithmeticInsns.get(arithmeticInsnIdx);
+
+    OpcodeInfo oldOpcodeInfo = randomInsn.insn.info;
+
+    OpcodeInfo newOpcodeInfo = oldOpcodeInfo;
+
+    while (newOpcodeInfo.value == oldOpcodeInfo.value) {
+      newOpcodeInfo = Instruction.getOpcodeInfo(getLegalDifferentOpcode(randomInsn));
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.arithmeticInsnIdx = arithmeticInsnIdx;
+    mutation.newOpcode = newOpcodeInfo.value;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedArithmeticInsns(mutatableCode);
+
+    MInsn randomInsn = arithmeticInsns.get(mutation.arithmeticInsnIdx);
+
+    String oldInsnString = randomInsn.toString();
+
+    OpcodeInfo newOpcodeInfo = Instruction.getOpcodeInfo(mutation.newOpcode);
+
+    randomInsn.insn.info = newOpcodeInfo;
+
+    Log.info("Changed " + oldInsnString + " to " + randomInsn);
+
+    stats.incrementStat("Changed arithmetic opcode");
+
+    // Clear the cache.
+    arithmeticInsns = null;
+  }
+
+  private boolean isArithmeticOperation(MInsn mInsn) {
+    Opcode opcode = mInsn.insn.info.opcode;
+    if (Opcode.isBetween(opcode, Opcode.ADD_INT, Opcode.USHR_INT_LIT8)) {
+      return true;
+    }
+    return false;
+  }
+
+  private Opcode getLegalDifferentOpcode(MInsn mInsn) {
+    Opcode opcode = mInsn.insn.info.opcode;
+
+    for (List<Opcode> opcodeList : opcodeLists) {
+      Opcode first = opcodeList.get(0);
+      Opcode last = opcodeList.get(opcodeList.size() - 1);
+      if (Opcode.isBetween(opcode, first, last)) {
+        int newOpcodeIdx = rng.nextInt(opcodeList.size());
+        return opcodeList.get(newOpcodeIdx);
+      }
+    }
+
+    return opcode;
+  }
+
+  private static List<Opcode> intOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> int2addrOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> longOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> long2addrOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> floatOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> float2addrOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> doubleOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> double2addrOpcodes = new ArrayList<Opcode>();
+  private static List<Opcode> intLit8Opcodes = new ArrayList<Opcode>();
+  private static List<Opcode> intLit16Opcodes = new ArrayList<Opcode>();
+  private static List<List<Opcode>> opcodeLists = new ArrayList<List<Opcode>>();
+
+  static {
+    intOpcodes.add(Opcode.ADD_INT);
+    intOpcodes.add(Opcode.SUB_INT);
+    intOpcodes.add(Opcode.MUL_INT);
+    intOpcodes.add(Opcode.DIV_INT);
+    intOpcodes.add(Opcode.REM_INT);
+    intOpcodes.add(Opcode.AND_INT);
+    intOpcodes.add(Opcode.OR_INT);
+    intOpcodes.add(Opcode.XOR_INT);
+    intOpcodes.add(Opcode.SHL_INT);
+    intOpcodes.add(Opcode.SHR_INT);
+    intOpcodes.add(Opcode.USHR_INT);
+
+    int2addrOpcodes.add(Opcode.ADD_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.SUB_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.MUL_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.DIV_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.REM_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.AND_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.OR_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.XOR_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.SHL_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.SHR_INT_2ADDR);
+    int2addrOpcodes.add(Opcode.USHR_INT_2ADDR);
+
+    longOpcodes.add(Opcode.ADD_LONG);
+    longOpcodes.add(Opcode.SUB_LONG);
+    longOpcodes.add(Opcode.MUL_LONG);
+    longOpcodes.add(Opcode.DIV_LONG);
+    longOpcodes.add(Opcode.REM_LONG);
+    longOpcodes.add(Opcode.AND_LONG);
+    longOpcodes.add(Opcode.OR_LONG);
+    longOpcodes.add(Opcode.XOR_LONG);
+    longOpcodes.add(Opcode.SHL_LONG);
+    longOpcodes.add(Opcode.SHR_LONG);
+    longOpcodes.add(Opcode.USHR_LONG);
+
+    long2addrOpcodes.add(Opcode.ADD_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.SUB_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.MUL_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.DIV_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.REM_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.AND_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.OR_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.XOR_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.SHL_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.SHR_LONG_2ADDR);
+    long2addrOpcodes.add(Opcode.USHR_LONG_2ADDR);
+
+    floatOpcodes.add(Opcode.ADD_FLOAT);
+    floatOpcodes.add(Opcode.SUB_FLOAT);
+    floatOpcodes.add(Opcode.MUL_FLOAT);
+    floatOpcodes.add(Opcode.DIV_FLOAT);
+    floatOpcodes.add(Opcode.REM_FLOAT);
+
+    float2addrOpcodes.add(Opcode.ADD_FLOAT_2ADDR);
+    float2addrOpcodes.add(Opcode.SUB_FLOAT_2ADDR);
+    float2addrOpcodes.add(Opcode.MUL_FLOAT_2ADDR);
+    float2addrOpcodes.add(Opcode.DIV_FLOAT_2ADDR);
+    float2addrOpcodes.add(Opcode.REM_FLOAT_2ADDR);
+
+    doubleOpcodes.add(Opcode.ADD_DOUBLE);
+    doubleOpcodes.add(Opcode.SUB_DOUBLE);
+    doubleOpcodes.add(Opcode.MUL_DOUBLE);
+    doubleOpcodes.add(Opcode.DIV_DOUBLE);
+    doubleOpcodes.add(Opcode.REM_DOUBLE);
+
+    double2addrOpcodes.add(Opcode.ADD_DOUBLE_2ADDR);
+    double2addrOpcodes.add(Opcode.SUB_DOUBLE_2ADDR);
+    double2addrOpcodes.add(Opcode.MUL_DOUBLE_2ADDR);
+    double2addrOpcodes.add(Opcode.DIV_DOUBLE_2ADDR);
+    double2addrOpcodes.add(Opcode.REM_DOUBLE_2ADDR);
+
+    intLit8Opcodes.add(Opcode.ADD_INT_LIT8);
+    intLit8Opcodes.add(Opcode.RSUB_INT_LIT8);
+    intLit8Opcodes.add(Opcode.MUL_INT_LIT8);
+    intLit8Opcodes.add(Opcode.DIV_INT_LIT8);
+    intLit8Opcodes.add(Opcode.REM_INT_LIT8);
+    intLit8Opcodes.add(Opcode.AND_INT_LIT8);
+    intLit8Opcodes.add(Opcode.OR_INT_LIT8);
+    intLit8Opcodes.add(Opcode.XOR_INT_LIT8);
+    intLit8Opcodes.add(Opcode.SHL_INT_LIT8);
+    intLit8Opcodes.add(Opcode.SHR_INT_LIT8);
+    intLit8Opcodes.add(Opcode.USHR_INT_LIT8);
+
+    intLit16Opcodes.add(Opcode.ADD_INT_LIT16);
+    intLit16Opcodes.add(Opcode.RSUB_INT);
+    intLit16Opcodes.add(Opcode.MUL_INT_LIT16);
+    intLit16Opcodes.add(Opcode.DIV_INT_LIT16);
+    intLit16Opcodes.add(Opcode.REM_INT_LIT16);
+    intLit16Opcodes.add(Opcode.AND_INT_LIT16);
+    intLit16Opcodes.add(Opcode.OR_INT_LIT16);
+    intLit16Opcodes.add(Opcode.XOR_INT_LIT16);
+
+    opcodeLists.add(intOpcodes);
+    opcodeLists.add(longOpcodes);
+    opcodeLists.add(floatOpcodes);
+    opcodeLists.add(doubleOpcodes);
+    opcodeLists.add(int2addrOpcodes);
+    opcodeLists.add(long2addrOpcodes);
+    opcodeLists.add(float2addrOpcodes);
+    opcodeLists.add(double2addrOpcodes);
+    opcodeLists.add(intLit8Opcodes);
+    opcodeLists.add(intLit16Opcodes);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/BranchShifter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/BranchShifter.java
new file mode 100644
index 0000000..a28f5ba
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/BranchShifter.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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MBranchInsn;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class BranchShifter extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int branchInsnIdx;
+    public int newTargetIdx;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(branchInsnIdx).append(" ");
+      builder.append(newTargetIdx);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      branchInsnIdx = Integer.parseInt(elements[2]);
+      newTargetIdx = Integer.parseInt(elements[3]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public BranchShifter() { }
+
+  public BranchShifter(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 30;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MBranchInsn> branchInsns;
+
+  private void generateCachedBranchInsns(MutatableCode mutatableCode) {
+    if (branchInsns != null) {
+      return;
+    }
+
+    branchInsns = new ArrayList<MBranchInsn>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MBranchInsn) {
+        branchInsns.add((MBranchInsn) mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    // Can't shift a branch if there's only one instruction in the method.
+    if (mutatableCode.getInstructionCount() == 1) {
+      Log.debug("Method contains only one instruction, skipping.");
+      return false;
+    }
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MBranchInsn) {
+        return true;
+      }
+    }
+
+    Log.debug("Method contains no branch instructions.");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedBranchInsns(mutatableCode);
+
+    // Pick a random branching instruction.
+    int branchInsnIdx = rng.nextInt(branchInsns.size());
+    MBranchInsn branchInsn = branchInsns.get(branchInsnIdx);
+
+    // Get its original target, find its index.
+    MInsn oldTargetInsn = branchInsn.target;
+    int oldTargetInsnIdx = mutatableCode.getInstructionIndex(oldTargetInsn);
+
+    int newTargetIdx = oldTargetInsnIdx;
+
+    int delta = 0;
+
+    // Keep searching for a new index.
+    while (newTargetIdx == oldTargetInsnIdx) {
+      // Vary by +/- 2 instructions.
+      delta = 0;
+      while (delta == 0) {
+        delta = (rng.nextInt(5) - 2);
+      }
+
+      newTargetIdx = oldTargetInsnIdx + delta;
+
+      // Check the new index is legal.
+      if (newTargetIdx < 0) {
+        newTargetIdx = 0;
+      } else if (newTargetIdx >= mutatableCode.getInstructionCount()) {
+        newTargetIdx = mutatableCode.getInstructionCount() - 1;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.branchInsnIdx = branchInsnIdx;
+    mutation.newTargetIdx = newTargetIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedBranchInsns(mutatableCode);
+
+    MBranchInsn branchInsn = branchInsns.get(mutation.branchInsnIdx);
+
+    // Get the new target.
+    MInsn newTargetInsn = mutatableCode.getInstructionAt(mutation.newTargetIdx);
+
+    // Set the new target.
+    branchInsn.target = newTargetInsn;
+
+    Log.info("Shifted the target of " + branchInsn + " to point to " + newTargetInsn);
+
+    stats.incrementStat("Shifted branch target");
+
+    // Clear cache.
+    branchInsns = null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/CmpBiasChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/CmpBiasChanger.java
new file mode 100644
index 0000000..dc60e79
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/CmpBiasChanger.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class CmpBiasChanger extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int cmpBiasInsnIdx;
+
+    @Override
+    public String getString() {
+      return Integer.toString(cmpBiasInsnIdx);
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      cmpBiasInsnIdx = Integer.parseInt(elements[2]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public CmpBiasChanger() { }
+
+  public CmpBiasChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 30;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> cmpBiasInsns = null;
+
+  private void generateCachedCmpBiasInsns(MutatableCode mutatableCode) {
+    if (cmpBiasInsns != null) {
+      return;
+    }
+
+    cmpBiasInsns = new ArrayList<MInsn>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isCmpBiasOperation(mInsn)) {
+        cmpBiasInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isCmpBiasOperation(mInsn)) {
+        return true;
+      }
+    }
+
+    Log.debug("No cmp-with-bias operations in method, skipping...");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedCmpBiasInsns(mutatableCode);
+
+    int cmpBiasInsnIdx = rng.nextInt(cmpBiasInsns.size());
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.cmpBiasInsnIdx = cmpBiasInsnIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedCmpBiasInsns(mutatableCode);
+
+    MInsn cmpBiasInsn = cmpBiasInsns.get(mutation.cmpBiasInsnIdx);
+
+    String oldInsnString = cmpBiasInsn.toString();
+
+    Opcode newOpcode = getLegalDifferentOpcode(cmpBiasInsn);
+
+    cmpBiasInsn.insn.info = Instruction.getOpcodeInfo(newOpcode);
+
+    Log.info("Changed " + oldInsnString + " to " + cmpBiasInsn);
+
+    stats.incrementStat("Changed comparison bias");
+
+    // Clear cache.
+    cmpBiasInsns = null;
+  }
+
+  private Opcode getLegalDifferentOpcode(MInsn mInsn) {
+    Opcode opcode = mInsn.insn.info.opcode;
+    if (opcode == Opcode.CMPG_DOUBLE) {
+      return Opcode.CMPL_DOUBLE;
+    }
+    if (opcode == Opcode.CMPL_DOUBLE) {
+      return Opcode.CMPG_DOUBLE;
+    }
+    if (opcode == Opcode.CMPG_FLOAT) {
+      return Opcode.CMPL_FLOAT;
+    }
+    return Opcode.CMPG_FLOAT;
+  }
+
+  private boolean isCmpBiasOperation(MInsn mInsn) {
+    Opcode opcode = mInsn.insn.info.opcode;
+    if (Opcode.isBetween(opcode, Opcode.CMPL_FLOAT, Opcode.CMPG_DOUBLE)) {
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/CodeMutator.java b/tools/dexfuzz/src/dexfuzz/program/mutators/CodeMutator.java
new file mode 100644
index 0000000..be566ad
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/CodeMutator.java
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.Options;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+
+import java.util.List;
+import java.util.Random;
+
+/**
+ * The base class for all classes that can mutate methods.
+ */
+public abstract class CodeMutator {
+  /**
+   * The RNG, passed in by the Program that initialised us.
+   */
+  protected Random rng;
+
+  /**
+   * Used to track which mutations happen.
+   */
+  protected MutationStats stats;
+
+  /**
+   * Used to track mutations that have been applied so far.
+   */
+  protected List<Mutation> mutations;
+
+  /**
+   * The chance, out of 100, that this mutator actually mutates the the program
+   * when asked to by the Program. The default is 50% chance, but each mutator that
+   * extends CodeMutator should its own default.
+   */
+  protected int likelihood = 50;
+
+  /**
+   * This constructor is only intended for use in MutationRecorder...
+   */
+  public CodeMutator() {
+
+  }
+
+  /**
+   * Constructor that all subclasses must call...
+   *
+   * @param rng The RNG that the Program created.
+   */
+  public CodeMutator(Random rng, MutationStats stats, List<Mutation> mutations) {
+    this.rng = rng;
+    this.stats = stats;
+    this.mutations = mutations;
+
+    String name = this.getClass().getSimpleName().toLowerCase();
+
+    if (Options.mutationLikelihoods.containsKey(name)) {
+      likelihood = Options.mutationLikelihoods.get(name);
+      Log.info("Set mutation likelihood to " + likelihood
+          + "% for " + this.getClass().getSimpleName());
+    }
+  }
+
+  /**
+   * When the Program picks a particular mutator to mutate the code, it calls
+   * this function, that determines if the mutator will actually mutate the code.
+   * If so, it then calls the mutationFunction() method, that every subclass CodeMutator
+   * is expected to implement to perform its mutation.
+   *
+   * @return If mutation took place.
+   */
+  public boolean attemptToMutate(MutatableCode mutatableCode) {
+    if (shouldMutate(mutatableCode)) {
+      generateAndApplyMutation(mutatableCode);
+      return true;
+    }
+    Log.info("Skipping mutation.");
+    return false;
+  }
+
+  public void forceMutate(Mutation mutation) {
+    Log.info("Forcing mutation.");
+    applyMutation(mutation);
+  }
+
+  public boolean canBeTriggered() {
+    return (likelihood > 0);
+  }
+
+  /**
+   * Randomly determine if the mutator will actually mutate a method, based on its
+   * provided likelihood of mutation.
+   *
+   * @return If the method should be mutated.
+   */
+  private boolean shouldMutate(MutatableCode mutatableCode) {
+    return ((rng.nextInt(100) < likelihood) && canMutate(mutatableCode));
+  }
+
+  private void generateAndApplyMutation(MutatableCode mutatableCode) {
+    Mutation mutation = generateMutation(mutatableCode);
+    // Always save the mutation.
+    mutations.add(mutation);
+    applyMutation(mutation);
+  }
+
+  /**
+   * A CodeMutator must override this method if there is any reason why could not mutate
+   * a particular method, and return false in that case.
+   */
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    return true;
+  }
+
+  protected abstract Mutation generateMutation(MutatableCode mutatableCode);
+
+  protected abstract void applyMutation(Mutation uncastMutation);
+
+  public abstract Mutation getNewMutation();
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/ConstantValueChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/ConstantValueChanger.java
new file mode 100644
index 0000000..22f04e8
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/ConstantValueChanger.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.formats.ContainsConst;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class ConstantValueChanger extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int constInsnIdx;
+    public long newConstant;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(constInsnIdx).append(" ");
+      builder.append(newConstant);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      constInsnIdx = Integer.parseInt(elements[2]);
+      newConstant = Long.parseLong(elements[3]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public ConstantValueChanger() { }
+
+  public ConstantValueChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 70;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> constInsns = null;
+
+  private void generateCachedConstInsns(MutatableCode mutatableCode) {
+    if (constInsns != null) {
+      return;
+    }
+
+    constInsns = new ArrayList<MInsn>();
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.info.format instanceof ContainsConst) {
+        constInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.info.format instanceof ContainsConst) {
+        return true;
+      }
+    }
+
+    Log.debug("Method contains no const instructions.");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedConstInsns(mutatableCode);
+
+    // Pick a random const instruction.
+    int constInsnIdx = rng.nextInt(constInsns.size());
+    MInsn constInsn = constInsns.get(constInsnIdx);
+
+    // Get the constant.
+    long oldConstant = ((ContainsConst)constInsn.insn.info.format).getConst(constInsn.insn);
+
+    long newConstant = oldConstant;
+
+    // Make a new constant.
+    while (newConstant == oldConstant) {
+      newConstant = rng.nextLong()
+          % ((ContainsConst)constInsn.insn.info.format).getConstRange();
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.constInsnIdx = constInsnIdx;
+    mutation.newConstant = newConstant;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedConstInsns(mutatableCode);
+
+    MInsn constInsn = constInsns.get(mutation.constInsnIdx);
+
+    long oldConstant = ((ContainsConst)constInsn.insn.info.format).getConst(constInsn.insn);
+
+    Log.info("Changed constant value #" + oldConstant + " to #" + mutation.newConstant
+        + " in " + constInsn);
+
+    stats.incrementStat("Changed constant value");
+
+    // Set the new constant.
+    ((ContainsConst)constInsn.insn.info.format).setConst(constInsn.insn, mutation.newConstant);
+
+    // Clear cache.
+    constInsns = null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/ConversionRepeater.java b/tools/dexfuzz/src/dexfuzz/program/mutators/ConversionRepeater.java
new file mode 100644
index 0000000..7fdf304
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/ConversionRepeater.java
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class ConversionRepeater extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int conversionInsnIdx;
+
+    @Override
+    public String getString() {
+      return Integer.toString(conversionInsnIdx);
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      conversionInsnIdx = Integer.parseInt(elements[2]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public ConversionRepeater() { }
+
+  public ConversionRepeater(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 50;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> conversionInsns = null;
+
+  private void generateCachedConversionInsns(MutatableCode mutatableCode) {
+    if (conversionInsns != null) {
+      return;
+    }
+
+    conversionInsns = new ArrayList<MInsn>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isConversionInstruction(mInsn)) {
+        conversionInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isConversionInstruction(mInsn)) {
+        return true;
+      }
+    }
+
+    Log.debug("No conversion operations in method, skipping...");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedConversionInsns(mutatableCode);
+    int conversionInsnIdx = rng.nextInt(conversionInsns.size());
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.conversionInsnIdx = conversionInsnIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedConversionInsns(mutatableCode);
+
+    MInsn originalInsn = conversionInsns.get(mutation.conversionInsnIdx);
+
+    // We want to create two new instructions:
+    // [original conversion] eg float-to-int
+    // NEW: [there] eg int-to-float (with vregs of first inst swapped)
+    // NEW: [back] eg float-to-int
+
+    // Create the "there" instruction.
+    MInsn newInsnThere = originalInsn.clone();
+
+    // Flip the opcode.
+    Opcode oppositeOpcode = null;
+    switch (newInsnThere.insn.info.opcode) {
+      case INT_TO_LONG:
+        oppositeOpcode = Opcode.LONG_TO_INT;
+        break;
+      case INT_TO_FLOAT:
+        oppositeOpcode = Opcode.FLOAT_TO_INT;
+        break;
+      case INT_TO_DOUBLE:
+        oppositeOpcode = Opcode.DOUBLE_TO_INT;
+        break;
+      case LONG_TO_INT:
+        oppositeOpcode = Opcode.INT_TO_LONG;
+        break;
+      case LONG_TO_FLOAT:
+        oppositeOpcode = Opcode.FLOAT_TO_LONG;
+        break;
+      case LONG_TO_DOUBLE:
+        oppositeOpcode = Opcode.DOUBLE_TO_LONG;
+        break;
+      case FLOAT_TO_INT:
+        oppositeOpcode = Opcode.INT_TO_FLOAT;
+        break;
+      case FLOAT_TO_LONG:
+        oppositeOpcode = Opcode.LONG_TO_FLOAT;
+        break;
+      case FLOAT_TO_DOUBLE:
+        oppositeOpcode = Opcode.DOUBLE_TO_FLOAT;
+        break;
+      case DOUBLE_TO_INT:
+        oppositeOpcode = Opcode.INT_TO_DOUBLE;
+        break;
+      case DOUBLE_TO_LONG:
+        oppositeOpcode = Opcode.LONG_TO_DOUBLE;
+        break;
+      case DOUBLE_TO_FLOAT:
+        oppositeOpcode = Opcode.FLOAT_TO_DOUBLE;
+        break;
+      default:
+        Log.errorAndQuit(
+            "Trying to repeat the conversion in an insn that is not a conversion insn.");
+    }
+    newInsnThere.insn.info = Instruction.getOpcodeInfo(oppositeOpcode);
+
+    // Swap the vregs.
+    long tempReg = newInsnThere.insn.vregA;
+    newInsnThere.insn.vregA = newInsnThere.insn.vregB;
+    newInsnThere.insn.vregB = tempReg;
+
+    // Create the "back" instruction.
+    MInsn newInsnBack = originalInsn.clone();
+
+    // Get the index into the MutatableCode's mInsns list for this insn.
+    int originalInsnIdx = mutatableCode.getInstructionIndex(originalInsn);
+
+    // Insert the new instructions.
+    mutatableCode.insertInstructionAfter(newInsnThere, originalInsnIdx);
+    mutatableCode.insertInstructionAfter(newInsnBack, originalInsnIdx + 1);
+
+    Log.info("Performing conversion repetition for " + originalInsn);
+
+    stats.incrementStat("Repeating conversion");
+
+    // Clear the cache.
+    conversionInsns = null;
+  }
+
+  private boolean isConversionInstruction(MInsn mInsn) {
+    Opcode opcode = mInsn.insn.info.opcode;
+    if (Opcode.isBetween(opcode, Opcode.INT_TO_LONG, Opcode.DOUBLE_TO_FLOAT)) {
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/FieldFlagChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/FieldFlagChanger.java
new file mode 100644
index 0000000..0849d12
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/FieldFlagChanger.java
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.EncodedField;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.formats.ContainsPoolIndex;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class FieldFlagChanger extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int fieldInsnIdx;
+    public boolean setVolatile;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(fieldInsnIdx).append(" ");
+      builder.append(setVolatile);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      fieldInsnIdx = Integer.parseInt(elements[2]);
+      setVolatile = Boolean.parseBoolean(elements[3]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public FieldFlagChanger() { }
+
+  public FieldFlagChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 40;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> fieldInsns = null;
+
+  private void generateCachedFieldInsns(MutatableCode mutatableCode) {
+    if (fieldInsns != null) {
+      return;
+    }
+
+    fieldInsns = new ArrayList<MInsn>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isFileDefinedFieldInstruction(mInsn, mutatableCode)) {
+        fieldInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (isFileDefinedFieldInstruction(mInsn, mutatableCode)) {
+        return true;
+      }
+    }
+
+    Log.debug("No field instructions in method, skipping...");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedFieldInsns(mutatableCode);
+
+    int fieldInsnIdx = rng.nextInt(fieldInsns.size());
+
+    Instruction insn = fieldInsns.get(fieldInsnIdx).insn;
+    ContainsPoolIndex containsPoolIndex = (ContainsPoolIndex) insn.info.format;
+    int fieldIdx = containsPoolIndex.getPoolIndex(insn);
+    EncodedField encodedField = mutatableCode.program.getEncodedField(fieldIdx);
+
+    boolean setVolatile = false;
+    if (!encodedField.isVolatile()) {
+      setVolatile = true;
+    }
+    // TODO: Flip more flags?
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.fieldInsnIdx = fieldInsnIdx;
+    mutation.setVolatile = setVolatile;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedFieldInsns(mutatableCode);
+
+    Instruction insn = fieldInsns.get(mutation.fieldInsnIdx).insn;
+    ContainsPoolIndex containsPoolIndex = (ContainsPoolIndex) insn.info.format;
+    int fieldIdx = containsPoolIndex.getPoolIndex(insn);
+    EncodedField encodedField = mutatableCode.program.getEncodedField(fieldIdx);
+
+    if (mutation.setVolatile) {
+      encodedField.setVolatile(true);
+      Log.info("Set field idx " + fieldIdx + " as volatile");
+    } else {
+      encodedField.setVolatile(false);
+      Log.info("Set field idx " + fieldIdx + " as not volatile");
+    }
+
+    stats.incrementStat("Changed volatility of field");
+
+    // Clear cache.
+    fieldInsns = null;
+  }
+
+  private boolean isFileDefinedFieldInstruction(MInsn mInsn, MutatableCode mutatableCode) {
+    Opcode opcode = mInsn.insn.info.opcode;
+    if (Opcode.isBetween(opcode, Opcode.IGET, Opcode.SPUT_SHORT)) {
+      Instruction insn = mInsn.insn;
+      ContainsPoolIndex containsPoolIndex = (ContainsPoolIndex) insn.info.format;
+      int fieldIdx = containsPoolIndex.getPoolIndex(insn);
+      if (mutatableCode.program.getEncodedField(fieldIdx) != null) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionDeleter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionDeleter.java
new file mode 100644
index 0000000..8ffa4c5
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionDeleter.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MInsnWithData;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+
+import java.util.List;
+import java.util.Random;
+
+public class InstructionDeleter extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int insnToDeleteIdx;
+
+    @Override
+    public String getString() {
+      return Integer.toString(insnToDeleteIdx);
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      insnToDeleteIdx = Integer.parseInt(elements[2]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public InstructionDeleter() { }
+
+  public InstructionDeleter(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 40;
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    if (mutatableCode.getInstructionCount() < 4) {
+      // TODO: Make this more sophisticated - right now this is to avoid problems with
+      // a method that has 3 instructions: fill-array-data; return-void; <data for fill-array-data>
+      Log.debug("Cannot delete insns in a method with only a few.");
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    // Pick an instruction at random...
+    int insnIdx = rng.nextInt(mutatableCode.getInstructionCount());
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.insnToDeleteIdx = insnIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    MInsn toBeDeleted =
+        mutatableCode.getInstructionAt(mutation.insnToDeleteIdx);
+
+    Log.info("Deleting " + toBeDeleted);
+
+    stats.incrementStat("Deleted instruction");
+
+    // Delete the instruction.
+    mutatableCode.deleteInstruction(mutation.insnToDeleteIdx);
+
+    // If we delete a with-data insn, we should delete the associated data insn as well.
+    if (toBeDeleted instanceof MInsnWithData) {
+      Log.info(toBeDeleted + " had associated data, so the data insn was deleted.");
+      // Get the data instruction.
+      MInsn dataInsn =
+          ((MInsnWithData)toBeDeleted).dataTarget;
+      mutatableCode.deleteInstruction(dataInsn);
+      stats.incrementStat("Deleted a with-data insn's data");
+    }
+    // If we delete a data insn, we should delete the associated with-data insn as well.
+    if (toBeDeleted.insn.justRaw) {
+      // .justRaw implies that this is a data insn.
+      Log.info(toBeDeleted
+          + " was data, so the associated with-data insn was deleted.");
+
+      // First, find the with-data insn that is pointing to this insn.
+      MInsn withDataInsn = null;
+      for (MInsn mInsn : mutatableCode.getInstructions()) {
+        if (mInsn instanceof MInsnWithData) {
+          if (((MInsnWithData)mInsn).dataTarget == toBeDeleted) {
+            withDataInsn = mInsn;
+            break;
+          }
+        }
+      }
+
+      // Now delete the with-data insn.
+      if (withDataInsn != null) {
+        mutatableCode.deleteInstruction(withDataInsn);
+        stats.incrementStat("Deleted a data insn's with-data insn");
+      } else {
+        Log.errorAndQuit("Tried to delete a data insn, "
+            + "but it didn't have any with-data insn pointing at it?");
+      }
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionDuplicator.java b/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionDuplicator.java
new file mode 100644
index 0000000..4917056
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionDuplicator.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.List;
+import java.util.Random;
+
+public class InstructionDuplicator extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int insnToDuplicateIdx;
+
+    @Override
+    public String getString() {
+      return Integer.toString(insnToDuplicateIdx);
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      insnToDuplicateIdx = Integer.parseInt(elements[2]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public InstructionDuplicator() { }
+
+  public InstructionDuplicator(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 80;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    boolean foundInsn = false;
+    int insnIdx = 0;
+
+    while (!foundInsn) {
+      // Pick an instruction at random...
+      insnIdx = rng.nextInt(mutatableCode.getInstructionCount());
+      MInsn oldInsn = mutatableCode.getInstructionAt(insnIdx);
+      foundInsn = true;
+      Opcode opcode = oldInsn.insn.info.opcode;
+      // ...check it's a legal instruction to duplicate.
+      if (opcode == Opcode.SPARSE_SWITCH || opcode == Opcode.PACKED_SWITCH
+          || opcode == Opcode.FILL_ARRAY_DATA || oldInsn.insn.justRaw) {
+        foundInsn = false;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.insnToDuplicateIdx = insnIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    MInsn oldInsn = mutatableCode.getInstructionAt(mutation.insnToDuplicateIdx);
+
+    MInsn newInsn = oldInsn.clone();
+
+    Log.info("Duplicating " + oldInsn);
+
+    stats.incrementStat("Duplicated instruction");
+
+    mutatableCode.insertInstructionAt(newInsn, mutation.insnToDuplicateIdx);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionSwapper.java b/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionSwapper.java
new file mode 100644
index 0000000..17ea939
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/InstructionSwapper.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+
+import java.util.List;
+import java.util.Random;
+
+public class InstructionSwapper extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int swapInsnIdx;
+    public int swapWithInsnIdx;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(swapInsnIdx).append(" ");
+      builder.append(swapWithInsnIdx);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      swapInsnIdx = Integer.parseInt(elements[2]);
+      swapWithInsnIdx = Integer.parseInt(elements[3]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public InstructionSwapper() { }
+
+  public InstructionSwapper(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 80;
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    if (mutatableCode.getInstructionCount() == 1) {
+      // Cannot swap one instruction.
+      Log.debug("Cannot swap insns in a method with only one.");
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    int swapInsnIdx = 0;
+    int swapWithInsnIdx = 0;
+
+    boolean foundFirstInsn = false;
+    boolean foundSecondInsn = false;
+
+    while (!foundFirstInsn || !foundSecondInsn) {
+      // Look for the first insn.
+      while (!foundFirstInsn) {
+        swapInsnIdx = rng.nextInt(mutatableCode.getInstructionCount());
+        MInsn toBeSwapped = mutatableCode.getInstructionAt(swapInsnIdx);
+        foundFirstInsn = true;
+        if (toBeSwapped.insn.justRaw) {
+          foundFirstInsn = false;
+        }
+      }
+
+      // Look for the second insn.
+      int secondInsnAttempts = 0;
+      while (!foundSecondInsn) {
+        int delta = rng.nextInt(5) - 1;
+
+        if (delta == 0) {
+          continue;
+        }
+
+        swapWithInsnIdx = swapInsnIdx + delta;
+        foundSecondInsn = true;
+
+        // Check insn is in valid range.
+        if (swapWithInsnIdx < 0) {
+          foundSecondInsn = false;
+        } else if (swapWithInsnIdx >= mutatableCode.getInstructionCount()) {
+          foundSecondInsn = false;
+        }
+
+        // Finally, check if we're swapping with a raw insn.
+        if (foundSecondInsn) {
+          if (mutatableCode.getInstructionAt(swapWithInsnIdx).insn.justRaw) {
+            foundSecondInsn = false;
+          }
+        }
+
+        // If we've checked 10 times for an insn to swap with,
+        // and still found nothing, then try a new first insn.
+        if (!foundSecondInsn) {
+          secondInsnAttempts++;
+          if (secondInsnAttempts == 10) {
+            foundFirstInsn = false;
+            break;
+          }
+        }
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.swapInsnIdx = swapInsnIdx;
+    mutation.swapWithInsnIdx = swapWithInsnIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    MInsn toBeSwapped = mutatableCode.getInstructionAt(mutation.swapInsnIdx);
+    MInsn swappedWith = mutatableCode.getInstructionAt(mutation.swapWithInsnIdx);
+
+    Log.info("Swapping " + toBeSwapped + " with " + swappedWith);
+
+    stats.incrementStat("Swapped two instructions");
+
+    mutatableCode.swapInstructionsByIndex(mutation.swapInsnIdx, mutation.swapWithInsnIdx);
+
+    Log.info("Now " + swappedWith + " is swapped with " + toBeSwapped);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/NewMethodCaller.java b/tools/dexfuzz/src/dexfuzz/program/mutators/NewMethodCaller.java
new file mode 100644
index 0000000..88a2f9a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/NewMethodCaller.java
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Instruction.InvokeFormatInfo;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.List;
+import java.util.Random;
+
+public class NewMethodCaller extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public enum InvokeType {
+      VIRTUAL,
+      DIRECT,
+      SUPER,
+      STATIC,
+      INTERFACE
+    }
+
+    public int insertionIdx;
+    public InvokeType invokeType;
+    public String className;
+    public String methodName;
+    public String signature;
+    public int numArgs;
+    public int[] args;
+
+    @Override
+    public String getString() {
+      StringBuilder argsString = new StringBuilder();
+      for (int i = 0; i < numArgs; i++) {
+        argsString.append(args[i]);
+        if (i < (numArgs - 1)) {
+          argsString.append(" ");
+        }
+      }
+      String result = String.format("%d %d %s %s %s %d %s",
+          insertionIdx,
+          invokeType.ordinal(),
+          className,
+          methodName,
+          signature,
+          numArgs,
+          argsString);
+      return result;
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      insertionIdx = Integer.parseInt(elements[2]);
+      invokeType = InvokeType.values()[Integer.parseInt(elements[3])];
+      className = elements[4];
+      methodName = elements[5];
+      signature = elements[6];
+      numArgs = Integer.parseInt(elements[7]);
+      args = new int[numArgs];
+      for (int i = 0; i < numArgs; i++) {
+        args[i] = Integer.parseInt(elements[8 + i]);
+      }
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public NewMethodCaller() { }
+
+  public NewMethodCaller(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 10;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    // Find the insertion point.
+    int insertionIdx = 0;
+    boolean foundInsn = false;
+
+    while (!foundInsn) {
+      insertionIdx = rng.nextInt(mutatableCode.getInstructionCount());
+      MInsn insertionPoint =
+          mutatableCode.getInstructionAt(insertionIdx);
+      foundInsn = true;
+
+      // Don't want to insert instructions where there are raw instructions for now.
+      if (insertionPoint.insn.justRaw) {
+        foundInsn = false;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.insertionIdx = insertionIdx;
+
+    // TODO: Right now this mutator can only insert calls to System.gc() Add more!
+
+    mutation.invokeType = AssociatedMutation.InvokeType.STATIC;
+    mutation.className = "Ljava/lang/System;";
+    mutation.methodName = "gc";
+    mutation.signature = "()V";
+    mutation.numArgs = 0;
+
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    MInsn newInsn = new MInsn();
+    newInsn.insn = new Instruction();
+
+    switch (mutation.invokeType) {
+      case VIRTUAL:
+        newInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_VIRTUAL);
+        break;
+      case DIRECT:
+        newInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_DIRECT);
+        break;
+      case SUPER:
+        newInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_SUPER);
+        break;
+      case STATIC:
+        newInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_STATIC);
+        break;
+      case INTERFACE:
+        newInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_INTERFACE);
+        break;
+      default:
+    }
+
+    // TODO: Handle more than just static invokes.
+
+    int methodIdx = mutatableCode.program.getNewItemCreator()
+        .findOrCreateMethodId(mutation.className,
+            mutation.methodName, mutation.signature);
+
+    newInsn.insn.vregB = methodIdx;
+    newInsn.insn.invokeFormatInfo = new InvokeFormatInfo();
+
+    // TODO: More field population, when we call methods that take arguments.
+
+    MInsn insertionPoint =
+        mutatableCode.getInstructionAt(mutation.insertionIdx);
+
+    Log.info(String.format("Called new method %s %s %s, inserting at %s",
+        mutation.className, mutation.methodName, mutation.signature, insertionPoint));
+
+    stats.incrementStat("Called new method");
+
+    mutatableCode.insertInstructionAt(newInsn, mutation.insertionIdx);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/NonsenseStringPrinter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/NonsenseStringPrinter.java
new file mode 100644
index 0000000..b4c9d7b
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/NonsenseStringPrinter.java
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.List;
+import java.util.Random;
+
+public class NonsenseStringPrinter extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int insertionIdx;
+    public String nonsenseString;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(insertionIdx).append(" ");
+      builder.append(nonsenseString);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      insertionIdx = Integer.parseInt(elements[2]);
+      nonsenseString = elements[3];
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public NonsenseStringPrinter() { }
+
+  public NonsenseStringPrinter(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 10;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    // Find the insertion point
+    int insertionIdx = 0;
+    boolean foundInsn = false;
+
+    while (!foundInsn) {
+      insertionIdx = rng.nextInt(mutatableCode.getInstructionCount());
+      MInsn insertionPoint =
+          mutatableCode.getInstructionAt(insertionIdx);
+      foundInsn = true;
+
+      // Don't want to insert instructions where there are raw instructions for now.
+      if (insertionPoint.insn.justRaw) {
+        foundInsn = false;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.insertionIdx = insertionIdx;
+    mutation.nonsenseString = getRandomString();
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    int outFieldIdx = mutatableCode.program.getNewItemCreator().findOrCreateFieldId(
+        "Ljava/lang/System;",
+        "Ljava/io/PrintStream;",
+        "out");
+    int printMethodIdx = mutatableCode.program.getNewItemCreator().findOrCreateMethodId(
+        "Ljava/io/PrintStream;",
+        "print",
+        "(Ljava/lang/String;)V");
+    int nonsenseStringIdx = mutatableCode.program.getNewItemCreator().findOrCreateString(
+        mutation.nonsenseString);
+
+    MInsn insertionPoint = mutatableCode.getInstructionAt(mutation.insertionIdx);
+
+    mutatableCode.allocateTemporaryVRegs(2);
+
+    int streamRegister = mutatableCode.getTemporaryVReg(0);
+    int stringRegister = mutatableCode.getTemporaryVReg(1);
+
+    // Load into string and stream into the temporary registers.
+    // then call print(stream, string)
+    MInsn constStringInsn = new MInsn();
+    constStringInsn.insn = new Instruction();
+    constStringInsn.insn.info = Instruction.getOpcodeInfo(Opcode.CONST_STRING);
+    constStringInsn.insn.vregB = nonsenseStringIdx;
+    constStringInsn.insn.vregA = stringRegister;
+
+    MInsn streamLoadInsn = new MInsn();
+    streamLoadInsn.insn = new Instruction();
+    streamLoadInsn.insn.info = Instruction.getOpcodeInfo(Opcode.SGET_OBJECT);
+    streamLoadInsn.insn.vregB = outFieldIdx;
+    streamLoadInsn.insn.vregA = streamRegister;
+
+    MInsn invokeInsn = new MInsn();
+    invokeInsn.insn = new Instruction();
+    invokeInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_VIRTUAL_RANGE);
+    invokeInsn.insn.vregA = 2;
+    invokeInsn.insn.vregB = printMethodIdx;
+    invokeInsn.insn.vregC = streamRegister;
+
+    Log.info(String.format("Printing nonsense string '%s', inserting at %s",
+        mutation.nonsenseString, insertionPoint));
+
+    stats.incrementStat("Printed nonsense string");
+
+    mutatableCode.insertInstructionAt(invokeInsn, mutation.insertionIdx);
+    mutatableCode.insertInstructionAt(streamLoadInsn, mutation.insertionIdx);
+    mutatableCode.insertInstructionAt(constStringInsn, mutation.insertionIdx);
+
+    mutatableCode.finishedUsingTemporaryVRegs();
+  }
+
+  private String getRandomString() {
+    int size = rng.nextInt(10);
+    int start = (int) 'A';
+    int end = (int) 'Z';
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < size; i++) {
+      builder.append((char) (rng.nextInt((end + 1) - start) + start));
+    }
+    return builder.toString();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/PoolIndexChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/PoolIndexChanger.java
new file mode 100644
index 0000000..cae5dc1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/PoolIndexChanger.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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.formats.ContainsPoolIndex;
+import dexfuzz.rawdex.formats.ContainsPoolIndex.PoolIndexKind;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class PoolIndexChanger extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int poolIndexInsnIdx;
+    public int newPoolIndex;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(poolIndexInsnIdx).append(" ");
+      builder.append(newPoolIndex);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      poolIndexInsnIdx = Integer.parseInt(elements[2]);
+      newPoolIndex = Integer.parseInt(elements[3]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public PoolIndexChanger() { }
+
+  public PoolIndexChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 30;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> poolIndexInsns = null;
+
+  private void generateCachedPoolIndexInsns(MutatableCode mutatableCode) {
+    if (poolIndexInsns != null) {
+      return;
+    }
+
+    poolIndexInsns = new ArrayList<MInsn>();
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.info.format instanceof ContainsPoolIndex) {
+        poolIndexInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    // Remember what kinds of pool indices we see.
+    List<PoolIndexKind> seenKinds = new ArrayList<PoolIndexKind>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.info.format instanceof ContainsPoolIndex) {
+
+        ContainsPoolIndex containsPoolIndex =
+            (ContainsPoolIndex)mInsn.insn.info.format;
+
+        PoolIndexKind newPoolIndexKind =
+            containsPoolIndex.getPoolIndexKind(mInsn.insn.info);
+
+        seenKinds.add(newPoolIndexKind);
+      }
+    }
+
+    // Now check that there exists a kind such that the max pool index for
+    // the kind is greater than 1 (i.e., something can be changed)
+    if (!seenKinds.isEmpty()) {
+
+      for (PoolIndexKind kind : seenKinds) {
+        int numPoolIndices = mutatableCode.program.getTotalPoolIndicesByKind(kind);
+        if (numPoolIndices > 1) {
+          return true;
+        }
+      }
+
+      Log.debug("Method does not contain any insns that index into a const pool size > 1");
+      return false;
+    }
+
+    Log.debug("Method contains no instructions that index into the constant pool.");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedPoolIndexInsns(mutatableCode);
+
+    int poolIndexInsnIdx = 0;
+    boolean found = false;
+
+    int oldPoolIndex = 0;
+    int newPoolIndex = 0;
+    int maxPoolIndex = 0;
+
+    // Pick a random instruction.
+    while (!found) {
+      poolIndexInsnIdx = rng.nextInt(poolIndexInsns.size());
+      MInsn poolIndexInsn = poolIndexInsns.get(poolIndexInsnIdx);
+
+      found = true;
+
+      ContainsPoolIndex containsPoolIndex =
+          (ContainsPoolIndex)poolIndexInsn.insn.info.format;
+
+      // Get the pool index.
+      oldPoolIndex = containsPoolIndex.getPoolIndex(poolIndexInsn.insn);
+      newPoolIndex = oldPoolIndex;
+
+      // Get the largest pool index available for the provided kind of pool index.
+      PoolIndexKind poolIndexKind =
+          containsPoolIndex.getPoolIndexKind(poolIndexInsn.insn.info);
+      maxPoolIndex = mutatableCode.program.getTotalPoolIndicesByKind(poolIndexKind);
+
+      if (maxPoolIndex <= 1) {
+        found = false;
+      }
+    }
+
+    // Get a new pool index.
+    while (newPoolIndex == oldPoolIndex) {
+      newPoolIndex = rng.nextInt(maxPoolIndex);
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.poolIndexInsnIdx = poolIndexInsnIdx;
+    mutation.newPoolIndex = newPoolIndex;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedPoolIndexInsns(mutatableCode);
+
+    MInsn poolIndexInsn = poolIndexInsns.get(mutation.poolIndexInsnIdx);
+
+    ContainsPoolIndex containsPoolIndex =
+        (ContainsPoolIndex) poolIndexInsn.insn.info.format;
+
+    int oldPoolIndex = containsPoolIndex.getPoolIndex(poolIndexInsn.insn);
+
+    Log.info("Changed pool index " + oldPoolIndex + " to " + mutation.newPoolIndex
+        + " in " + poolIndexInsn);
+
+    stats.incrementStat("Changed constant pool index");
+
+    // Set the new pool index.
+    containsPoolIndex.setPoolIndex(poolIndexInsn.insn, mutation.newPoolIndex);
+
+    // Clear cache.
+    poolIndexInsns = null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/RandomInstructionGenerator.java b/tools/dexfuzz/src/dexfuzz/program/mutators/RandomInstructionGenerator.java
new file mode 100644
index 0000000..ff43c7c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/RandomInstructionGenerator.java
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MBranchInsn;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.OpcodeInfo;
+import dexfuzz.rawdex.formats.AbstractFormat;
+import dexfuzz.rawdex.formats.ContainsConst;
+import dexfuzz.rawdex.formats.ContainsPoolIndex;
+import dexfuzz.rawdex.formats.ContainsPoolIndex.PoolIndexKind;
+import dexfuzz.rawdex.formats.ContainsVRegs;
+
+import java.util.List;
+import java.util.Random;
+
+public class RandomInstructionGenerator extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int insertionIdx;
+    public int newOpcode;
+    public boolean hasConst;
+    public long constValue;
+    public boolean hasPoolIndex;
+    public int poolIndexValue;
+    public boolean hasVregs;
+    public int vregCount;
+    public int vregA;
+    public int vregB;
+    public int vregC;
+    public int branchTargetIdx;
+
+    @Override
+    public String getString() {
+      String result = String.format("%d %d %s %d %s %d %s %d %d %d %d %d",
+          insertionIdx,
+          newOpcode,
+          (hasConst ? "T" : "F"),
+          constValue,
+          (hasPoolIndex ? "T" : "F"),
+          poolIndexValue,
+          (hasVregs ? "T" : "F"),
+          vregCount,
+          vregA,
+          vregB,
+          vregC,
+          branchTargetIdx
+          );
+      return result;
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      insertionIdx = Integer.parseInt(elements[2]);
+      newOpcode = Integer.parseInt(elements[3]);
+      hasConst = (elements[4].equals("T"));
+      constValue = Long.parseLong(elements[5]);
+      hasPoolIndex = (elements[6].equals("T"));
+      poolIndexValue = Integer.parseInt(elements[7]);
+      hasVregs = (elements[8].equals("T"));
+      vregCount = Integer.parseInt(elements[9]);
+      vregA = Integer.parseInt(elements[10]);
+      vregB = Integer.parseInt(elements[11]);
+      vregC = Integer.parseInt(elements[12]);
+      branchTargetIdx = Integer.parseInt(elements[13]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public RandomInstructionGenerator() { }
+
+  public RandomInstructionGenerator(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 30;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    // Find the insertion point.
+    int insertionIdx = 0;
+    boolean foundInsn = false;
+
+    while (!foundInsn) {
+      insertionIdx = rng.nextInt(mutatableCode.getInstructionCount());
+      MInsn insertionPoint =
+          mutatableCode.getInstructionAt(insertionIdx);
+      foundInsn = true;
+
+      // Don't want to insert instructions where there are raw instructions for now.
+      if (insertionPoint.insn.justRaw) {
+        foundInsn = false;
+      }
+    }
+
+    Opcode newOpcode = null;
+    int opcodeCount = Opcode.values().length;
+    boolean foundOpcode = false;
+
+    while (!foundOpcode) {
+      newOpcode = Opcode.values()[rng.nextInt(opcodeCount)];
+      foundOpcode = true;
+      if (Opcode.isBetween(newOpcode, Opcode.FILLED_NEW_ARRAY, Opcode.FILL_ARRAY_DATA)
+          || Opcode.isBetween(newOpcode, Opcode.PACKED_SWITCH, Opcode.SPARSE_SWITCH)
+          || Opcode.isBetween(newOpcode, Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_INTERFACE)
+          || Opcode.isBetween(newOpcode,
+              Opcode.INVOKE_VIRTUAL_RANGE, Opcode.INVOKE_INTERFACE_RANGE)
+              // Can never accept these instructions at compile time.
+              || Opcode.isBetween(newOpcode, Opcode.IGET_QUICK, Opcode.IPUT_SHORT_QUICK)
+              // Unused opcodes...
+              || Opcode.isBetween(newOpcode, Opcode.UNUSED_3E, Opcode.UNUSED_43)
+              || Opcode.isBetween(newOpcode, Opcode.UNUSED_79, Opcode.UNUSED_7A)
+              || Opcode.isBetween(newOpcode, Opcode.UNUSED_EF, Opcode.UNUSED_FF)) {
+        foundOpcode = false;
+      }
+    }
+
+    OpcodeInfo newOpcodeInfo = Instruction.getOpcodeInfo(newOpcode);
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.insertionIdx = insertionIdx;
+    mutation.newOpcode = newOpcodeInfo.value;
+
+    AbstractFormat fmt = newOpcodeInfo.format;
+
+    if (fmt instanceof ContainsConst) {
+      mutation.hasConst = true;
+      mutation.constValue = rng.nextLong() % ((ContainsConst)fmt).getConstRange();
+    }
+    if (fmt instanceof ContainsPoolIndex) {
+      mutation.hasPoolIndex = true;
+      ContainsPoolIndex containsPoolIndex = (ContainsPoolIndex) fmt;
+      PoolIndexKind poolIndexKind = containsPoolIndex.getPoolIndexKind(newOpcodeInfo);
+      int maxPoolIndex = mutatableCode.program.getTotalPoolIndicesByKind(poolIndexKind);
+      if (maxPoolIndex > 0) {
+        mutation.poolIndexValue = rng.nextInt(maxPoolIndex);
+      } else {
+        mutation.poolIndexValue = 0;
+      }
+    }
+    if (mutatableCode.registersSize == 0) {
+      mutatableCode.registersSize = 1;
+    }
+    if (fmt instanceof ContainsVRegs) {
+      mutation.hasVregs = true;
+      ContainsVRegs containsVregs = (ContainsVRegs) fmt;
+      mutation.vregCount = containsVregs.getVRegCount();
+      switch (mutation.vregCount) {
+        case 3:
+          mutation.vregC = rng.nextInt(mutatableCode.registersSize);
+          // fallthrough
+        case 2:
+          mutation.vregB = rng.nextInt(mutatableCode.registersSize);
+          // fallthrough
+        case 1:
+          mutation.vregA = rng.nextInt(mutatableCode.registersSize);
+          break;
+        default:
+          Log.errorAndQuit("Invalid number of vregs specified.");
+      }
+    }
+    // If we have some kind of branch, pick a random target.
+    if (Opcode.isBetween(newOpcode, Opcode.IF_EQ, Opcode.IF_LEZ)
+        || Opcode.isBetween(newOpcode, Opcode.GOTO, Opcode.GOTO_32)) {
+      mutation.branchTargetIdx = rng.nextInt(mutatableCode.getInstructionCount());
+    }
+
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    Opcode newOpcode = Instruction.getOpcodeInfo(mutation.newOpcode).opcode;
+
+    boolean isBranch = false;
+    if (Opcode.isBetween(newOpcode, Opcode.IF_EQ, Opcode.IF_LEZ)
+        || Opcode.isBetween(newOpcode, Opcode.GOTO, Opcode.GOTO_32)) {
+      isBranch = true;
+    }
+
+    MInsn newInsn = null;
+    if (!isBranch) {
+      newInsn = new MInsn();
+    } else {
+      newInsn = new MBranchInsn();
+    }
+    newInsn.insn = new Instruction();
+    newInsn.insn.info = Instruction.getOpcodeInfo(mutation.newOpcode);
+    AbstractFormat fmt = newInsn.insn.info.format;
+
+    if (mutation.hasConst) {
+      ContainsConst containsConst = (ContainsConst) fmt;
+      containsConst.setConst(newInsn.insn, mutation.constValue);
+    }
+    if (mutation.hasPoolIndex) {
+      ContainsPoolIndex containsPoolIndex = (ContainsPoolIndex) fmt;
+      containsPoolIndex.setPoolIndex(newInsn.insn, mutation.poolIndexValue);
+    }
+    if (mutation.hasVregs) {
+      switch (mutation.vregCount) {
+        case 3:
+          newInsn.insn.vregC = mutation.vregC;
+          // fallthrough
+        case 2:
+          newInsn.insn.vregB = mutation.vregB;
+          // fallthrough
+        case 1:
+          newInsn.insn.vregA = mutation.vregA;
+          break;
+        default:
+          Log.errorAndQuit("Invalid number of vregs specified.");
+      }
+    }
+
+    if (isBranch) {
+      // We have a branch instruction, point it at its target.
+      MBranchInsn newBranchInsn = (MBranchInsn) newInsn;
+      newBranchInsn.target = mutatableCode.getInstructionAt(mutation.branchTargetIdx);
+    }
+
+    MInsn insertionPoint =
+        mutatableCode.getInstructionAt(mutation.insertionIdx);
+
+    Log.info("Generated random instruction: " + newInsn
+        + ", inserting at " + insertionPoint);
+
+    stats.incrementStat("Generated random instruction");
+
+    mutatableCode.insertInstructionAt(newInsn, mutation.insertionIdx);
+
+    // If we've generated a monitor insn, generate the matching opposing insn.
+    if (newInsn.insn.info.opcode == Opcode.MONITOR_ENTER) {
+      MInsn exitInsn = newInsn.clone();
+      exitInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MONITOR_EXIT);
+      mutatableCode.insertInstructionAfter(exitInsn, mutation.insertionIdx);
+      Log.info("Generated matching monitor-exit: " + exitInsn);
+    } else if (newInsn.insn.info.opcode == Opcode.MONITOR_EXIT) {
+      MInsn enterInsn = newInsn.clone();
+      enterInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MONITOR_ENTER);
+      mutatableCode.insertInstructionAt(enterInsn, mutation.insertionIdx);
+      Log.info("Generated matching monitor-enter: " + enterInsn);
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/SwitchBranchShifter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/SwitchBranchShifter.java
new file mode 100644
index 0000000..6981034
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/SwitchBranchShifter.java
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MSwitchInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class SwitchBranchShifter extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int switchInsnIdx;
+    public int switchTargetIdx;
+    public int newTargetIdx;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(switchInsnIdx).append(" ");
+      builder.append(switchTargetIdx).append(" ");
+      builder.append(newTargetIdx);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      switchInsnIdx = Integer.parseInt(elements[2]);
+      switchTargetIdx = Integer.parseInt(elements[3]);
+      newTargetIdx = Integer.parseInt(elements[4]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public SwitchBranchShifter() { }
+
+  public SwitchBranchShifter(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 30;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MSwitchInsn> switchInsns;
+
+  private void generateCachedSwitchInsns(MutatableCode mutatableCode) {
+    if (switchInsns != null) {
+      return;
+    }
+
+    switchInsns = new ArrayList<MSwitchInsn>();
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MSwitchInsn) {
+        switchInsns.add((MSwitchInsn) mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn instanceof MSwitchInsn) {
+        return true;
+      }
+    }
+
+    Log.debug("Method contains no switch instructions.");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedSwitchInsns(mutatableCode);
+
+    // Pick a random switch instruction.
+    int switchInsnIdx = rng.nextInt(switchInsns.size());
+    MSwitchInsn switchInsn = switchInsns.get(switchInsnIdx);
+
+    // Pick a random one of its targets.
+    int switchTargetIdx = rng.nextInt(switchInsn.targets.size());
+
+    // Get the original target, find its index.
+    MInsn oldTargetInsn = switchInsn.targets.get(switchTargetIdx);
+    int oldTargetInsnIdx = mutatableCode.getInstructionIndex(oldTargetInsn);
+
+    int newTargetIdx = oldTargetInsnIdx;
+
+    int delta = 0;
+
+    // Keep searching for a new index.
+    while (newTargetIdx == oldTargetInsnIdx) {
+      // Vary by +/- 2 instructions.
+      delta = 0;
+      while (delta == 0) {
+        delta = (rng.nextInt(5) - 2);
+      }
+
+      newTargetIdx = oldTargetInsnIdx + delta;
+
+      // Check the new index is legal
+      if (newTargetIdx < 0) {
+        newTargetIdx = 0;
+      } else if (newTargetIdx >= mutatableCode.getInstructionCount()) {
+        newTargetIdx = mutatableCode.getInstructionCount() - 1;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.switchInsnIdx = switchInsnIdx;
+    mutation.switchTargetIdx = switchTargetIdx;
+    mutation.newTargetIdx = newTargetIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedSwitchInsns(mutatableCode);
+
+    MSwitchInsn switchInsn = switchInsns.get(mutation.switchInsnIdx);
+
+    // Get the new target.
+    MInsn newTargetInsn =
+        mutatableCode.getInstructionAt(mutation.newTargetIdx);
+
+    // Set the new target.
+    switchInsn.targets.remove(mutation.switchTargetIdx);
+    switchInsn.targets.add(mutation.switchTargetIdx, newTargetInsn);
+
+    Log.info("Shifted target #" + mutation.switchTargetIdx + " of " + switchInsn
+        + " to point to " + newTargetInsn);
+
+    stats.incrementStat("Shifted switch target");
+
+    // Clear cache.
+    switchInsns = null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java
new file mode 100644
index 0000000..1bf6463
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/TryBlockShifter.java
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MTryBlock;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+
+import java.util.List;
+import java.util.Random;
+
+public class TryBlockShifter extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int tryIdx;
+    public boolean shiftingTryBlock; // false => shifting handler
+    public boolean shiftingStart; // false => shifting end (try block only)
+    public boolean shiftingHandlerCatchall;
+    public int shiftingHandlerIdx;
+    public int newShiftedInsnIdx;
+
+    @Override
+    public String getString() {
+      String result = String.format("%d %s %s %s %d %d",
+          tryIdx,
+          (shiftingTryBlock ? "T" : "F"),
+          (shiftingStart ? "T" : "F"),
+          (shiftingHandlerCatchall ? "T" : "F"),
+          shiftingHandlerIdx,
+          newShiftedInsnIdx
+          );
+      return result;
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      tryIdx = Integer.parseInt(elements[2]);
+      shiftingTryBlock = elements[3].equals("T");
+      shiftingStart = elements[4].equals("T");
+      shiftingHandlerCatchall = elements[5].equals("T");
+      shiftingHandlerIdx = Integer.parseInt(elements[6]);
+      newShiftedInsnIdx = Integer.parseInt(elements[7]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public TryBlockShifter() { }
+
+  public TryBlockShifter(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 40;
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    if (mutatableCode.triesSize > 0) {
+      return true;
+    }
+
+    Log.debug("Method contains no tries.");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    // Pick a random try.
+    int tryIdx = rng.nextInt(mutatableCode.triesSize);
+    MTryBlock tryBlock = mutatableCode.mutatableTries.get(tryIdx);
+
+    boolean shiftingTryBlock = rng.nextBoolean();
+    boolean shiftingStart = false;
+    boolean shiftingHandlerCatchall = false;
+    int shiftingHandlerIdx = -1;
+    if (shiftingTryBlock) {
+      // We're shifting the boundaries of the try block
+      // determine if we shift the start or the end.
+      shiftingStart = rng.nextBoolean();
+    } else {
+      // We're shifting the start of a handler of the try block.
+      if (tryBlock.handlers.isEmpty()) {
+        // No handlers, so we MUST mutate the catchall
+        shiftingHandlerCatchall = true;
+      } else if (tryBlock.catchAllHandler != null) {
+        // There is a catchall handler, so potentially mutate it.
+        shiftingHandlerCatchall = rng.nextBoolean();
+      }
+      // If we're not going to shift the catchall handler, then
+      // pick an explicit handler to shift.
+      if (!shiftingHandlerCatchall) {
+        shiftingHandlerIdx = rng.nextInt(tryBlock.handlers.size());
+      }
+    }
+
+    // Get the original instruction wherever we're shifting.
+    MInsn oldInsn = null;
+    if (shiftingTryBlock && shiftingStart) {
+      oldInsn = tryBlock.startInsn;
+    } else if (shiftingTryBlock && !(shiftingStart)) {
+      oldInsn = tryBlock.endInsn;
+    } else if (!(shiftingTryBlock) && shiftingHandlerCatchall) {
+      oldInsn = tryBlock.catchAllHandler;
+    } else if (!(shiftingTryBlock) && !(shiftingHandlerCatchall)
+        && (shiftingHandlerIdx != -1)) {
+      oldInsn = tryBlock.handlers.get(shiftingHandlerIdx);
+    } else {
+      Log.errorAndQuit("Faulty logic in TryBlockShifter!");
+    }
+
+    // Find the index of this instruction.
+    int oldInsnIdx = mutatableCode.getInstructionIndex(oldInsn);
+
+    int newInsnIdx = oldInsnIdx;
+
+    int delta = 0;
+
+    // Keep searching for a new index.
+    while (newInsnIdx == oldInsnIdx) {
+      // Vary by +/- 2 instructions.
+      delta = 0;
+      while (delta == 0) {
+        delta = (rng.nextInt(5) - 2);
+      }
+
+      newInsnIdx = oldInsnIdx + delta;
+
+      // Check the new index is legal.
+      if (newInsnIdx < 0) {
+        newInsnIdx = 0;
+      } else if (newInsnIdx >= mutatableCode.getInstructionCount()) {
+        newInsnIdx = mutatableCode.getInstructionCount() - 1;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.tryIdx = tryIdx;
+    mutation.shiftingTryBlock = shiftingTryBlock;
+    mutation.shiftingStart = shiftingStart;
+    mutation.shiftingHandlerCatchall = shiftingHandlerCatchall;
+    mutation.shiftingHandlerIdx = shiftingHandlerIdx;
+    mutation.newShiftedInsnIdx = newInsnIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    MTryBlock tryBlock = mutatableCode.mutatableTries.get(mutation.tryIdx);
+
+    MInsn newInsn =
+        mutatableCode.getInstructionAt(mutation.newShiftedInsnIdx);
+
+    // Find the right mutatable instruction in try block, and point it at the new instruction.
+    if (mutation.shiftingTryBlock && mutation.shiftingStart) {
+      tryBlock.startInsn = newInsn;
+      Log.info("Shifted the start of try block #" + mutation.tryIdx
+          + " to be at " + newInsn);
+    } else if (mutation.shiftingTryBlock && !(mutation.shiftingStart)) {
+      tryBlock.endInsn = newInsn;
+      Log.info("Shifted the end of try block #" + mutation.tryIdx
+          + " to be at " + newInsn);
+    } else if (!(mutation.shiftingTryBlock) && mutation.shiftingHandlerCatchall) {
+      tryBlock.catchAllHandler = newInsn;
+      Log.info("Shifted the catch all handler of try block #" + mutation.tryIdx
+          + " to be at " + newInsn);
+    } else if (!(mutation.shiftingTryBlock) && !(mutation.shiftingHandlerCatchall)
+        && (mutation.shiftingHandlerIdx != -1)) {
+      tryBlock.handlers.set(mutation.shiftingHandlerIdx, newInsn);
+      Log.info("Shifted handler #" + mutation.shiftingHandlerIdx
+          + " of try block #" + mutation.tryIdx + " to be at " + newInsn);
+    } else {
+      Log.errorAndQuit("faulty logic in TryBlockShifter");
+    }
+
+    stats.incrementStat("Shifted boundary in a try block");
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/VRegChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/VRegChanger.java
new file mode 100644
index 0000000..d685f7d
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/VRegChanger.java
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.formats.ContainsVRegs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class VRegChanger extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int vregInsnIdx;
+    public int mutatingVreg;
+    public int newVregValue;
+
+    @Override
+    public String getString() {
+      StringBuilder builder = new StringBuilder();
+      builder.append(vregInsnIdx).append(" ");
+      builder.append(mutatingVreg).append(" ");
+      builder.append(newVregValue);
+      return builder.toString();
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      vregInsnIdx = Integer.parseInt(elements[2]);
+      mutatingVreg = Integer.parseInt(elements[3]);
+      newVregValue = Integer.parseInt(elements[4]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public VRegChanger() { }
+
+  public VRegChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 60;
+  }
+
+  // A cache that should only exist between generateMutation() and applyMutation(),
+  // or be created at the start of applyMutation(), if we're reading in mutations from
+  // a file.
+  private List<MInsn> vregInsns = null;
+
+  private void generateCachedVRegInsns(MutatableCode mutatableCode) {
+    if (vregInsns != null) {
+      return;
+    }
+
+    vregInsns = new ArrayList<MInsn>();
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.info.format instanceof ContainsVRegs) {
+        vregInsns.add(mInsn);
+      }
+    }
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    if (mutatableCode.registersSize < 2) {
+      Log.debug("Impossible to change vregs in a method with fewer than 2 registers.");
+      return false;
+    }
+
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (mInsn.insn.info.format instanceof ContainsVRegs) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    generateCachedVRegInsns(mutatableCode);
+
+    // Pick a random vreg instruction.
+    int vregInsnIdx = rng.nextInt(vregInsns.size());
+    MInsn vregInsn = vregInsns.get(vregInsnIdx);
+
+    // Get the number of VRegs this instruction uses.
+    int numVregs = ((ContainsVRegs)vregInsn.insn.info.format).getVRegCount();
+
+    // Pick which vreg to mutate.
+    int mutatingVreg = rng.nextInt(numVregs);
+
+    // Find the old index.
+    int oldVregValue = 0;
+
+    switch (mutatingVreg) {
+      case 0:
+        oldVregValue = (int) vregInsn.insn.vregA;
+        break;
+      case 1:
+        oldVregValue = (int) vregInsn.insn.vregB;
+        break;
+      case 2:
+        oldVregValue = (int) vregInsn.insn.vregC;
+        break;
+      default:
+        Log.errorAndQuit("Invalid number of vregs reported by a Format.");
+    }
+
+    // Search for a new vreg value.
+    int newVregValue = oldVregValue;
+    while (newVregValue == oldVregValue) {
+      newVregValue = rng.nextInt(mutatableCode.registersSize);
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.vregInsnIdx = vregInsnIdx;
+    mutation.mutatingVreg = mutatingVreg;
+    mutation.newVregValue = newVregValue;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    generateCachedVRegInsns(mutatableCode);
+
+    MInsn vregInsn = vregInsns.get(mutation.vregInsnIdx);
+
+    // Remember what the instruction used to look like.
+    String oldInsnString = vregInsn.toString();
+
+    int oldVregValue = 0;
+
+    String vregId = "A";
+    switch (mutation.mutatingVreg) {
+      case 0:
+        oldVregValue = (int) vregInsn.insn.vregA;
+        vregInsn.insn.vregA = (long) mutation.newVregValue;
+        break;
+      case 1:
+        oldVregValue = (int) vregInsn.insn.vregB;
+        vregInsn.insn.vregB = (long) mutation.newVregValue;
+        vregId = "B";
+        break;
+      case 2:
+        oldVregValue = (int) vregInsn.insn.vregC;
+        vregInsn.insn.vregC = (long) mutation.newVregValue;
+        vregId = "C";
+        break;
+      default:
+        Log.errorAndQuit("Invalid number of vregs specified in a VRegChanger mutation.");
+    }
+
+    Log.info("In " + oldInsnString + " changed v" + vregId + ": v" + oldVregValue
+        + " to v" + mutation.newVregValue);
+
+    stats.incrementStat("Changed a virtual register");
+
+    // Clear cache.
+    vregInsns = null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/ValuePrinter.java b/tools/dexfuzz/src/dexfuzz/program/mutators/ValuePrinter.java
new file mode 100644
index 0000000..271aca3
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/program/mutators/ValuePrinter.java
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.program.mutators;
+
+import dexfuzz.Log;
+import dexfuzz.MutationStats;
+import dexfuzz.program.MInsn;
+import dexfuzz.program.MutatableCode;
+import dexfuzz.program.Mutation;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+
+import java.util.List;
+import java.util.Random;
+
+public class ValuePrinter extends CodeMutator {
+  /**
+   * Every CodeMutator has an AssociatedMutation, representing the
+   * mutation that this CodeMutator can perform, to allow separate
+   * generateMutation() and applyMutation() phases, allowing serialization.
+   */
+  public static class AssociatedMutation extends Mutation {
+    public int printedOutputIdx;
+
+    @Override
+    public String getString() {
+      return Integer.toString(printedOutputIdx);
+    }
+
+    @Override
+    public void parseString(String[] elements) {
+      printedOutputIdx = Integer.parseInt(elements[2]);
+    }
+  }
+
+  // The following two methods are here for the benefit of MutationSerializer,
+  // so it can create a CodeMutator and get the correct associated Mutation, as it
+  // reads in mutations from a dump of mutations.
+  @Override
+  public Mutation getNewMutation() {
+    return new AssociatedMutation();
+  }
+
+  public ValuePrinter() { }
+
+  public ValuePrinter(Random rng, MutationStats stats, List<Mutation> mutations) {
+    super(rng, stats, mutations);
+    likelihood = 40;
+  }
+
+  @Override
+  protected boolean canMutate(MutatableCode mutatableCode) {
+    for (MInsn mInsn : mutatableCode.getInstructions()) {
+      if (getInstructionOutputType(mInsn) != OutputType.UNKNOWN) {
+        return true;
+      }
+    }
+
+    Log.debug("No instructions with legible output in method, skipping.");
+    return false;
+  }
+
+  @Override
+  protected Mutation generateMutation(MutatableCode mutatableCode) {
+    // Find an instruction whose output we wish to print.
+    int printedOutputIdx = 0;
+    boolean foundInsn = false;
+
+    while (!foundInsn) {
+      printedOutputIdx = rng.nextInt(mutatableCode.getInstructionCount());
+      MInsn insnOutputToPrint =
+          mutatableCode.getInstructionAt(printedOutputIdx);
+      foundInsn = true;
+
+      // Don't want to insert instructions where there are raw instructions for now.
+      if (insnOutputToPrint.insn.justRaw) {
+        foundInsn = false;
+      }
+
+      if (getInstructionOutputType(insnOutputToPrint) == OutputType.UNKNOWN) {
+        foundInsn = false;
+      }
+    }
+
+    AssociatedMutation mutation = new AssociatedMutation();
+    mutation.setup(this.getClass(), mutatableCode);
+    mutation.printedOutputIdx = printedOutputIdx;
+    return mutation;
+  }
+
+  @Override
+  protected void applyMutation(Mutation uncastMutation) {
+    // Cast the Mutation to our AssociatedMutation, so we can access its fields.
+    AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
+    MutatableCode mutatableCode = mutation.mutatableCode;
+
+    MInsn insnOutputToPrint =
+        mutatableCode.getInstructionAt(mutation.printedOutputIdx);
+
+    int outFieldIdx = mutatableCode.program.getNewItemCreator().findOrCreateFieldId(
+        "Ljava/lang/System;",
+        "Ljava/io/PrintStream;",
+        "out");
+
+    OutputType outputType = getInstructionOutputType(insnOutputToPrint);
+
+    if (outputType == OutputType.UNKNOWN) {
+      Log.errorAndQuit("Requested to print output of an instruction, whose output"
+          + " type is unknown.");
+    }
+    int printMethodIdx = mutatableCode.program.getNewItemCreator().findOrCreateMethodId(
+        "Ljava/io/PrintStream;",
+        "print",
+        outputType.getSignatureForPrintln());
+
+    boolean isWide = false;
+    boolean isRef = false;
+    if (outputType == OutputType.LONG || outputType == OutputType.DOUBLE) {
+      isWide = true;
+    }
+    if (outputType == OutputType.STRING) {
+      isRef = true;
+    }
+
+    // If we're printing a wide value, we need to allocate 3 registers!
+    if (isWide) {
+      mutatableCode.allocateTemporaryVRegs(3);
+    } else {
+      mutatableCode.allocateTemporaryVRegs(2);
+    }
+
+    int streamRegister = mutatableCode.getTemporaryVReg(0);
+    int valueRegister = mutatableCode.getTemporaryVReg(1);
+
+    // Copy the value we want to print to the 2nd temporary register
+    // Then load the out stream
+    // Then call print(out stream, value)
+
+    MInsn valueCopyInsn = new MInsn();
+    valueCopyInsn.insn = new Instruction();
+    if (isRef) {
+      valueCopyInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_OBJECT_16);
+    } else if (isWide) {
+      valueCopyInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_WIDE_16);
+    } else {
+      valueCopyInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_16);
+    }
+    valueCopyInsn.insn.vregB = insnOutputToPrint.insn.vregA;
+    valueCopyInsn.insn.vregA = valueRegister;
+
+    MInsn streamLoadInsn = new MInsn();
+    streamLoadInsn.insn = new Instruction();
+    streamLoadInsn.insn.info = Instruction.getOpcodeInfo(Opcode.SGET_OBJECT);
+    streamLoadInsn.insn.vregB = outFieldIdx;
+    streamLoadInsn.insn.vregA = streamRegister;
+
+    MInsn invokeInsn = new MInsn();
+    invokeInsn.insn = new Instruction();
+    invokeInsn.insn.info = Instruction.getOpcodeInfo(Opcode.INVOKE_VIRTUAL_RANGE);
+    if (isWide) {
+      invokeInsn.insn.vregA = 3;
+    } else {
+      invokeInsn.insn.vregA = 2;
+    }
+    invokeInsn.insn.vregB = printMethodIdx;
+    invokeInsn.insn.vregC = streamRegister;
+
+    Log.info(String.format("Printing output value of instruction %s", insnOutputToPrint));
+
+    stats.incrementStat("Printed output value");
+
+    mutatableCode.insertInstructionAfter(invokeInsn, mutation.printedOutputIdx);
+    mutatableCode.insertInstructionAfter(streamLoadInsn, mutation.printedOutputIdx);
+    mutatableCode.insertInstructionAfter(valueCopyInsn, mutation.printedOutputIdx);
+
+    mutatableCode.finishedUsingTemporaryVRegs();
+  }
+
+  private static enum OutputType {
+    STRING("(Ljava/lang/String;)V"),
+    BOOLEAN("(Z)V"),
+    BYTE("(B)V"),
+    CHAR("(C)V"),
+    SHORT("(S)V"),
+    INT("(I)V"),
+    LONG("(J)V"),
+    FLOAT("(F)V"),
+    DOUBLE("(D)V"),
+    UNKNOWN("UNKNOWN");
+
+    private String printingSignature;
+    private OutputType(String s) {
+      printingSignature = s;
+    }
+
+    public String getSignatureForPrintln() {
+      return printingSignature;
+    }
+  }
+
+  private OutputType getInstructionOutputType(MInsn mInsn) {
+    Opcode opcode = mInsn.insn.info.opcode;
+    if (opcode == Opcode.CONST_STRING || opcode == Opcode.CONST_STRING_JUMBO) {
+      return OutputType.STRING;
+    }
+    if (opcode == Opcode.IGET_BOOLEAN || opcode == Opcode.SGET_BOOLEAN) {
+      return OutputType.BOOLEAN;
+    }
+    if (opcode == Opcode.IGET_BYTE || opcode == Opcode.SGET_BYTE
+        || opcode == Opcode.INT_TO_BYTE) {
+      return OutputType.BYTE;
+    }
+    if (opcode == Opcode.IGET_CHAR || opcode == Opcode.SGET_CHAR
+        || opcode == Opcode.INT_TO_CHAR) {
+      return OutputType.CHAR;
+    }
+    if (opcode == Opcode.IGET_SHORT || opcode == Opcode.SGET_SHORT
+        || opcode == Opcode.INT_TO_SHORT) {
+      return OutputType.SHORT;
+    }
+    if (opcode == Opcode.NEG_INT || opcode == Opcode.NOT_INT
+        || opcode == Opcode.LONG_TO_INT || opcode == Opcode.FLOAT_TO_INT
+        || opcode == Opcode.DOUBLE_TO_INT
+        || Opcode.isBetween(opcode, Opcode.ADD_INT, Opcode.USHR_INT)
+        || Opcode.isBetween(opcode, Opcode.ADD_INT_2ADDR, Opcode.USHR_INT_2ADDR)
+        || Opcode.isBetween(opcode, Opcode.ADD_INT_LIT16, Opcode.USHR_INT_LIT8)) {
+      return OutputType.INT;
+    }
+    if (opcode == Opcode.NEG_LONG || opcode == Opcode.NOT_LONG
+        || opcode == Opcode.INT_TO_LONG || opcode == Opcode.FLOAT_TO_LONG
+        || opcode == Opcode.DOUBLE_TO_LONG
+        || Opcode.isBetween(opcode, Opcode.ADD_LONG, Opcode.USHR_LONG)
+        || Opcode.isBetween(opcode, Opcode.ADD_LONG_2ADDR, Opcode.USHR_LONG_2ADDR)) {
+      return OutputType.LONG;
+    }
+    if (opcode == Opcode.NEG_FLOAT
+        || opcode == Opcode.INT_TO_FLOAT || opcode == Opcode.LONG_TO_FLOAT
+        || opcode == Opcode.DOUBLE_TO_FLOAT
+        || Opcode.isBetween(opcode, Opcode.ADD_FLOAT, Opcode.REM_FLOAT)
+        || Opcode.isBetween(opcode, Opcode.ADD_FLOAT_2ADDR, Opcode.REM_FLOAT_2ADDR)) {
+      return OutputType.FLOAT;
+    }
+    if (opcode == Opcode.NEG_DOUBLE
+        || opcode == Opcode.INT_TO_DOUBLE || opcode == Opcode.LONG_TO_DOUBLE
+        || opcode == Opcode.FLOAT_TO_DOUBLE
+        || Opcode.isBetween(opcode, Opcode.ADD_DOUBLE, Opcode.REM_DOUBLE)
+        || Opcode.isBetween(opcode, Opcode.ADD_DOUBLE_2ADDR, Opcode.REM_DOUBLE_2ADDR)) {
+      return OutputType.DOUBLE;
+    }
+    return OutputType.UNKNOWN;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationElement.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationElement.java
new file mode 100644
index 0000000..6bb2f96
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationElement.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationElement implements RawDexObject {
+  public int nameIdx;
+  public EncodedValue value;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    nameIdx = file.readUleb128();
+    (value = new EncodedValue()).read(file);
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(nameIdx);
+    value.write(file);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.STRING_ID && nameIdx >= insertedIdx) {
+      nameIdx++;
+    }
+    value.incrementIndex(kind, insertedIdx);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationItem.java
new file mode 100644
index 0000000..40cf5e4
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationItem.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationItem implements RawDexObject {
+  public int visibility;
+  public EncodedAnnotation annotation;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    visibility = file.readUnsignedByte();
+    (annotation = new EncodedAnnotation()).read(file);
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeByte(visibility);
+    annotation.write(file);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    annotation.incrementIndex(kind, insertedIdx);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationOffItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationOffItem.java
new file mode 100644
index 0000000..b44cd18
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationOffItem.java
@@ -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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationOffItem implements RawDexObject {
+  public Offset annotationOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    annotationOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().tryToWriteOffset(annotationOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetItem.java
new file mode 100644
index 0000000..1e1c540
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetItem.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationSetItem implements RawDexObject {
+  public int size;
+  public AnnotationOffItem[] entries;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    size = file.readUInt();
+    entries = new AnnotationOffItem[size];
+    for (int i = 0; i < size; i++) {
+      (entries[i] = new AnnotationOffItem()).read(file);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(size);
+    for (AnnotationOffItem annotationOffItem : entries) {
+      annotationOffItem.write(file);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetRefItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetRefItem.java
new file mode 100644
index 0000000..cb543de
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetRefItem.java
@@ -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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationSetRefItem implements RawDexObject {
+  public Offset annotationsOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    annotationsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().tryToWriteOffset(annotationsOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetRefList.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetRefList.java
new file mode 100644
index 0000000..1d27053
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationSetRefList.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationSetRefList implements RawDexObject {
+  public int size;
+  public AnnotationSetRefItem[] list;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    size = file.readUInt();
+    list = new AnnotationSetRefItem[size];
+    for (int i = 0; i < size; i++) {
+      (list[i] = new AnnotationSetRefItem()).read(file);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(size);
+    for (AnnotationSetRefItem annotationSetRefItem : list) {
+      annotationSetRefItem.write(file);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationsDirectoryItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationsDirectoryItem.java
new file mode 100644
index 0000000..8285472
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/AnnotationsDirectoryItem.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class AnnotationsDirectoryItem implements RawDexObject {
+  public Offset classAnnotationsOff;
+  public int fieldsSize;
+  public int annotatedMethodsSize;
+  public int annotatedParametersSize;
+  public FieldAnnotation[] fieldAnnotations;
+  public MethodAnnotation[] methodAnnotations;
+  public ParameterAnnotation[] parameterAnnotations;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    classAnnotationsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    fieldsSize = file.readUInt();
+    annotatedMethodsSize = file.readUInt();
+    annotatedParametersSize = file.readUInt();
+    if (fieldsSize != 0) {
+      fieldAnnotations = new FieldAnnotation[fieldsSize];
+      for (int i = 0; i < fieldsSize; i++) {
+        (fieldAnnotations[i] = new FieldAnnotation()).read(file);
+      }
+    }
+    if (annotatedMethodsSize != 0) {
+      methodAnnotations = new MethodAnnotation[annotatedMethodsSize];
+      for (int i = 0; i < annotatedMethodsSize; i++) {
+        (methodAnnotations[i] = new MethodAnnotation()).read(file);
+      }
+    }
+    if (annotatedParametersSize != 0) {
+      parameterAnnotations = new ParameterAnnotation[annotatedParametersSize];
+      for (int i = 0; i < annotatedParametersSize; i++) {
+        (parameterAnnotations[i] = new ParameterAnnotation()).read(file);
+      }
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.getOffsetTracker().tryToWriteOffset(classAnnotationsOff, file, false /* ULEB128 */);
+    file.writeUInt(fieldsSize);
+    file.writeUInt(annotatedMethodsSize);
+    file.writeUInt(annotatedParametersSize);
+    if (fieldAnnotations != null) {
+      for (FieldAnnotation fieldAnnotation : fieldAnnotations) {
+        fieldAnnotation.write(file);
+      }
+    }
+    if (methodAnnotations != null) {
+      for (MethodAnnotation methodAnnotation : methodAnnotations) {
+        methodAnnotation.write(file);
+      }
+    }
+    if (parameterAnnotations != null) {
+      for (ParameterAnnotation parameterAnnotation : parameterAnnotations) {
+        parameterAnnotation.write(file);
+      }
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (fieldAnnotations != null) {
+      for (FieldAnnotation fieldAnnotation : fieldAnnotations) {
+        fieldAnnotation.incrementIndex(kind, insertedIdx);
+      }
+    }
+    if (methodAnnotations != null) {
+      for (MethodAnnotation methodAnnotation : methodAnnotations) {
+        methodAnnotation.incrementIndex(kind, insertedIdx);
+      }
+    }
+    if (parameterAnnotations != null) {
+      for (ParameterAnnotation parameterAnnotation : parameterAnnotations) {
+        parameterAnnotation.incrementIndex(kind, insertedIdx);
+      }
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/ClassDataItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/ClassDataItem.java
new file mode 100644
index 0000000..79564bc
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/ClassDataItem.java
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class ClassDataItem implements RawDexObject {
+  public int staticFieldsSize;
+  public int instanceFieldsSize;
+  public int directMethodsSize;
+  public int virtualMethodsSize;
+
+  public EncodedField[] staticFields;
+  public EncodedField[] instanceFields;
+  public EncodedMethod[] directMethods;
+  public EncodedMethod[] virtualMethods;
+
+  public static class MetaInfo {
+    public ClassDefItem classDefItem;
+  }
+
+  public MetaInfo meta = new MetaInfo();
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    staticFieldsSize = file.readUleb128();
+    instanceFieldsSize = file.readUleb128();
+    directMethodsSize = file.readUleb128();
+    virtualMethodsSize = file.readUleb128();
+
+    staticFields = new EncodedField[staticFieldsSize];
+    for (int i = 0; i < staticFieldsSize; i++) {
+      (staticFields[i] = new EncodedField()).read(file);
+    }
+    instanceFields = new EncodedField[instanceFieldsSize];
+    for (int i = 0; i < instanceFieldsSize; i++) {
+      (instanceFields[i] = new EncodedField()).read(file);
+    }
+    directMethods = new EncodedMethod[directMethodsSize];
+    for (int i = 0; i < directMethodsSize; i++) {
+      (directMethods[i] = new EncodedMethod()).read(file);
+    }
+    virtualMethods = new EncodedMethod[virtualMethodsSize];
+    for (int i = 0; i < virtualMethodsSize; i++) {
+      (virtualMethods[i] = new EncodedMethod()).read(file);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUleb128(staticFieldsSize);
+    file.writeUleb128(instanceFieldsSize);
+    file.writeUleb128(directMethodsSize);
+    file.writeUleb128(virtualMethodsSize);
+    for (int i = 0; i < staticFieldsSize; i++) {
+      staticFields[i].write(file);
+    }
+    for (int i = 0; i < instanceFieldsSize; i++) {
+      instanceFields[i].write(file);
+    }
+    for (int i = 0; i < directMethodsSize; i++) {
+      directMethods[i].write(file);
+    }
+    for (int i = 0; i < virtualMethodsSize; i++) {
+      virtualMethods[i].write(file);
+    }
+  }
+
+  private void incrementEncodedFields(int insertedIdx, EncodedField[] fields) {
+    int fieldIdx = 0;
+    for (EncodedField field : fields) {
+      fieldIdx = field.fieldIdxDiff;
+      if (fieldIdx >= insertedIdx) {
+        field.fieldIdxDiff++;
+        // Only need to increment one, as all the others are diffed from the previous.
+        break;
+      }
+    }
+  }
+
+  private void incrementEncodedMethods(int insertedIdx, EncodedMethod[] methods) {
+    int methodIdx = 0;
+    for (EncodedMethod method : methods) {
+      methodIdx = method.methodIdxDiff;
+      if (methodIdx >= insertedIdx) {
+        method.methodIdxDiff++;
+        // Only need to increment one, as all the others are diffed from the previous.
+        break;
+      }
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.FIELD_ID) {
+      incrementEncodedFields(insertedIdx, staticFields);
+      incrementEncodedFields(insertedIdx, instanceFields);
+    }
+    if (kind == IndexUpdateKind.METHOD_ID) {
+      incrementEncodedMethods(insertedIdx, directMethods);
+      incrementEncodedMethods(insertedIdx, virtualMethods);
+    }
+  }
+
+  /**
+   * For a given field index, search this ClassDataItem for a definition of this field.
+   * @return null if the field isn't in this ClassDataItem.
+   */
+  public EncodedField getEncodedFieldWithIndex(int fieldIdx) {
+    int searchFieldIdx = 0;
+    for (EncodedField field : instanceFields) {
+      searchFieldIdx += field.fieldIdxDiff;
+      if (searchFieldIdx == fieldIdx) {
+        return field;
+      }
+    }
+    searchFieldIdx = 0;
+    for (EncodedField field : staticFields) {
+      searchFieldIdx += field.fieldIdxDiff;
+      if (searchFieldIdx == fieldIdx) {
+        return field;
+      }
+    }
+    return null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/ClassDefItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/ClassDefItem.java
new file mode 100644
index 0000000..5e68d24
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/ClassDefItem.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class ClassDefItem implements RawDexObject {
+  public static int data_size = 0x20;
+
+  public int classIdx;
+  public int accessFlags;
+  public int superclassIdx;
+  public Offset interfacesOff;
+  public int sourceFileIdx;
+  public Offset annotationsOff;
+  public Offset classDataOff;
+  public Offset staticValuesOff;
+
+  public static class MetaInfo {
+    public ClassDataItem classDataItem;
+  }
+
+  public MetaInfo meta = new MetaInfo();
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    classIdx = file.readUInt();
+    accessFlags = file.readUInt();
+    superclassIdx = file.readUInt();
+    interfacesOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    sourceFileIdx = file.readUInt();
+    annotationsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    classDataOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    staticValuesOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(classIdx);
+    file.writeUInt(accessFlags);
+    file.writeUInt(superclassIdx);
+    file.getOffsetTracker().tryToWriteOffset(interfacesOff, file, false /* ULEB128 */);
+    file.writeUInt(sourceFileIdx);
+    file.getOffsetTracker().tryToWriteOffset(annotationsOff, file, false /* ULEB128 */);
+    file.getOffsetTracker().tryToWriteOffset(classDataOff, file, false /* ULEB128 */);
+    file.getOffsetTracker().tryToWriteOffset(staticValuesOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && classIdx >= insertedIdx) {
+      classIdx++;
+    }
+    if (kind == IndexUpdateKind.TYPE_ID && superclassIdx >= insertedIdx) {
+      superclassIdx++;
+    }
+    if (kind == IndexUpdateKind.STRING_ID && sourceFileIdx >= insertedIdx) {
+      sourceFileIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/CodeItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/CodeItem.java
new file mode 100644
index 0000000..af3c377
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/CodeItem.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+import dexfuzz.program.MutatableCode;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+public class CodeItem implements RawDexObject {
+  public short registersSize;
+  public short insSize;
+  public short outsSize;
+  public short triesSize;
+  public int debugInfoOff; // NB: this is a special case
+  public int insnsSize;
+  public List<Instruction> insns;
+  public TryItem[] tries;
+  public EncodedCatchHandlerList handlers;
+
+  private MutatableCode mutatableCode;
+
+  public static class MethodMetaInfo {
+    public String methodName;
+    public boolean isStatic;
+    public String shorty;
+  }
+
+  public MethodMetaInfo meta = new MethodMetaInfo();
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    registersSize = file.readUShort();
+    insSize = file.readUShort();
+    outsSize = file.readUShort();
+    triesSize = file.readUShort();
+    debugInfoOff = file.readUInt();
+    insnsSize = file.readUInt();
+    populateInstructionList(file);
+    if (triesSize > 0) {
+      if ((insnsSize % 2) != 0) {
+        // Consume padding.
+        file.readUShort();
+      }
+      tries = new TryItem[triesSize];
+      for (int i = 0; i < triesSize; i++) {
+        (tries[i] = new TryItem()).read(file);
+      }
+      (handlers = new EncodedCatchHandlerList()).read(file);
+    }
+  }
+
+  private void populateInstructionList(DexRandomAccessFile file) throws IOException {
+    insns = new LinkedList<Instruction>();
+    long insnsOffset = file.getFilePointer();
+    if (insnsOffset != 0) {
+      long finger = insnsOffset;
+      long insnsEnd = insnsOffset + (2 * insnsSize);
+
+      while (finger < insnsEnd) {
+        file.seek(finger);
+        Instruction newInsn = new Instruction();
+        newInsn.read(file);
+        insns.add(newInsn);
+        finger += (2 * newInsn.getSize());
+      }
+
+      file.seek(finger);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUShort(registersSize);
+    file.writeUShort(insSize);
+    file.writeUShort(outsSize);
+    file.writeUShort(triesSize);
+    // We do not support retaining debug info currently.
+    file.writeUInt(0 /*debug_info_off*/);
+    file.writeUInt(insnsSize);
+    for (Instruction insn : insns) {
+      insn.write(file);
+    }
+    if (triesSize > 0) {
+      if ((insnsSize % 2) != 0) {
+        // produce padding
+        file.writeUShort((short) 0);
+      }
+      for (TryItem tryItem : tries) {
+        tryItem.write(file);
+      }
+      handlers.write(file);
+    }
+  }
+
+  /**
+   * CodeTranslator should call this to notify a CodeItem about its
+   * mutatable code, so it can always get the "latest" view of its
+   * instructions.
+   */
+  public void registerMutatableCode(MutatableCode mutatableCode) {
+    this.mutatableCode = mutatableCode;
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && triesSize > 0) {
+      // EncodedCatchHandlerList (well, the EncodedTypeAddrPairs it owns)
+      // are only interested in TYPE_IDs.
+      handlers.incrementIndex(kind, insertedIdx);
+    }
+
+    if (kind == IndexUpdateKind.PROTO_ID) {
+      // The only kind we can't encounter in an instruction.
+      return;
+    }
+
+    List<Instruction> insnsToIncrement = insns;
+
+    // If we have an associated MutatableCode, then it may have created some new insns
+    // that we won't know about yet, during the mutation phase.
+    //
+    // Ask for the latest view of the insns.
+    if (mutatableCode != null) {
+      insnsToIncrement = mutatableCode.requestLatestInstructions();
+    }
+
+    for (Instruction insn : insnsToIncrement) {
+      Opcode opcode = insn.info.opcode;
+      switch (kind) {
+        case STRING_ID:
+          if (opcode == Opcode.CONST_STRING || opcode == Opcode.CONST_STRING_JUMBO) {
+            // STRING@BBBB
+            if (insn.vregB >= insertedIdx) {
+              insn.vregB++;
+            }
+          }
+          break;
+        case TYPE_ID:
+          if (opcode == Opcode.CONST_CLASS
+              || opcode == Opcode.CHECK_CAST
+              || opcode == Opcode.NEW_INSTANCE
+              || opcode == Opcode.FILLED_NEW_ARRAY
+              || opcode == Opcode.FILLED_NEW_ARRAY_RANGE) {
+            // TYPE@BBBB
+            if (insn.vregB >= insertedIdx) {
+              insn.vregB++;
+            }
+          } else if (opcode == Opcode.INSTANCE_OF || opcode == Opcode.NEW_ARRAY) {
+            // TYPE@CCCC
+            if (insn.vregC >= insertedIdx) {
+              insn.vregC++;
+            }
+          }
+          break;
+        case FIELD_ID:
+          if (Opcode.isBetween(opcode, Opcode.SGET, Opcode.SPUT_SHORT)) {
+            // FIELD@BBBB
+            if (insn.vregB >= insertedIdx) {
+              insn.vregB++;
+            }
+          } else if (Opcode.isBetween(opcode, Opcode.IGET, Opcode.IPUT_SHORT)) {
+            // FIELD@CCCC
+            if (insn.vregC >= insertedIdx) {
+              insn.vregC++;
+            }
+          }
+          break;
+        case METHOD_ID:
+          if (Opcode.isBetween(opcode, Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_INTERFACE)
+              || Opcode.isBetween(opcode,
+                  Opcode.INVOKE_VIRTUAL_RANGE, Opcode.INVOKE_INTERFACE_RANGE)) {
+            // METHOD@BBBB
+            if (insn.vregB >= insertedIdx) {
+              insn.vregB++;
+            }
+          }
+          break;
+        default:
+          Log.errorAndQuit("Unexpected IndexUpdateKind requested "
+              + "in Instruction.incrementIndex()");
+      }
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java
new file mode 100644
index 0000000..922ee58
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/DebugInfoItem.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+// Right now we are not parsing debug_info_item, just take the raw size
+public class DebugInfoItem implements RawDexObject {
+  private int size;
+  private byte[] data;
+
+  public DebugInfoItem(int size) {
+    this.size = size;
+  }
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    data = new byte[size];
+    file.read(data);
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.write(data);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/DexRandomAccessFile.java b/tools/dexfuzz/src/dexfuzz/rawdex/DexRandomAccessFile.java
new file mode 100644
index 0000000..ec75585
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/DexRandomAccessFile.java
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * An extension to RandomAccessFile that allows reading/writing
+ * DEX files in little-endian form, the variable-length LEB format
+ * and also provides word-alignment functions.
+ */
+public class DexRandomAccessFile extends RandomAccessFile {
+  private OffsetTracker offsetTracker;
+
+  public OffsetTracker getOffsetTracker() {
+    return offsetTracker;
+  }
+
+  public void setOffsetTracker(OffsetTracker offsetTracker) {
+    this.offsetTracker = offsetTracker;
+  }
+
+  /**
+   * Constructor, passes straight on to RandomAccessFile currently.
+   * @param filename The file to open.
+   * @param mode Strings "r" or "rw" work best.
+   */
+  public DexRandomAccessFile(String filename, String mode)
+      throws FileNotFoundException {
+    super(filename, mode);
+  }
+
+  /**
+   * @return A 16-bit number, read from the file as little-endian.
+   */
+  public short readUShort() throws IOException {
+    int b1 = readUnsignedByte();
+    int b2 = readUnsignedByte();
+    return (short) ((b2 << 8) | b1);
+  }
+
+  /**
+   * @param value A 16-bit number to be written to the file in little-endian.
+   */
+  public void writeUShort(short value) throws IOException {
+    int b1 = value & 0xff;
+    int b2 = (value & 0xff00) >> 8;
+    writeByte(b1);
+    writeByte(b2);
+  }
+
+  /**
+   * @return A 32-bit number, read from the file as little-endian.
+   */
+  public int readUInt() throws IOException {
+    int b1 = readUnsignedByte();
+    int b2 = readUnsignedByte();
+    int b3 = readUnsignedByte();
+    int b4 = readUnsignedByte();
+    return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
+  }
+
+  /**
+   * @param value A 32-bit number to be written to the file in little-endian.
+   */
+  public void writeUInt(int value) throws IOException {
+    int b1 = value & 0xff;
+    writeByte(b1);
+    int b2 = (value & 0xff00) >> 8;
+    writeByte(b2);
+    int b3 = (value & 0xff0000) >> 16;
+    writeByte(b3);
+    int b4 = (value & 0xff000000) >> 24;
+    writeByte(b4);
+  }
+
+  /**
+   * @return An up to 32-bit number, read from the file in ULEB128 form.
+   */
+  public int readUleb128() throws IOException {
+    int shift = 0;
+    int value = 0;
+    int rawByte = readUnsignedByte();
+    boolean done = false;
+    while (!done) {
+      // Get the lower seven bits.
+      // 0x7f = 0111 1111
+      value |= ((rawByte & 0x7f) << shift);
+      shift += 7;
+      // Check the 8th bit - if it's 0, we're done.
+      // 0x80 = 1000 0000
+      if ((rawByte & 0x80) == 0) {
+        done = true;
+      } else {
+        rawByte = readUnsignedByte();
+      }
+    }
+    return value;
+  }
+
+  /**
+   * @param value A 32-bit number to be written to the file in ULEB128 form.
+   */
+  public void writeUleb128(int value) throws IOException {
+    if (value == 0) {
+      writeByte(0);
+      return;
+    }
+
+    while (value != 0) {
+      int marker = 1;
+      // If we're down to the last 7 bits, the marker will be 0.
+      if ((value & 0xffffff80) == 0) {
+        marker = 0;
+      }
+      // Get the lowest 7 bits, add on the marker in the high bit.
+      int nextByte = value & 0x7f | (marker << 7);
+      writeByte(nextByte);
+      value >>>= 7;
+    }
+  }
+
+  /**
+   * Write out ULEB128 value always using 5 bytes.
+   * A version of ULEB128 that will always write out 5 bytes, because this
+   * value will be patched later, and if we used a smaller encoding, the new value
+   * may overflow the previously selected encoding size.
+   * The largest encoding for 0 in ULEB128 would be:
+   *   0x80 0x80 0x80 0x80 0x00
+   * and for 1 would be:
+   *   0x81 0x80 0x80 0x80 0x00
+   */
+  public void writeLargestUleb128(int value) throws IOException {
+    Log.debug("Writing " + value + " using the largest possible ULEB128 encoding.");
+    if (value == 0) {
+      writeByte(0x80);
+      writeByte(0x80);
+      writeByte(0x80);
+      writeByte(0x80);
+      writeByte(0x0);
+      return;
+    }
+
+    for (int i = 0; i < 5; i++) {
+      int marker = 1;
+      // If we're writing the 5th byte, the marker is 0.
+      if (i == 4) {
+        marker = 0;
+      }
+      // Get the lowest 7 bits, add on the marker in the high bit.
+      int nextByte = value & 0x7f | (marker << 7);
+      writeByte(nextByte);
+      value >>>= 7;
+    }
+  }
+
+  /**
+   * @return An up to 32-bit number, read from the file in SLEB128 form.
+   */
+  public int readSleb128() throws IOException {
+    int shift = 0;
+    int value = 0;
+    int rawByte = readUnsignedByte();
+    boolean done = false;
+    boolean mustSignExtend = false;
+    while (!done) {
+      // Get the lower seven bits.
+      // 0x7f = 0111 1111
+      value |= ((rawByte & 0x7f) << shift);
+      shift += 7;
+      // Check the 8th bit - if it's 0, we're done.
+      // 0x80 = 1000 0000
+      if ((rawByte & 0x80) == 0) {
+        // Check the 7th bit - if it's a 1, we need to sign extend.
+        if ((rawByte & 0x60) != 0) {
+          mustSignExtend = true;
+        }
+        done = true;
+      } else {
+        rawByte = readUnsignedByte();
+      }
+    }
+    if (mustSignExtend) {
+      // Example:
+      // say we shifted 7 bits, we need
+      // to make all the upper 25 bits 1s.
+      // load a 1...
+      // 00000000 00000000 00000000 00000001
+      // << 7
+      // 00000000 00000000 00000000 10000000
+      // - 1
+      // 00000000 00000000 00000000 01111111
+      // ~
+      // 11111111 11111111 11111111 10000000
+      int upperOnes = ~((1 << shift) - 1);
+      value |= (upperOnes);
+    }
+    return value;
+  }
+
+  /**
+   * @param value A 32-bit number to be written to the file in SLEB128 form.
+   */
+  public void writeSleb128(int value) throws IOException {
+    if (value == 0) {
+      writeByte(0);
+      return;
+    }
+    if (value > 0) {
+      writeUleb128(value);
+      return;
+    }
+    if (value == -1) {
+      writeByte(0x7f);
+    }
+
+    // When it's all 1s (0xffffffff), we're done!
+    while (value != 0xffffffff) {
+      int marker = 1;
+      // If we're down to the last 7 bits (i.e., shifting a further 7 is all 1s),
+      // the marker will be 0.
+      if ((value >> 7) == 0xffffffff) {
+        marker = 0;
+      }
+      // Get the lowest 7 bits, add on the marker in the high bit.
+      int nextByte = value & 0x7f | (marker << 7);
+      writeByte(nextByte);
+      value >>= 7;
+    }
+  }
+
+  /**
+   * In DEX format, strings are in MUTF-8 format, the first ULEB128 value is the decoded size
+   * (i.e., string.length), and then follows a null-terminated series of characters.
+   * @param decodedSize The ULEB128 value that should have been read just before this.
+   * @return The raw bytes of the string, not including the null character.
+   */
+  public byte[] readDexUtf(int decodedSize) throws IOException {
+    // In the dex MUTF-8, the encoded size can never be larger than 3 times
+    // the actual string's length (which is the ULEB128 value just before this
+    // string, the "decoded size")
+
+    // Therefore, allocate as much space as we might need.
+    byte[] str = new byte[decodedSize * 3];
+
+    // Get our first byte.
+    int encodedSize = 0;
+    byte rawByte = readByte();
+
+    // Keep reading until we find the end marker.
+    while (rawByte != 0) {
+      str[encodedSize++] = rawByte;
+      rawByte = readByte();
+    }
+
+    // Copy everything we read into str into the correctly-sized actual string.
+    byte[] actualString = new byte[encodedSize];
+    for (int i = 0; i < encodedSize; i++) {
+      actualString[i] = str[i];
+    }
+
+    return actualString;
+  }
+
+  /**
+   * Writes out raw bytes that would have been read by readDexUTF().
+   * Will automatically write out the null-byte at the end.
+   * @param data Bytes to be written out.
+   */
+  public void writeDexUtf(byte[] data) throws IOException {
+    write(data);
+    // Remember to add the end marker.
+    writeByte(0);
+  }
+
+  /**
+   * Align the file handle's seek pointer to the next N bytes.
+   * @param alignment N to align to.
+   */
+  public void alignForwards(int alignment) throws IOException {
+    long offset = getFilePointer();
+    long mask = alignment - 1;
+    if ((offset & mask) != 0) {
+      int extra = alignment - (int) (offset & mask);
+      seek(offset + extra);
+    }
+  }
+
+  /**
+   * Align the file handle's seek pointer backwards to the previous N bytes.
+   * @param alignment N to align to.
+   */
+  public void alignBackwards(int alignment) throws IOException {
+    long offset = getFilePointer();
+    long mask = alignment - 1;
+    if ((offset & mask) != 0) {
+      offset &= (~mask);
+      seek(offset);
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedAnnotation.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedAnnotation.java
new file mode 100644
index 0000000..085a4a8
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedAnnotation.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedAnnotation implements RawDexObject {
+  public int typeIdx;
+  public int size;
+  public AnnotationElement[] elements;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    typeIdx = file.readUleb128();
+    size = file.readUleb128();
+    if (size != 0) {
+      elements = new AnnotationElement[size];
+      for (int i = 0; i < size; i++) {
+        (elements[i] = new AnnotationElement()).read(file);
+      }
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(typeIdx);
+    file.writeUleb128(size);
+    if (size != 0) {
+      for (AnnotationElement annotationElement : elements) {
+        annotationElement.write(file);
+      }
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && typeIdx >= insertedIdx) {
+      typeIdx++;
+    }
+    if (size != 0) {
+      for (AnnotationElement element : elements) {
+        element.incrementIndex(kind, insertedIdx);
+      }
+    }
+  }
+
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedArray.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedArray.java
new file mode 100644
index 0000000..267ff09
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedArray.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedArray implements RawDexObject {
+  public int size;
+  public EncodedValue[] values;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    size = file.readUleb128();
+    if (size != 0) {
+      values = new EncodedValue[size];
+      for (int i = 0; i < size; i++) {
+        (values[i] = new EncodedValue()).read(file);
+      }
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(size);
+    if (size != 0) {
+      for (EncodedValue encodedValue : values) {
+        encodedValue.write(file);
+      }
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (size != 0) {
+      for (EncodedValue value : values) {
+        value.incrementIndex(kind, insertedIdx);
+      }
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedArrayItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedArrayItem.java
new file mode 100644
index 0000000..e461a54
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedArrayItem.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedArrayItem implements RawDexObject {
+  public EncodedArray value;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    (value = new EncodedArray()).read(file);
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    value.write(file);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedCatchHandler.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedCatchHandler.java
new file mode 100644
index 0000000..83786c8
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedCatchHandler.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedCatchHandler implements RawDexObject {
+  public int size;
+  public EncodedTypeAddrPair[] handlers;
+  public int catchAllAddr;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    size = file.readSleb128();
+    int absoluteSize = Math.abs(size);
+    if (absoluteSize > 0) {
+      handlers = new EncodedTypeAddrPair[absoluteSize];
+      for (int i = 0; i < Math.abs(size); i++) {
+        (handlers[i] = new EncodedTypeAddrPair()).read(file);
+      }
+    }
+    if (size <= 0) {
+      catchAllAddr = file.readUleb128();
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeSleb128(size);
+    if (handlers != null) {
+      for (EncodedTypeAddrPair encodedTypeAddrPair : handlers) {
+        encodedTypeAddrPair.write(file);
+      }
+    }
+    if (size <= 0) {
+      file.writeUleb128(catchAllAddr);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (handlers != null) {
+      for (EncodedTypeAddrPair handler : handlers) {
+        handler.incrementIndex(kind, insertedIdx);
+      }
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedCatchHandlerList.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedCatchHandlerList.java
new file mode 100644
index 0000000..5619b5f
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedCatchHandlerList.java
@@ -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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedCatchHandlerList implements RawDexObject {
+  public int size;
+  public EncodedCatchHandler[] list;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    size = file.readUleb128();
+    list = new EncodedCatchHandler[size];
+    for (int i = 0; i < size; i++) {
+      (list[i] = new EncodedCatchHandler()).read(file);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(size);
+    for (EncodedCatchHandler encodedCatchHandler : list) {
+      encodedCatchHandler.write(file);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    for (EncodedCatchHandler handler : list) {
+      handler.incrementIndex(kind, insertedIdx);
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedField.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedField.java
new file mode 100644
index 0000000..18c1d43
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedField.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedField implements RawDexObject {
+  public int fieldIdxDiff;
+  public int accessFlags;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    fieldIdxDiff = file.readUleb128();
+    accessFlags = file.readUleb128();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(fieldIdxDiff);
+    file.writeUleb128(accessFlags);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+    // NB: our idx_diff is handled in ClassDataItem...
+  }
+
+  public boolean isVolatile() {
+    return ((accessFlags & Flag.ACC_VOLATILE.getValue()) != 0);
+  }
+
+  /**
+   * Set/unset the volatile flag for this EncodedField.
+   */
+  public void setVolatile(boolean turnOn) {
+    if (turnOn) {
+      accessFlags |= Flag.ACC_VOLATILE.getValue();
+    } else {
+      accessFlags &= ~(Flag.ACC_VOLATILE.getValue());
+    }
+  }
+
+  private static enum Flag {
+    ACC_PUBLIC(0x1),
+    ACC_PRIVATE(0x2),
+    ACC_PROTECTED(0x4),
+    ACC_STATIC(0x8),
+    ACC_FINAL(0x10),
+    ACC_VOLATILE(0x40),
+    ACC_TRANSIENT(0x80),
+    ACC_SYNTHETIC(0x1000),
+    ACC_ENUM(0x4000);
+
+    private int value;
+
+    private Flag(int value) {
+      this.value = value;
+    }
+
+    public int getValue() {
+      return value;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedMethod.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedMethod.java
new file mode 100644
index 0000000..3a8163a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedMethod.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.IOException;
+
+public class EncodedMethod implements RawDexObject {
+  public int methodIdxDiff;
+  public int accessFlags;
+  public Offset codeOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    methodIdxDiff = file.readUleb128();
+    accessFlags = file.readUleb128();
+    codeOff = file.getOffsetTracker().getNewOffset(file.readUleb128());
+    if (isNative()) {
+      Log.errorAndQuit("Sorry, DEX files with native methods are not supported yet.");
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(methodIdxDiff);
+    file.writeUleb128(accessFlags);
+    file.getOffsetTracker().tryToWriteOffset(codeOff, file, true /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+    // NB: our idx_diff is handled in ClassDataItem...
+  }
+
+  public boolean isStatic() {
+    return ((accessFlags & Flag.ACC_STATIC.getValue()) != 0);
+  }
+
+  public boolean isNative() {
+    return ((accessFlags & Flag.ACC_NATIVE.getValue()) != 0);
+  }
+
+  /**
+   * Set/unset the static flag for this EncodedMethod.
+   */
+  public void setStatic(boolean turnOn) {
+    if (turnOn) {
+      accessFlags |= Flag.ACC_STATIC.getValue();
+    } else {
+      accessFlags &= ~(Flag.ACC_STATIC.getValue());
+    }
+  }
+
+  private static enum Flag {
+    ACC_PUBLIC(0x1),
+    ACC_PRIVATE(0x2),
+    ACC_PROTECTED(0x4),
+    ACC_STATIC(0x8),
+    ACC_FINAL(0x10),
+    ACC_SYNCHRONIZED(0x20),
+    ACC_VARARGS(0x80),
+    ACC_NATIVE(0x100),
+    ACC_ABSTRACT(0x400),
+    ACC_STRICT(0x800),
+    ACC_SYNTHETIC(0x1000),
+    ACC_ENUM(0x4000),
+    ACC_CONSTRUCTOR(0x10000);
+
+    private int value;
+
+    private Flag(int value) {
+      this.value = value;
+    }
+
+    public int getValue() {
+      return value;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedTypeAddrPair.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedTypeAddrPair.java
new file mode 100644
index 0000000..ea49ae1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedTypeAddrPair.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedTypeAddrPair implements RawDexObject {
+  public int typeIdx;
+  public int addr;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    typeIdx = file.readUleb128();
+    addr = file.readUleb128();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUleb128(typeIdx);
+    file.writeUleb128(addr);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && typeIdx >= insertedIdx) {
+      typeIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/EncodedValue.java b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedValue.java
new file mode 100644
index 0000000..fdf133f
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/EncodedValue.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class EncodedValue implements RawDexObject {
+  public byte valueArg;
+  public byte valueType;
+  public byte[] value;
+  public EncodedArray encodedArray;
+  public EncodedAnnotation encodedAnnotation;
+
+  private static final byte VALUE_BYTE = 0x00;
+  private static final byte VALUE_ARRAY = 0x1c;
+  private static final byte VALUE_ANNOTATION = 0x1d;
+  private static final byte VALUE_NULL = 0x1e;
+  private static final byte VALUE_BOOLEAN = 0x1f;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    int valueArgAndType = file.readUnsignedByte();
+
+    // Get lower 5 bits.
+    valueType = (byte) (valueArgAndType & 0x1f);
+    // Get upper 3 bits.
+    valueArg = (byte) ((valueArgAndType & 0xe0) >> 5);
+
+    int size = 0;
+
+    switch (valueType) {
+      case VALUE_BYTE:
+        size = 1;
+        break;
+      case VALUE_ARRAY:
+        (encodedArray = new EncodedArray()).read(file);
+        size = 0; // So we don't read into value.
+        break;
+      case VALUE_ANNOTATION:
+        (encodedAnnotation = new EncodedAnnotation()).read(file);
+        size = 0; // So we don't read into value.
+        break;
+      case VALUE_NULL:
+      case VALUE_BOOLEAN:
+        // No value
+        size = 0;
+        break;
+      default:
+        // All others encode value_arg as (size - 1), so...
+        size = valueArg + 1;
+        break;
+    }
+
+    if (size != 0) {
+      value = new byte[size];
+      for (int i = 0; i < size; i++) {
+        value[i] = file.readByte();
+      }
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    int valueArgAndType = ((valueType) | (valueArg << 5));
+    file.writeByte(valueArgAndType);
+
+    if (encodedArray != null) {
+      encodedArray.write(file);
+    } else if (encodedAnnotation != null) {
+      encodedAnnotation.write(file);
+    } else if (value != null) {
+      file.write(value);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (encodedArray != null) {
+      encodedArray.incrementIndex(kind, insertedIdx);
+    } else if (encodedAnnotation != null) {
+      encodedAnnotation.incrementIndex(kind, insertedIdx);
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/FieldAnnotation.java b/tools/dexfuzz/src/dexfuzz/rawdex/FieldAnnotation.java
new file mode 100644
index 0000000..98f812e
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/FieldAnnotation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class FieldAnnotation implements RawDexObject {
+  public int fieldIdx;
+  public Offset annotationsOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    fieldIdx = file.readUInt();
+    annotationsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUInt(fieldIdx);
+    file.getOffsetTracker().tryToWriteOffset(annotationsOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.FIELD_ID && fieldIdx >= insertedIdx) {
+      fieldIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/FieldIdItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/FieldIdItem.java
new file mode 100644
index 0000000..75f2078
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/FieldIdItem.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class FieldIdItem implements RawDexObject {
+  public short classIdx;
+  public short typeIdx;
+  public int nameIdx;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    classIdx = file.readUShort();
+    typeIdx = file.readUShort();
+    nameIdx = file.readUInt();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUShort(classIdx);
+    file.writeUShort(typeIdx);
+    file.writeUInt(nameIdx);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && classIdx >= insertedIdx) {
+      classIdx++;
+    }
+    if (kind == IndexUpdateKind.TYPE_ID && typeIdx >= insertedIdx) {
+      typeIdx++;
+    }
+    if (kind == IndexUpdateKind.STRING_ID && nameIdx >= insertedIdx) {
+      nameIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/HeaderItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/HeaderItem.java
new file mode 100644
index 0000000..e6b290c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/HeaderItem.java
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.IOException;
+
+public class HeaderItem implements RawDexObject {
+  public byte[] magic;
+  public int checksum;
+  public byte[] signature; // Verification doesn't depend on this, so we don't update it.
+  public int fileSize;
+  public int headerSize;
+  public int endianTag;
+  public int linkSize;
+  public Offset linkOff;
+  public Offset mapOff;
+  public int stringIdsSize;
+  public Offset stringIdsOff;
+  public int typeIdsSize;
+  public Offset typeIdsOff;
+  public int protoIdsSize;
+  public Offset protoIdsOff;
+  public int fieldIdsSize;
+  public Offset fieldIdsOff;
+  public int methodIdsSize;
+  public Offset methodIdsOff;
+  public int classDefsSize;
+  public Offset classDefsOff;
+  public int dataSize;
+  public Offset dataOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    magic = new byte[8];
+    for (int i = 0; i < 8; i++) {
+      magic[i] = file.readByte();
+    }
+    checksum = file.readUInt();
+    signature = new byte[20];
+    for (int i = 0; i < 20; i++) {
+      signature[i] = file.readByte();
+    }
+    fileSize = file.readUInt();
+    headerSize = file.readUInt();
+    endianTag = file.readUInt();
+    linkSize = file.readUInt();
+    linkOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    mapOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    stringIdsSize = file.readUInt();
+    stringIdsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    typeIdsSize = file.readUInt();
+    typeIdsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    protoIdsSize = file.readUInt();
+    protoIdsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    fieldIdsSize = file.readUInt();
+    fieldIdsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    methodIdsSize = file.readUInt();
+    methodIdsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    classDefsSize = file.readUInt();
+    classDefsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    dataSize = file.readUInt();
+    dataOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+    if (headerSize != 0x70) {
+      Log.errorAndQuit("Invalid header size in header.");
+    }
+    if (file.getFilePointer() != headerSize) {
+      Log.errorAndQuit("Read a different amount than expected in header: "
+          + file.getFilePointer());
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    for (int i = 0; i < 8; i++) {
+      file.writeByte(magic[i]);
+    }
+    // Will be recalculated later!
+    file.writeUInt(checksum);
+    for (int i = 0; i < 20; i++) {
+      file.writeByte(signature[i]);
+    }
+    // Will be recalculated later!
+    file.writeUInt(fileSize);
+    file.writeUInt(headerSize);
+    file.writeUInt(endianTag);
+    file.writeUInt(linkSize);
+    file.getOffsetTracker().tryToWriteOffset(linkOff, file, false /* ULEB128 */);
+    file.getOffsetTracker().tryToWriteOffset(mapOff, file, false /* ULEB128 */);
+    file.writeUInt(stringIdsSize);
+    file.getOffsetTracker().tryToWriteOffset(stringIdsOff, file, false /* ULEB128 */);
+    file.writeUInt(typeIdsSize);
+    file.getOffsetTracker().tryToWriteOffset(typeIdsOff, file, false /* ULEB128 */);
+    file.writeUInt(protoIdsSize);
+    file.getOffsetTracker().tryToWriteOffset(protoIdsOff, file, false /* ULEB128 */);
+    file.writeUInt(fieldIdsSize);
+    file.getOffsetTracker().tryToWriteOffset(fieldIdsOff, file, false /* ULEB128 */);
+    file.writeUInt(methodIdsSize);
+    file.getOffsetTracker().tryToWriteOffset(methodIdsOff, file, false /* ULEB128 */);
+    file.writeUInt(classDefsSize);
+    file.getOffsetTracker().tryToWriteOffset(classDefsOff, file, false /* ULEB128 */);
+    // will be recalculated later
+    file.writeUInt(dataSize);
+    file.getOffsetTracker().tryToWriteOffset(dataOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/Instruction.java b/tools/dexfuzz/src/dexfuzz/rawdex/Instruction.java
new file mode 100644
index 0000000..2dda78f
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/Instruction.java
@@ -0,0 +1,584 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+import dexfuzz.rawdex.formats.AbstractFormat;
+import dexfuzz.rawdex.formats.ContainsConst;
+import dexfuzz.rawdex.formats.ContainsPoolIndex;
+import dexfuzz.rawdex.formats.ContainsTarget;
+import dexfuzz.rawdex.formats.ContainsVRegs;
+import dexfuzz.rawdex.formats.Format10t;
+import dexfuzz.rawdex.formats.Format10x;
+import dexfuzz.rawdex.formats.Format11n;
+import dexfuzz.rawdex.formats.Format11x;
+import dexfuzz.rawdex.formats.Format12x;
+import dexfuzz.rawdex.formats.Format20t;
+import dexfuzz.rawdex.formats.Format21c;
+import dexfuzz.rawdex.formats.Format21h;
+import dexfuzz.rawdex.formats.Format21s;
+import dexfuzz.rawdex.formats.Format21t;
+import dexfuzz.rawdex.formats.Format22b;
+import dexfuzz.rawdex.formats.Format22c;
+import dexfuzz.rawdex.formats.Format22s;
+import dexfuzz.rawdex.formats.Format22t;
+import dexfuzz.rawdex.formats.Format22x;
+import dexfuzz.rawdex.formats.Format23x;
+import dexfuzz.rawdex.formats.Format30t;
+import dexfuzz.rawdex.formats.Format31c;
+import dexfuzz.rawdex.formats.Format31i;
+import dexfuzz.rawdex.formats.Format31t;
+import dexfuzz.rawdex.formats.Format32x;
+import dexfuzz.rawdex.formats.Format35c;
+import dexfuzz.rawdex.formats.Format3rc;
+import dexfuzz.rawdex.formats.Format51l;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Instruction implements RawDexObject {
+  // Only used by Format35* instructions
+  public static class InvokeFormatInfo {
+    public byte vregD;
+    public byte vregE;
+    public byte vregF;
+    public byte vregG;
+  }
+
+  // Immutable information about this class of instruction.
+  public OpcodeInfo info;
+
+  // The raw bytes of the instruction.
+  // Only used during reading, and writing out is done from the decoded instruction data.
+  //  Except in the case of the 3 "data" instructions.
+  public byte[] rawBytes;
+
+  public static final int RAW_TYPE_PACKED_SWITCH_DATA = 1;
+  public static final int RAW_TYPE_SPARSE_SWITCH_DATA = 2;
+  public static final int RAW_TYPE_FILL_ARRAY_DATA_DATA = 3;
+
+  public int rawType;
+  public boolean justRaw;
+  public int rawSize;
+
+  public long vregA = 0;
+  public long vregB = 0;
+  public long vregC = 0;
+
+  public InvokeFormatInfo invokeFormatInfo;
+
+  /**
+   * Clone an instruction.
+   */
+  public Instruction clone() {
+    Instruction newInsn = new Instruction();
+    // If we've generated a new instruction, we won't have calculated its raw array.
+    if (newInsn.rawBytes != null) {
+      newInsn.rawBytes = new byte[rawBytes.length];
+      for (int i = 0; i < rawBytes.length; i++) {
+        newInsn.rawBytes[i] = rawBytes[i];
+      }
+    }
+    newInsn.justRaw = justRaw;
+    newInsn.rawType = rawType;
+    newInsn.rawSize = rawSize;
+
+    newInsn.vregA = vregA;
+    newInsn.vregB = vregB;
+    newInsn.vregC = vregC;
+    newInsn.info = info;
+    if (invokeFormatInfo != null) {
+      newInsn.invokeFormatInfo = new InvokeFormatInfo();
+      newInsn.invokeFormatInfo.vregD = invokeFormatInfo.vregD;
+      newInsn.invokeFormatInfo.vregE = invokeFormatInfo.vregE;
+      newInsn.invokeFormatInfo.vregF = invokeFormatInfo.vregF;
+      newInsn.invokeFormatInfo.vregG = invokeFormatInfo.vregG;
+    }
+    return newInsn;
+  }
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    // Remember the offset, so after reading the opcode, we can read the whole
+    // insn into raw_bytes.
+    long offset = file.getFilePointer();
+    int opcodeValue = readOpcode(file);
+    info = getOpcodeInfo(opcodeValue);
+    if (info == null) {
+      Log.errorAndQuit("Couldn't find OpcodeInfo for opcode with value: "
+          + opcodeValue);
+    }
+
+    rawBytes = new byte[2 * getSize()];
+    file.seek(offset);
+    file.read(rawBytes);
+
+    vregA = info.format.getA(rawBytes);
+    vregB = info.format.getB(rawBytes);
+    vregC = info.format.getC(rawBytes);
+
+    // Special case for 35* formats.
+    if (info.format.needsInvokeFormatInfo()) {
+      invokeFormatInfo = new InvokeFormatInfo();
+      invokeFormatInfo.vregD = (byte) (rawBytes[4] >> 4);
+      invokeFormatInfo.vregE = (byte) (rawBytes[5] & 0xf);
+      invokeFormatInfo.vregF = (byte) (rawBytes[5] >> 4);
+      invokeFormatInfo.vregG = (byte) (rawBytes[1] & 0xf);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    if (justRaw) {
+      // It is the responsibility of the CodeTranslator to make
+      // sure the raw bytes have been updated.
+      file.write(rawBytes);
+    } else {
+      info.format.writeToFile(file, this);
+    }
+  }
+
+  /**
+   * Get the size of an instruction, in code-words. (Code-words are 16-bits.)
+   */
+  public int getSize() {
+    if (justRaw) {
+      // It is the responsibility of the CodeTranslator to make sure
+      // the raw size has been updated.
+      return rawSize;
+    }
+    return info.format.getSize();
+  }
+
+  private int readOpcode(DexRandomAccessFile file) throws IOException {
+    short firstCodeWord = file.readUShort();
+    int opcode = (firstCodeWord & 0xff);
+    int upperBits = (firstCodeWord & 0xff00) >> 8;
+    if (opcode == 0x0 && upperBits != 0x0) {
+      justRaw = true;
+      rawType = upperBits;
+      // Need to calculate special sizes.
+      switch (rawType) {
+        case RAW_TYPE_PACKED_SWITCH_DATA:
+          rawSize = (file.readUShort() * 2) + 4;
+          break;
+        case RAW_TYPE_SPARSE_SWITCH_DATA:
+          rawSize = (file.readUShort() * 4) + 2;
+          break;
+        case RAW_TYPE_FILL_ARRAY_DATA_DATA:
+        {
+          int elementWidth = file.readUShort();
+          rawSize = ((file.readUInt() * elementWidth + 1) / 2) + 4;
+          break;
+        }
+        default:
+          Log.errorAndQuit("Unrecognised ident in data-payload instruction: " + rawType);
+      }
+    }
+    return opcode;
+  }
+
+  @Override
+  public String toString() {
+    if (justRaw) {
+      switch (rawType) {
+        case RAW_TYPE_PACKED_SWITCH_DATA:
+          return "PACKED SWITCH DATA";
+        case RAW_TYPE_SPARSE_SWITCH_DATA:
+          return "SPARSE SWITCH DATA";
+        case RAW_TYPE_FILL_ARRAY_DATA_DATA:
+          return "FILL ARRAY DATA DATA";
+        default:
+      }
+
+    }
+
+    String repr = info.name;
+
+    AbstractFormat format = info.format;
+
+    if (invokeFormatInfo != null) {
+      String vregs = "";
+
+      int numVregs = (int) vregA;
+
+      if (numVregs > 5) {
+        Log.debug("vA in an 35c invoke was greater than 5? Assuming 5.");
+        numVregs = 5;
+      } else if (numVregs < 0) {
+        Log.debug("vA in an 35c invoke was less than 0? Assuming 0.");
+        numVregs = 0;
+      }
+
+      switch (numVregs) {
+        case 5:
+          vregs = ", v" + invokeFormatInfo.vregG;
+          // fallthrough
+        case 4:
+          vregs = ", v" + invokeFormatInfo.vregF + vregs;
+          // fallthrough
+        case 3:
+          vregs = ", v" + invokeFormatInfo.vregE + vregs;
+          // fallthrough
+        case 2:
+          vregs = ", v" + invokeFormatInfo.vregD + vregs;
+          // fallthrough
+        case 1:
+          vregs = "v" + vregC + vregs;
+          break;
+        default:
+      }
+
+      repr += "(" + vregs + ")";
+
+      long poolIndex = ((ContainsPoolIndex)format).getPoolIndex(this);
+      repr += " meth@" + poolIndex;
+
+      return repr;
+    }
+
+
+
+    if (format instanceof ContainsVRegs) {
+      String vregs = "";
+      switch (((ContainsVRegs)format).getVRegCount()) {
+        case 3:
+          vregs = ", v" + vregC;
+          // fallthrough
+        case 2:
+          vregs = ", v" + vregB + vregs;
+          // fallthrough
+        case 1:
+          vregs = "v" + vregA + vregs;
+          break;
+        default:
+          Log.errorAndQuit("Invalid number of vregs reported by a Format.");
+      }
+
+      repr += " " + vregs;
+    }
+    if (format instanceof ContainsConst) {
+      long constant = ((ContainsConst)format).getConst(this);
+      repr += " #" + constant;
+    }
+    if (format instanceof ContainsPoolIndex) {
+      long poolIndex = ((ContainsPoolIndex)format).getPoolIndex(this);
+      repr += " pool@" + poolIndex;
+    }
+    if (format instanceof ContainsTarget) {
+      long target = ((ContainsTarget)format).getTarget(this);
+      repr += " +" + target;
+    }
+
+    return repr;
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+
+  // STATIC INSTRUCTION CODE
+  private static Map<Integer,OpcodeInfo> opcode_map_by_int = new HashMap<Integer,OpcodeInfo>();
+  private static Map<Opcode,OpcodeInfo> opcode_map_by_enum = new HashMap<Opcode,OpcodeInfo>();
+
+  public static OpcodeInfo getOpcodeInfo(Opcode opcode) {
+    return opcode_map_by_enum.get(opcode);
+  }
+
+  public static OpcodeInfo getOpcodeInfo(int opcodeValue) {
+    return opcode_map_by_int.get(opcodeValue);
+  }
+
+  private static void addOpcodeInfo(Opcode opcode, String name,
+      int opcodeValue, AbstractFormat fmt) {
+    OpcodeInfo info = new OpcodeInfo(opcode, name, opcodeValue, fmt);
+    if (opcode.ordinal() != opcodeValue) {
+      Log.errorAndQuit(String.format("Opcode: %s (enum ordinal 0x%x) != (value 0x%x)",
+          opcode.toString(), opcode.ordinal(), opcodeValue));
+    }
+    opcode_map_by_int.put(opcodeValue, info);
+    opcode_map_by_enum.put(opcode, info);
+  }
+
+  static {
+    addOpcodeInfo(Opcode.NOP, "nop", 0x00, new Format10x());
+    addOpcodeInfo(Opcode.MOVE, "move", 0x01, new Format12x());
+    addOpcodeInfo(Opcode.MOVE_FROM16, "move/from16", 0x02, new Format22x());
+    addOpcodeInfo(Opcode.MOVE_16, "move/16", 0x03, new Format32x());
+    addOpcodeInfo(Opcode.MOVE_WIDE, "move-wide", 0x04, new Format12x());
+    addOpcodeInfo(Opcode.MOVE_WIDE_FROM16, "move-wide/from16", 0x05, new Format22x());
+    addOpcodeInfo(Opcode.MOVE_WIDE_16, "move-wide/16", 0x06, new Format32x());
+    addOpcodeInfo(Opcode.MOVE_OBJECT, "move-object", 0x07, new Format12x());
+    addOpcodeInfo(Opcode.MOVE_OBJECT_FROM16, "move-object/from16", 0x08, new Format22x());
+    addOpcodeInfo(Opcode.MOVE_OBJECT_16, "move-object/16", 0x09, new Format32x());
+    addOpcodeInfo(Opcode.MOVE_RESULT, "move-result", 0x0a, new Format11x());
+    addOpcodeInfo(Opcode.MOVE_RESULT_WIDE, "move-result-wide", 0x0b, new Format11x());
+    addOpcodeInfo(Opcode.MOVE_RESULT_OBJECT, "move-result-object", 0x0c, new Format11x());
+    addOpcodeInfo(Opcode.MOVE_EXCEPTION, "move-exception", 0x0d, new Format11x());
+    addOpcodeInfo(Opcode.RETURN_VOID, "return-void", 0x0e, new Format10x());
+    addOpcodeInfo(Opcode.RETURN, "return", 0x0f, new Format11x());
+    addOpcodeInfo(Opcode.RETURN_WIDE, "return-wide", 0x10, new Format11x());
+    addOpcodeInfo(Opcode.RETURN_OBJECT, "return-object", 0x11, new Format11x());
+    addOpcodeInfo(Opcode.CONST_4, "const/4", 0x12, new Format11n());
+    addOpcodeInfo(Opcode.CONST_16, "const/16", 0x13, new Format21s());
+    addOpcodeInfo(Opcode.CONST, "const", 0x14, new Format31i());
+    addOpcodeInfo(Opcode.CONST_HIGH16, "const/high16", 0x15, new Format21h());
+    addOpcodeInfo(Opcode.CONST_WIDE_16, "const-wide/16", 0x16, new Format21s());
+    addOpcodeInfo(Opcode.CONST_WIDE_32, "const-wide/32", 0x17, new Format31i());
+    addOpcodeInfo(Opcode.CONST_WIDE, "const-wide", 0x18, new Format51l());
+    addOpcodeInfo(Opcode.CONST_WIDE_HIGH16, "const-wide/high16", 0x19, new Format21h());
+    addOpcodeInfo(Opcode.CONST_STRING, "const-string", 0x1a, new Format21c());
+    addOpcodeInfo(Opcode.CONST_STRING_JUMBO, "const-string/jumbo", 0x1b, new Format31c());
+    addOpcodeInfo(Opcode.CONST_CLASS, "const-class", 0x1c, new Format21c());
+    addOpcodeInfo(Opcode.MONITOR_ENTER, "monitor-enter", 0x1d, new Format11x());
+    addOpcodeInfo(Opcode.MONITOR_EXIT, "monitor-exit", 0x1e, new Format11x());
+    addOpcodeInfo(Opcode.CHECK_CAST, "check-cast", 0x1f, new Format21c());
+    addOpcodeInfo(Opcode.INSTANCE_OF, "instance-of", 0x20, new Format22c());
+    addOpcodeInfo(Opcode.ARRAY_LENGTH, "array-length", 0x21, new Format12x());
+    addOpcodeInfo(Opcode.NEW_INSTANCE, "new-instance", 0x22, new Format21c());
+    addOpcodeInfo(Opcode.NEW_ARRAY, "new-array", 0x23, new Format22c());
+    addOpcodeInfo(Opcode.FILLED_NEW_ARRAY, "filled-new-array", 0x24, new Format35c());
+    addOpcodeInfo(Opcode.FILLED_NEW_ARRAY_RANGE, "filled-new-array/range",
+        0x25, new Format3rc());
+    addOpcodeInfo(Opcode.FILL_ARRAY_DATA, "fill-array-data", 0x26, new Format31t());
+    addOpcodeInfo(Opcode.THROW, "throw", 0x27, new Format11x());
+    addOpcodeInfo(Opcode.GOTO, "goto", 0x28, new Format10t());
+    addOpcodeInfo(Opcode.GOTO_16, "goto/16", 0x29, new Format20t());
+    addOpcodeInfo(Opcode.GOTO_32, "goto/32", 0x2a, new Format30t());
+    addOpcodeInfo(Opcode.PACKED_SWITCH, "packed-switch", 0x2b, new Format31t());
+    addOpcodeInfo(Opcode.SPARSE_SWITCH, "sparse-switch", 0x2c, new Format31t());
+    addOpcodeInfo(Opcode.CMPL_FLOAT, "cmpl-float", 0x2d, new Format23x());
+    addOpcodeInfo(Opcode.CMPG_FLOAT, "cmpg-float", 0x2e, new Format23x());
+    addOpcodeInfo(Opcode.CMPL_DOUBLE, "cmpl-double", 0x2f, new Format23x());
+    addOpcodeInfo(Opcode.CMPG_DOUBLE, "cmpg-double", 0x30, new Format23x());
+    addOpcodeInfo(Opcode.CMP_LONG, "cmp-long", 0x31, new Format23x());
+    addOpcodeInfo(Opcode.IF_EQ, "if-eq", 0x32, new Format22t());
+    addOpcodeInfo(Opcode.IF_NE, "if-ne", 0x33, new Format22t());
+    addOpcodeInfo(Opcode.IF_LT, "if-lt", 0x34, new Format22t());
+    addOpcodeInfo(Opcode.IF_GE, "if-ge", 0x35, new Format22t());
+    addOpcodeInfo(Opcode.IF_GT, "if-gt", 0x36, new Format22t());
+    addOpcodeInfo(Opcode.IF_LE, "if-le", 0x37, new Format22t());
+    addOpcodeInfo(Opcode.IF_EQZ, "if-eqz", 0x38, new Format21t());
+    addOpcodeInfo(Opcode.IF_NEZ, "if-nez", 0x39, new Format21t());
+    addOpcodeInfo(Opcode.IF_LTZ, "if-ltz", 0x3a, new Format21t());
+    addOpcodeInfo(Opcode.IF_GEZ, "if-gez", 0x3b, new Format21t());
+    addOpcodeInfo(Opcode.IF_GTZ, "if-gtz", 0x3c, new Format21t());
+    addOpcodeInfo(Opcode.IF_LEZ, "if-lez", 0x3d, new Format21t());
+    addOpcodeInfo(Opcode.UNUSED_3E, "unused-3e", 0x3e, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_3F, "unused-3f", 0x3f, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_40, "unused-40", 0x40, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_41, "unused-41", 0x41, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_42, "unused-42", 0x42, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_43, "unused-43", 0x43, new Format10x());
+    addOpcodeInfo(Opcode.AGET, "aget", 0x44, new Format23x());
+    addOpcodeInfo(Opcode.AGET_WIDE, "aget-wide", 0x45, new Format23x());
+    addOpcodeInfo(Opcode.AGET_WIDE, "aget-wide", 0x45, new Format23x());
+    addOpcodeInfo(Opcode.AGET_OBJECT, "aget-object", 0x46, new Format23x());
+    addOpcodeInfo(Opcode.AGET_BOOLEAN, "aget-boolean", 0x47, new Format23x());
+    addOpcodeInfo(Opcode.AGET_BYTE, "aget-byte", 0x48, new Format23x());
+    addOpcodeInfo(Opcode.AGET_CHAR, "aget-char", 0x49, new Format23x());
+    addOpcodeInfo(Opcode.AGET_SHORT, "aget-short", 0x4a, new Format23x());
+    addOpcodeInfo(Opcode.APUT, "aput", 0x4b, new Format23x());
+    addOpcodeInfo(Opcode.APUT_WIDE, "aput-wide", 0x4c, new Format23x());
+    addOpcodeInfo(Opcode.APUT_OBJECT, "aput-object", 0x4d, new Format23x());
+    addOpcodeInfo(Opcode.APUT_BOOLEAN, "aput-boolean", 0x4e, new Format23x());
+    addOpcodeInfo(Opcode.APUT_BYTE, "aput-byte", 0x4f, new Format23x());
+    addOpcodeInfo(Opcode.APUT_CHAR, "aput-char", 0x50, new Format23x());
+    addOpcodeInfo(Opcode.APUT_SHORT, "aput-short", 0x51, new Format23x());
+    addOpcodeInfo(Opcode.IGET, "iget", 0x52, new Format22c());
+    addOpcodeInfo(Opcode.IGET_WIDE, "iget-wide", 0x53, new Format22c());
+    addOpcodeInfo(Opcode.IGET_OBJECT, "iget-object", 0x54, new Format22c());
+    addOpcodeInfo(Opcode.IGET_BOOLEAN, "iget-boolean", 0x55, new Format22c());
+    addOpcodeInfo(Opcode.IGET_BYTE, "iget-byte", 0x56, new Format22c());
+    addOpcodeInfo(Opcode.IGET_CHAR, "iget-char", 0x57, new Format22c());
+    addOpcodeInfo(Opcode.IGET_SHORT, "iget-short", 0x58, new Format22c());
+    addOpcodeInfo(Opcode.IPUT, "iput", 0x59, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_WIDE, "iput-wide", 0x5a, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_OBJECT, "iput-object", 0x5b, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_BOOLEAN, "iput-boolean", 0x5c, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_BYTE, "iput-byte", 0x5d, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_CHAR, "iput-char", 0x5e, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_SHORT, "iput-short", 0x5f, new Format22c());
+    addOpcodeInfo(Opcode.SGET, "sget", 0x60, new Format21c());
+    addOpcodeInfo(Opcode.SGET_WIDE, "sget-wide", 0x61, new Format21c());
+    addOpcodeInfo(Opcode.SGET_OBJECT, "sget-object", 0x62, new Format21c());
+    addOpcodeInfo(Opcode.SGET_BOOLEAN, "sget-boolean", 0x63, new Format21c());
+    addOpcodeInfo(Opcode.SGET_BYTE, "sget-byte", 0x64, new Format21c());
+    addOpcodeInfo(Opcode.SGET_CHAR, "sget-char", 0x65, new Format21c());
+    addOpcodeInfo(Opcode.SGET_SHORT, "sget-short", 0x66, new Format21c());
+    addOpcodeInfo(Opcode.SPUT, "sput", 0x67, new Format21c());
+    addOpcodeInfo(Opcode.SPUT_WIDE, "sput-wide", 0x68, new Format21c());
+    addOpcodeInfo(Opcode.SPUT_OBJECT, "sput-object", 0x69, new Format21c());
+    addOpcodeInfo(Opcode.SPUT_BOOLEAN, "sput-boolean", 0x6a, new Format21c());
+    addOpcodeInfo(Opcode.SPUT_BYTE, "sput-byte", 0x6b, new Format21c());
+    addOpcodeInfo(Opcode.SPUT_CHAR, "sput-char", 0x6c, new Format21c());
+    addOpcodeInfo(Opcode.SPUT_SHORT, "sput-short", 0x6d, new Format21c());
+    addOpcodeInfo(Opcode.INVOKE_VIRTUAL, "invoke-virtual", 0x6e, new Format35c());
+    addOpcodeInfo(Opcode.INVOKE_SUPER, "invoke-super", 0x6f, new Format35c());
+    addOpcodeInfo(Opcode.INVOKE_DIRECT, "invoke-direct", 0x70, new Format35c());
+    addOpcodeInfo(Opcode.INVOKE_STATIC, "invoke-static", 0x71, new Format35c());
+    addOpcodeInfo(Opcode.INVOKE_INTERFACE, "invoke-interface", 0x72, new Format35c());
+    addOpcodeInfo(Opcode.RETURN_VOID_BARRIER, "return-void-barrier", 0x73, new Format10x());
+    addOpcodeInfo(Opcode.INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", 0x74, new Format3rc());
+    addOpcodeInfo(Opcode.INVOKE_SUPER_RANGE, "invoke-super/range", 0x75, new Format3rc());
+    addOpcodeInfo(Opcode.INVOKE_DIRECT_RANGE, "invoke-direct/range", 0x76, new Format3rc());
+    addOpcodeInfo(Opcode.INVOKE_STATIC_RANGE, "invoke-static/range", 0x77, new Format3rc());
+    addOpcodeInfo(Opcode.INVOKE_INTERFACE_RANGE, "invoke-interface/range",
+        0x78, new Format3rc());
+    addOpcodeInfo(Opcode.UNUSED_79, "unused-79", 0x79, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_7A, "unused-7a", 0x7a, new Format10x());
+    addOpcodeInfo(Opcode.NEG_INT, "neg-int", 0x7b, new Format12x());
+    addOpcodeInfo(Opcode.NOT_INT, "not-int", 0x7c, new Format12x());
+    addOpcodeInfo(Opcode.NEG_LONG, "neg-long", 0x7d, new Format12x());
+    addOpcodeInfo(Opcode.NOT_LONG, "not-long", 0x7e, new Format12x());
+    addOpcodeInfo(Opcode.NEG_FLOAT, "neg-float", 0x7f, new Format12x());
+    addOpcodeInfo(Opcode.NEG_DOUBLE, "neg-double", 0x80, new Format12x());
+    addOpcodeInfo(Opcode.INT_TO_LONG, "int-to-long", 0x81, new Format12x());
+    addOpcodeInfo(Opcode.INT_TO_FLOAT, "int-to-float", 0x82, new Format12x());
+    addOpcodeInfo(Opcode.INT_TO_DOUBLE, "int-to-double", 0x83, new Format12x());
+    addOpcodeInfo(Opcode.LONG_TO_INT, "long-to-int", 0x84, new Format12x());
+    addOpcodeInfo(Opcode.LONG_TO_FLOAT, "long-to-float", 0x85, new Format12x());
+    addOpcodeInfo(Opcode.LONG_TO_DOUBLE, "long-to-double", 0x86, new Format12x());
+    addOpcodeInfo(Opcode.FLOAT_TO_INT, "float-to-int", 0x87, new Format12x());
+    addOpcodeInfo(Opcode.FLOAT_TO_LONG, "float-to-long", 0x88, new Format12x());
+    addOpcodeInfo(Opcode.FLOAT_TO_DOUBLE, "float-to-double", 0x89, new Format12x());
+    addOpcodeInfo(Opcode.DOUBLE_TO_INT, "double-to-int", 0x8a, new Format12x());
+    addOpcodeInfo(Opcode.DOUBLE_TO_LONG, "double-to-long", 0x8b, new Format12x());
+    addOpcodeInfo(Opcode.DOUBLE_TO_FLOAT, "double-to-float", 0x8c, new Format12x());
+    addOpcodeInfo(Opcode.INT_TO_BYTE, "int-to-byte", 0x8d, new Format12x());
+    addOpcodeInfo(Opcode.INT_TO_CHAR, "int-to-char", 0x8e, new Format12x());
+    addOpcodeInfo(Opcode.INT_TO_SHORT, "int-to-short", 0x8f, new Format12x());
+    addOpcodeInfo(Opcode.ADD_INT, "add-int", 0x90, new Format23x());
+    addOpcodeInfo(Opcode.SUB_INT, "sub-int", 0x91, new Format23x());
+    addOpcodeInfo(Opcode.MUL_INT, "mul-int", 0x92, new Format23x());
+    addOpcodeInfo(Opcode.DIV_INT, "div-int", 0x93, new Format23x());
+    addOpcodeInfo(Opcode.REM_INT, "rem-int", 0x94, new Format23x());
+    addOpcodeInfo(Opcode.AND_INT, "and-int", 0x95, new Format23x());
+    addOpcodeInfo(Opcode.OR_INT, "or-int", 0x96, new Format23x());
+    addOpcodeInfo(Opcode.XOR_INT, "xor-int", 0x97, new Format23x());
+    addOpcodeInfo(Opcode.SHL_INT, "shl-int", 0x98, new Format23x());
+    addOpcodeInfo(Opcode.SHR_INT, "shr-int", 0x99, new Format23x());
+    addOpcodeInfo(Opcode.USHR_INT, "ushr-int", 0x9a, new Format23x());
+    addOpcodeInfo(Opcode.ADD_LONG, "add-long", 0x9b, new Format23x());
+    addOpcodeInfo(Opcode.SUB_LONG, "sub-long", 0x9c, new Format23x());
+    addOpcodeInfo(Opcode.MUL_LONG, "mul-long", 0x9d, new Format23x());
+    addOpcodeInfo(Opcode.DIV_LONG, "div-long", 0x9e, new Format23x());
+    addOpcodeInfo(Opcode.REM_LONG, "rem-long", 0x9f, new Format23x());
+    addOpcodeInfo(Opcode.AND_LONG, "and-long", 0xa0, new Format23x());
+    addOpcodeInfo(Opcode.OR_LONG, "or-long", 0xa1, new Format23x());
+    addOpcodeInfo(Opcode.XOR_LONG, "xor-long", 0xa2, new Format23x());
+    addOpcodeInfo(Opcode.SHL_LONG, "shl-long", 0xa3, new Format23x());
+    addOpcodeInfo(Opcode.SHR_LONG, "shr-long", 0xa4, new Format23x());
+    addOpcodeInfo(Opcode.USHR_LONG, "ushr-long", 0xa5, new Format23x());
+    addOpcodeInfo(Opcode.ADD_FLOAT, "add-float", 0xa6, new Format23x());
+    addOpcodeInfo(Opcode.SUB_FLOAT, "sub-float", 0xa7, new Format23x());
+    addOpcodeInfo(Opcode.MUL_FLOAT, "mul-float", 0xa8, new Format23x());
+    addOpcodeInfo(Opcode.DIV_FLOAT, "div-float", 0xa9, new Format23x());
+    addOpcodeInfo(Opcode.REM_FLOAT, "rem-float", 0xaa, new Format23x());
+    addOpcodeInfo(Opcode.ADD_DOUBLE, "add-double", 0xab, new Format23x());
+    addOpcodeInfo(Opcode.SUB_DOUBLE, "sub-double", 0xac, new Format23x());
+    addOpcodeInfo(Opcode.MUL_DOUBLE, "mul-double", 0xad, new Format23x());
+    addOpcodeInfo(Opcode.DIV_DOUBLE, "div-double", 0xae, new Format23x());
+    addOpcodeInfo(Opcode.REM_DOUBLE, "rem-double", 0xaf, new Format23x());
+    addOpcodeInfo(Opcode.ADD_INT_2ADDR, "add-int/2addr", 0xb0, new Format12x());
+    addOpcodeInfo(Opcode.SUB_INT_2ADDR, "sub-int/2addr", 0xb1, new Format12x());
+    addOpcodeInfo(Opcode.MUL_INT_2ADDR, "mul-int/2addr", 0xb2, new Format12x());
+    addOpcodeInfo(Opcode.DIV_INT_2ADDR, "div-int/2addr", 0xb3, new Format12x());
+    addOpcodeInfo(Opcode.REM_INT_2ADDR, "rem-int/2addr", 0xb4, new Format12x());
+    addOpcodeInfo(Opcode.AND_INT_2ADDR, "and-int/2addr", 0xb5, new Format12x());
+    addOpcodeInfo(Opcode.OR_INT_2ADDR, "or-int/2addr", 0xb6, new Format12x());
+    addOpcodeInfo(Opcode.XOR_INT_2ADDR, "xor-int/2addr", 0xb7, new Format12x());
+    addOpcodeInfo(Opcode.SHL_INT_2ADDR, "shl-int/2addr", 0xb8, new Format12x());
+    addOpcodeInfo(Opcode.SHR_INT_2ADDR, "shr-int/2addr", 0xb9, new Format12x());
+    addOpcodeInfo(Opcode.USHR_INT_2ADDR, "ushr-int/2addr", 0xba, new Format12x());
+    addOpcodeInfo(Opcode.ADD_LONG_2ADDR, "add-long/2addr", 0xbb, new Format12x());
+    addOpcodeInfo(Opcode.SUB_LONG_2ADDR, "sub-long/2addr", 0xbc, new Format12x());
+    addOpcodeInfo(Opcode.MUL_LONG_2ADDR, "mul-long/2addr", 0xbd, new Format12x());
+    addOpcodeInfo(Opcode.DIV_LONG_2ADDR, "div-long/2addr", 0xbe, new Format12x());
+    addOpcodeInfo(Opcode.REM_LONG_2ADDR, "rem-long/2addr", 0xbf, new Format12x());
+    addOpcodeInfo(Opcode.AND_LONG_2ADDR, "and-long/2addr", 0xc0, new Format12x());
+    addOpcodeInfo(Opcode.OR_LONG_2ADDR, "or-long/2addr", 0xc1, new Format12x());
+    addOpcodeInfo(Opcode.XOR_LONG_2ADDR, "xor-long/2addr", 0xc2, new Format12x());
+    addOpcodeInfo(Opcode.SHL_LONG_2ADDR, "shl-long/2addr", 0xc3, new Format12x());
+    addOpcodeInfo(Opcode.SHR_LONG_2ADDR, "shr-long/2addr", 0xc4, new Format12x());
+    addOpcodeInfo(Opcode.USHR_LONG_2ADDR, "ushr-long/2addr", 0xc5, new Format12x());
+    addOpcodeInfo(Opcode.ADD_FLOAT_2ADDR, "add-float/2addr", 0xc6, new Format12x());
+    addOpcodeInfo(Opcode.SUB_FLOAT_2ADDR, "sub-float/2addr", 0xc7, new Format12x());
+    addOpcodeInfo(Opcode.MUL_FLOAT_2ADDR, "mul-float/2addr", 0xc8, new Format12x());
+    addOpcodeInfo(Opcode.DIV_FLOAT_2ADDR, "div-float/2addr", 0xc9, new Format12x());
+    addOpcodeInfo(Opcode.REM_FLOAT_2ADDR, "rem-float/2addr", 0xca, new Format12x());
+    addOpcodeInfo(Opcode.ADD_DOUBLE_2ADDR, "add-double/2addr", 0xcb, new Format12x());
+    addOpcodeInfo(Opcode.SUB_DOUBLE_2ADDR, "sub-double/2addr", 0xcc, new Format12x());
+    addOpcodeInfo(Opcode.MUL_DOUBLE_2ADDR, "mul-double/2addr", 0xcd, new Format12x());
+    addOpcodeInfo(Opcode.DIV_DOUBLE_2ADDR, "div-double/2addr", 0xce, new Format12x());
+    addOpcodeInfo(Opcode.REM_DOUBLE_2ADDR, "rem-double/2addr", 0xcf, new Format12x());
+    addOpcodeInfo(Opcode.ADD_INT_LIT16, "add-int/lit16", 0xd0, new Format22s());
+    addOpcodeInfo(Opcode.RSUB_INT, "rsub-int", 0xd1, new Format22s());
+    addOpcodeInfo(Opcode.MUL_INT_LIT16, "mul-int/lit16", 0xd2, new Format22s());
+    addOpcodeInfo(Opcode.DIV_INT_LIT16, "div-int/lit16", 0xd3, new Format22s());
+    addOpcodeInfo(Opcode.REM_INT_LIT16, "rem-int/lit16", 0xd4, new Format22s());
+    addOpcodeInfo(Opcode.AND_INT_LIT16, "and-int/lit16", 0xd5, new Format22s());
+    addOpcodeInfo(Opcode.OR_INT_LIT16, "or-int/lit16", 0xd6, new Format22s());
+    addOpcodeInfo(Opcode.XOR_INT_LIT16, "xor-int/lit16", 0xd7, new Format22s());
+    addOpcodeInfo(Opcode.ADD_INT_LIT8, "add-int/lit8", 0xd8, new Format22b());
+    addOpcodeInfo(Opcode.RSUB_INT_LIT8, "rsub-int/lit8", 0xd9, new Format22b());
+    addOpcodeInfo(Opcode.MUL_INT_LIT8, "mul-int/lit8", 0xda, new Format22b());
+    addOpcodeInfo(Opcode.DIV_INT_LIT8, "div-int/lit8", 0xdb, new Format22b());
+    addOpcodeInfo(Opcode.REM_INT_LIT8, "rem-int/lit8", 0xdc, new Format22b());
+    addOpcodeInfo(Opcode.AND_INT_LIT8, "and-int/lit8", 0xdd, new Format22b());
+    addOpcodeInfo(Opcode.OR_INT_LIT8, "or-int/lit8", 0xde, new Format22b());
+    addOpcodeInfo(Opcode.XOR_INT_LIT8, "xor-int/lit8", 0xdf, new Format22b());
+    addOpcodeInfo(Opcode.SHL_INT_LIT8, "shl-int/lit8", 0xe0, new Format22b());
+    addOpcodeInfo(Opcode.SHR_INT_LIT8, "shr-int/lit8", 0xe1, new Format22b());
+    addOpcodeInfo(Opcode.USHR_INT_LIT8, "ushr-int/lit8", 0xe2, new Format22b());
+    addOpcodeInfo(Opcode.IGET_QUICK, "+iget-quick", 0xe3, new Format22c());
+    addOpcodeInfo(Opcode.IGET_WIDE_QUICK, "+iget-wide-quick", 0xe4, new Format22c());
+    addOpcodeInfo(Opcode.IGET_OBJECT_QUICK, "+iget-object-quick", 0xe5, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_QUICK, "+iput-quick", 0xe6, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_WIDE_QUICK, "+iput-wide-quick", 0xe7, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_OBJECT_QUICK, "+iput-object-quick", 0xe8, new Format22c());
+    addOpcodeInfo(Opcode.INVOKE_VIRTUAL_QUICK, "+invoke-virtual-quick", 0xe9, new Format35c());
+    addOpcodeInfo(Opcode.INVOKE_VIRTUAL_QUICK_RANGE, "+invoke-virtual-quick/range",
+        0xea, new Format3rc());
+    addOpcodeInfo(Opcode.IPUT_BOOLEAN_QUICK, "+iput-boolean-quick", 0xeb, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_BYTE_QUICK, "+iput-byte-quick", 0xec, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_CHAR_QUICK, "+iput-char-quick", 0xed, new Format22c());
+    addOpcodeInfo(Opcode.IPUT_SHORT_QUICK, "+iput-short-quick", 0xee, new Format22c());
+    addOpcodeInfo(Opcode.UNUSED_EF, "unused-ef", 0xef, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F0, "unused-f0", 0xf0, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F1, "unused-f1", 0xf1, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F2, "unused-f2", 0xf2, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F3, "unused-f3", 0xf3, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F4, "unused-f4", 0xf4, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F5, "unused-f5", 0xf5, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F6, "unused-f6", 0xf6, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F7, "unused-f7", 0xf7, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F8, "unused-f8", 0xf8, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_F9, "unused-f9", 0xf9, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_FA, "unused-fa", 0xfa, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_FB, "unused-fb", 0xfb, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_FC, "unused-fc", 0xfc, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_FD, "unused-fd", 0xfd, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_FE, "unused-fe", 0xfe, new Format10x());
+    addOpcodeInfo(Opcode.UNUSED_FF, "unused-ff", 0xff, new Format10x());
+    if (opcode_map_by_int.size() != 256) {
+      Log.errorAndQuit("Incorrect number of bytecodes defined.");
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/MapItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/MapItem.java
new file mode 100644
index 0000000..4ca2463
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/MapItem.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class MapItem implements RawDexObject {
+  public static final int TYPE_HEADER_ITEM = 0x0;
+  public static final int TYPE_STRING_ID_ITEM = 0x1;
+  public static final int TYPE_TYPE_ID_ITEM = 0x2;
+  public static final int TYPE_PROTO_ID_ITEM = 0x3;
+  public static final int TYPE_FIELD_ID_ITEM = 0x4;
+  public static final int TYPE_METHOD_ID_ITEM = 0x5;
+  public static final int TYPE_CLASS_DEF_ITEM = 0x6;
+  public static final int TYPE_MAP_LIST = 0x1000;
+  public static final int TYPE_TYPE_LIST = 0x1001;
+  public static final int TYPE_ANNOTATION_SET_REF_LIST = 0x1002;
+  public static final int TYPE_ANNOTATION_SET_ITEM = 0x1003;
+  public static final int TYPE_CLASS_DATA_ITEM = 0x2000;
+  public static final int TYPE_CODE_ITEM = 0x2001;
+  public static final int TYPE_STRING_DATA_ITEM = 0x2002;
+  public static final int TYPE_DEBUG_INFO_ITEM = 0x2003;
+  public static final int TYPE_ANNOTATION_ITEM = 0x2004;
+  public static final int TYPE_ENCODED_ARRAY_ITEM = 0x2005;
+  public static final int TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006;
+
+  public short type;
+  public int size;
+  public Offset offset;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    type = file.readUShort();
+    file.readUShort(); // Unused padding.
+    size = file.readUInt();
+    if (type == TYPE_HEADER_ITEM) {
+      offset = file.getOffsetTracker().getNewHeaderOffset(file.readUInt());
+    } else {
+      offset = file.getOffsetTracker().getNewOffset(file.readUInt());
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUShort(type);
+    file.writeUShort((short) 0); // Unused padding.
+    file.writeUInt(size);
+    file.getOffsetTracker().tryToWriteOffset(offset, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java b/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java
new file mode 100644
index 0000000..080b5a4
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/MapList.java
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MapList implements RawDexObject {
+
+  private RawDexFile rawDexFile;
+
+  public int size;
+  public List<MapItem> mapItems;
+
+  public MapList(RawDexFile rawDexFile) {
+    this.rawDexFile = rawDexFile;
+  }
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    // Find the map list.
+    file.seek(rawDexFile.header.mapOff.getOriginalOffset());
+
+    file.getOffsetTracker().getNewOffsettable(file, this);
+
+    // Get the number of entries.
+    size = file.readUInt();
+
+    // Allocate and populate the array.
+    mapItems = new ArrayList<MapItem>(size);
+    for (int i = 0; i < size; i++) {
+      MapItem mapItem = new MapItem();
+      mapItems.add(mapItem);
+      mapItem.read(file);
+    }
+
+    file.getOffsetTracker().rememberPointAfterMapList();
+
+    // NB: We track the current index into the MapList, so when we encounter the DebugInfoItem
+    // MapItem, we know how to find the next MapItem, so we know how large the DebugInfo
+    // area is, so we can copy it as a blob.
+    int mapItemIdx = 0;
+
+    // Iterate through the list, and create all the other data structures.
+    for (MapItem mapItem : mapItems) {
+      file.seek(mapItem.offset.getOriginalOffset());
+      switch (mapItem.type) {
+        case MapItem.TYPE_HEADER_ITEM:
+          // Already read it; skip.
+          break;
+        case MapItem.TYPE_STRING_ID_ITEM:
+          for (int i = 0; i < mapItem.size; i++) {
+            StringIdItem newStringId = new StringIdItem();
+            rawDexFile.stringIds.add(newStringId);
+            newStringId.read(file);
+          }
+          break;
+        case MapItem.TYPE_TYPE_ID_ITEM:
+          for (int i = 0; i < mapItem.size; i++) {
+            TypeIdItem newTypeId = new TypeIdItem();
+            rawDexFile.typeIds.add(newTypeId);
+            newTypeId.read(file);
+          }
+          break;
+        case MapItem.TYPE_PROTO_ID_ITEM:
+          for (int i = 0; i < mapItem.size; i++) {
+            ProtoIdItem newProtoId = new ProtoIdItem();
+            rawDexFile.protoIds.add(newProtoId);
+            newProtoId.read(file);
+          }
+          break;
+        case MapItem.TYPE_FIELD_ID_ITEM:
+          for (int i = 0; i < mapItem.size; i++) {
+            FieldIdItem newFieldId = new FieldIdItem();
+            rawDexFile.fieldIds.add(newFieldId);
+            newFieldId.read(file);
+          }
+          break;
+        case MapItem.TYPE_METHOD_ID_ITEM:
+          for (int i = 0; i < mapItem.size; i++) {
+            MethodIdItem newMethodId = new MethodIdItem();
+            rawDexFile.methodIds.add(newMethodId);
+            newMethodId.read(file);
+          }
+          break;
+        case MapItem.TYPE_CLASS_DEF_ITEM:
+          for (int i = 0; i < mapItem.size; i++) {
+            ClassDefItem newClassDef = new ClassDefItem();
+            rawDexFile.classDefs.add(newClassDef);
+            newClassDef.read(file);
+          }
+          break;
+        case MapItem.TYPE_MAP_LIST:
+          // Already read it; skip.
+          break;
+        case MapItem.TYPE_TYPE_LIST:
+          rawDexFile.typeLists = new ArrayList<TypeList>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            TypeList newTypeList = new TypeList();
+            rawDexFile.typeLists.add(newTypeList);
+            newTypeList.read(file);
+          }
+          break;
+        case MapItem.TYPE_ANNOTATION_SET_REF_LIST:
+          rawDexFile.annotationSetRefLists =
+            new ArrayList<AnnotationSetRefList>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            AnnotationSetRefList newAnnotationSetRefList = new AnnotationSetRefList();
+            rawDexFile.annotationSetRefLists.add(newAnnotationSetRefList);
+            newAnnotationSetRefList.read(file);
+          }
+          break;
+        case MapItem.TYPE_ANNOTATION_SET_ITEM:
+          rawDexFile.annotationSetItems = new ArrayList<AnnotationSetItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            AnnotationSetItem newAnnotationSetItem = new AnnotationSetItem();
+            rawDexFile.annotationSetItems.add(newAnnotationSetItem);
+            newAnnotationSetItem.read(file);
+          }
+          break;
+        case MapItem.TYPE_CLASS_DATA_ITEM:
+          rawDexFile.classDatas = new ArrayList<ClassDataItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            ClassDataItem newClassData = new ClassDataItem();
+            rawDexFile.classDatas.add(newClassData);
+            newClassData.read(file);
+          }
+          break;
+        case MapItem.TYPE_CODE_ITEM:
+          rawDexFile.codeItems = new ArrayList<CodeItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            CodeItem newCodeItem = new CodeItem();
+            rawDexFile.codeItems.add(newCodeItem);
+            newCodeItem.read(file);
+          }
+          break;
+        case MapItem.TYPE_STRING_DATA_ITEM:
+          rawDexFile.stringDatas = new ArrayList<StringDataItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            StringDataItem newStringData = new StringDataItem();
+            rawDexFile.stringDatas.add(newStringData);
+            newStringData.read(file);
+          }
+          break;
+        case MapItem.TYPE_DEBUG_INFO_ITEM:
+        {
+          // We aren't interested in updating the debug data, so just read it as a blob.
+          int start = mapItem.offset.getOriginalOffset();
+          int end = mapItems.get(mapItemIdx + 1).offset.getOriginalOffset();
+          int size = end - start;
+          rawDexFile.debugInfoItem = new DebugInfoItem(size);
+          rawDexFile.debugInfoItem.read(file);
+          break;
+        }
+        case MapItem.TYPE_ANNOTATION_ITEM:
+          rawDexFile.annotationItems = new ArrayList<AnnotationItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            AnnotationItem newAnnotationItem = new AnnotationItem();
+            rawDexFile.annotationItems.add(newAnnotationItem);
+            newAnnotationItem.read(file);
+          }
+          break;
+        case MapItem.TYPE_ENCODED_ARRAY_ITEM:
+          rawDexFile.encodedArrayItems = new ArrayList<EncodedArrayItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            EncodedArrayItem newEncodedArrayItem = new EncodedArrayItem();
+            rawDexFile.encodedArrayItems.add(newEncodedArrayItem);
+            newEncodedArrayItem.read(file);
+          }
+          break;
+        case MapItem.TYPE_ANNOTATIONS_DIRECTORY_ITEM:
+          rawDexFile.annotationsDirectoryItems =
+          new ArrayList<AnnotationsDirectoryItem>(mapItem.size);
+          for (int i = 0; i < mapItem.size; i++) {
+            AnnotationsDirectoryItem newAnnotationsDirectoryItem = new AnnotationsDirectoryItem();
+            rawDexFile.annotationsDirectoryItems.add(newAnnotationsDirectoryItem);
+            newAnnotationsDirectoryItem.read(file);
+          }
+          break;
+        default:
+          Log.errorAndQuit("Encountered unknown map item when reading map item list.");
+      }
+      mapItemIdx++;
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(mapItems.size());
+    for (MapItem mapItem : mapItems) {
+      mapItem.write(file);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/MethodAnnotation.java b/tools/dexfuzz/src/dexfuzz/rawdex/MethodAnnotation.java
new file mode 100644
index 0000000..1a24fb6
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/MethodAnnotation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class MethodAnnotation implements RawDexObject {
+  public int methodIdx;
+  public Offset annotationsOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    methodIdx = file.readUInt();
+    annotationsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUInt(methodIdx);
+    file.getOffsetTracker().tryToWriteOffset(annotationsOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.METHOD_ID && methodIdx >= insertedIdx) {
+      methodIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/MethodIdItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/MethodIdItem.java
new file mode 100644
index 0000000..12d0187
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/MethodIdItem.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class MethodIdItem implements RawDexObject {
+  public short classIdx;
+  public short protoIdx;
+  public int nameIdx;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    classIdx = file.readUShort();
+    protoIdx = file.readUShort();
+    nameIdx = file.readUInt();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUShort(classIdx);
+    file.writeUShort(protoIdx);
+    file.writeUInt(nameIdx);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && classIdx >= insertedIdx) {
+      classIdx++;
+    }
+    if (kind == IndexUpdateKind.PROTO_ID && protoIdx >= insertedIdx) {
+      protoIdx++;
+    }
+    if (kind == IndexUpdateKind.STRING_ID && nameIdx >= insertedIdx) {
+      nameIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/Offset.java b/tools/dexfuzz/src/dexfuzz/rawdex/Offset.java
new file mode 100644
index 0000000..b6718e3
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/Offset.java
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+public class Offset {
+  /**
+   * The absolute value of this offset as it was originally read.
+   */
+  private int originalOffset;
+
+  /**
+   * The Offsettable that this Offset points to.
+   */
+  private Offsettable offsettable;
+
+  /**
+   * The location of this Offset in the new file, ONLY SET IF the Offset
+   * couldn't be written because what it points to hasn't been written
+   * yet.
+   */
+  private int outputLocation;
+
+  /**
+   * Was the output location for this Offset set?.
+   */
+  private boolean outputLocationSet;
+
+  /**
+   * Does this Offset need to be written out using ULEB128?.
+   */
+  private boolean useUleb128;
+
+  /**
+   * Was this Offset created after reading, during mutation?.
+   */
+  private boolean isNewOffset;
+
+  /**
+   * Only one Offset should have this flag set, the MapItem that points
+   * to the HeaderItem.
+   */
+  private boolean pointsAtHeader;
+
+  /**
+   * If an Offset pointed at 0 (because it is not actually a valid Offset),
+   * and it's not pointing at the header, then this is set.
+   */
+  private boolean pointsAtNull;
+
+  public Offset(boolean header) {
+    pointsAtHeader = header;
+  }
+
+  public RawDexObject getPointedToItem() {
+    return offsettable.getItem();
+  }
+
+  public boolean pointsToSomething() {
+    return offsettable != null;
+  }
+
+  public boolean pointsAtNull() {
+    return pointsAtNull;
+  }
+
+  public boolean pointsAtHeader() {
+    return pointsAtHeader;
+  }
+
+  /**
+   * Returns true if this Offset points at the provided RawDexObject.
+   */
+  public boolean pointsToThisItem(RawDexObject thisItem) {
+    if (!pointsToSomething()) {
+      return false;
+    }
+    return (offsettable.getItem().equals(thisItem));
+  }
+
+  /**
+   * Returns true if this Offset points at the provided Offsettable.
+   */
+  public boolean pointsToThisOffsettable(Offsettable thisOffsettable) {
+    if (!pointsToSomething()) {
+      return false;
+    }
+    return (offsettable.equals(thisOffsettable));
+  }
+
+  /**
+   * Makes this Offset point at a new Offsettable.
+   */
+  public void pointTo(Offsettable offsettableItem) {
+    if (offsettable != null) {
+      Log.debug("Updating what an Offset points to...");
+    }
+    offsettable = offsettableItem;
+  }
+
+  /**
+   * Call this to make an Offset that pointed at null before now point at something.
+   * An Offset may have previously pointed at null before...
+   * Example: if there are no fields referred to in a DEX file, then header.field_ids_off
+   * will point at null. We distinguish when Offsets point at null, and are not pointing
+   * at the header (only the header MapItem should do this) with a flag. Therefore, this
+   * method is needed to indicate that this Offset now points at something.
+   */
+  public void unsetNullAndPointTo(Offsettable offsettableItem) {
+    pointsAtNull = false;
+    if (offsettable != null) {
+      Log.debug("Updating what an Offset points to...");
+    }
+    offsettable = offsettableItem;
+  }
+
+  public void pointToNew(Offsettable offsettableItem) {
+    offsettable = offsettableItem;
+    isNewOffset = true;
+  }
+
+  public int getNewPositionOfItem() {
+    return offsettable.getNewPosition();
+  }
+
+  public boolean usesUleb128() {
+    return useUleb128;
+  }
+
+  /**
+   * Mark this Offset as using the ULEB128 encoding.
+   */
+  public void setUsesUleb128() {
+    if (useUleb128) {
+      throw new Error("Offset is already marked as using ULEB128!");
+    }
+    useUleb128 = true;
+  }
+
+  public boolean isNewOffset() {
+    return isNewOffset;
+  }
+
+  public void setPointsAtNull() {
+    pointsAtNull = true;
+  }
+
+  public void setOutputLocation(int loc) {
+    outputLocation = loc;
+    outputLocationSet = true;
+  }
+
+  /**
+   * Get the location in the output DEX file where this offset has been written.
+   * (This is used when patching Offsets when the Offsettable position was not
+   * known at the time of writing out the Offset.)
+   */
+  public int getOutputLocation() {
+    if (!outputLocationSet) {
+      throw new Error("Output location was not set yet!");
+    }
+    return outputLocation;
+  }
+
+  public void setOriginalOffset(int offset) {
+    originalOffset = offset;
+  }
+
+  public int getOriginalOffset() {
+    return originalOffset;
+  }
+
+  public boolean readyForWriting() {
+    return offsettable.readyForFinalOffsetToBeWritten();
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/OffsetTracker.java b/tools/dexfuzz/src/dexfuzz/rawdex/OffsetTracker.java
new file mode 100644
index 0000000..34d609a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/OffsetTracker.java
@@ -0,0 +1,513 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class allows the recording of both Offsettable items (that is, items that can be
+ * referred to by an offset somewhere else in the file - RawDexObjects) and Offsets.
+ * The idea in a nutshell is that for every Offsettable item we read, we remember
+ * its original position in the file using a map, and the order in which the Offsettables were
+ * written out. We also remember every Offset we read in, and its value. Then, after reading
+ * the whole file, we use the map to find the Offsettable it pointed at.
+ * Then, as we write out the file, for every Offsettable we write out, we record its new position,
+ * using the order we collected earlier. For every Offset we write out, we look at its Offsettable
+ * to see where it was written. If it hasn't been written yet, then we write out a blank value
+ * for the time being, remember where that blank value was written, and put the Offset into a
+ * table for patching once everything has been written out.
+ * There are some variables (index_after_map_list, restore_point) used for remembering certain
+ * points to jump forward and back to, because we cannot read and write the file out in exactly
+ * the same order.
+ * TODO: Perhaps it makes more sense to just reorder the offsettable_table once it's been read,
+ * in preparation for the order in which the file is written out?
+ * Finally, we provide methods for adding new Offsettable items into the right place in the order
+ * table.
+ */
+public class OffsetTracker {
+  /**
+   * A map from the original offset in the input DEX file to
+   * the Offsettable it points to. (That Offsettable will contain
+   * the actual item, and later on the new offset for the item when
+   * the item is written out.
+   */
+  private Map<Integer, Offsettable> offsettableMap;
+
+  /**
+   * A table of all Offsettables. We need to ensure we write out
+   * all items in the same order we read them in, to make sure we update
+   * the Offsettable.new_position field with the correct value wrt to
+   * the original_position field.
+   */
+  private List<Offsettable> offsettableTable;
+
+  /**
+   * A table of all offsets that is populated as we read in the DEX file.
+   * As the end, we find the correct Offsettable for the Offset in the above
+   * map, and associate them.
+   */
+  private List<Offset> needsAssociationTable;
+
+  /**
+   * A table of all offsets that we could not write out an updated offset for
+   * as we write out a DEX file. Will be checked after writing is complete,
+   * to allow specific patching of each offset's location as at that point
+   * all Offsettables will have been updated with their new position.
+   */
+  private List<Offset> needsUpdateTable;
+
+  /**
+   * Tracks how far we are through the offsettable_table as we write out the file.
+   */
+  private int offsettableTableIdx;
+
+  /**
+   * Because we write in a slightly different order to how we read
+   * (why? to read, we read the header, then the map list, and then use the map
+   *  list to read everything else.
+   *  when we write, we write the header, and then we cannot write the map list
+   *  because we don't know where it will go yet, so we write everything else first)
+   * so: we remember the position in the offsettable_table after we read the map list,
+   * so we can skip there after we write out the header.
+   */
+  private int indexAfterMapList;
+
+  /**
+   * Related to index_after_map_list, this is the index we save when we're jumping back to
+   * write the map list.
+   */
+  private int restorePoint;
+
+  /**
+   * Create a new OffsetTracker. Should persist between parsing a DEX file, and outputting
+   * the mutated DEX file.
+   */
+  public OffsetTracker() {
+    offsettableMap = new HashMap<Integer,Offsettable>();
+    offsettableTable = new ArrayList<Offsettable>();
+    needsAssociationTable = new ArrayList<Offset>();
+    needsUpdateTable = new ArrayList<Offset>();
+  }
+
+  /**
+   * Lookup an Item by the offset it had in the input DEX file.
+   * @param offset The offset in the input DEX file.
+   * @return The corresponding Item.
+   */
+  public RawDexObject getItemByOffset(int offset) {
+    return offsettableMap.get(offset).getItem();
+  }
+
+  /**
+   * As Items are read in, they call this function once they have word-aligned the file pointer,
+   * to record their position and themselves into an Offsettable object, that will be tracked.
+   * @param file Used for recording position into the new Offsettable.
+   * @param item Used for recording the relevant Item into the new Offsettable.
+   */
+  public void getNewOffsettable(DexRandomAccessFile file, RawDexObject item) throws IOException {
+    Offsettable offsettable = new Offsettable(item, false);
+    offsettable.setOriginalPosition((int) file.getFilePointer());
+    offsettableMap.put(offsettable.getOriginalPosition(), offsettable);
+    offsettableTable.add(offsettable);
+  }
+
+  /**
+   * As Items read in Offsets, they call this function with the offset they originally
+   * read from the file, to allow later association with an Offsettable.
+   * @param originalOffset The original offset read from the input DEX file.
+   * @return An Offset that will later be associated with an Offsettable.
+   */
+  public Offset getNewOffset(int originalOffset) throws IOException {
+    Offset offset = new Offset(false);
+    offset.setOriginalOffset(originalOffset);
+    needsAssociationTable.add(offset);
+    return offset;
+  }
+
+  /**
+   * Only MapItem should call this method, when the MapItem that points to the header
+   * is read.
+   */
+  public Offset getNewHeaderOffset(int originalOffset) throws IOException {
+    Offset offset = new Offset(true);
+    offset.setOriginalOffset(originalOffset);
+    needsAssociationTable.add(offset);
+    return offset;
+  }
+
+  /**
+   * Call this after reading, to associate Offsets with Offsettables.
+   */
+  public void associateOffsets() {
+    for (Offset offset : needsAssociationTable) {
+      if (offset.getOriginalOffset() == 0 && !(offset.pointsAtHeader())) {
+        offset.setPointsAtNull();
+      } else {
+        offset.pointTo(offsettableMap.get(offset.getOriginalOffset()));
+        if (!offset.pointsToSomething()) {
+          Log.error(String.format("Couldn't find original offset 0x%x!",
+              offset.getOriginalOffset()));
+        }
+      }
+    }
+    needsAssociationTable.clear();
+  }
+
+  /**
+   * As Items are written out into the output DEX file, this function is called
+   * to update the next Offsettable with the file pointer's current position.
+   * This should allow the tracking of new offset locations.
+   * This also requires that reading and writing of all items happens in the same order
+   * (with the exception of the map list, see above)
+   * @param file Used for recording the new position.
+   */
+  public void updatePositionOfNextOffsettable(DexRandomAccessFile file) throws IOException {
+    if (offsettableTableIdx == offsettableTable.size()) {
+      Log.errorAndQuit("Not all created Offsettable items have been added to the "
+          + "Offsettable Table!");
+    }
+    Offsettable offsettable = offsettableTable.get(offsettableTableIdx);
+    offsettable.setNewPosition((int) file.getFilePointer());
+    offsettableTableIdx++;
+  }
+
+  /**
+   * As Items are written out, any writing out of an offset must call this function, passing
+   * in the relevant offset. This function will write out the offset, if the associated
+   * Offsettable has been updated with its new position, or else will write out a null value, and
+   * the Offset will be stored for writing after all Items have been written, and all
+   * Offsettables MUST have been updated.
+   * @param offset The offset received from getNewOffset().
+   * @param file Used for writing out to the file.
+   * @param useUleb128 Whether or not the offset should be written in UINT or ULEB128 form.
+   */
+  public void tryToWriteOffset(Offset offset, DexRandomAccessFile file, boolean useUleb128)
+      throws IOException {
+    if (!offset.isNewOffset() && (!offset.pointsToSomething())) {
+      if (useUleb128) {
+        file.writeUleb128(0);
+      } else {
+        file.writeUInt(0);
+      }
+      return;
+    }
+
+    if (offset.readyForWriting()) {
+      if (useUleb128) {
+        file.writeUleb128(offset.getNewPositionOfItem());
+      } else {
+        file.writeUInt(offset.getNewPositionOfItem());
+      }
+    } else {
+      offset.setOutputLocation((int) file.getFilePointer());
+      if (useUleb128) {
+        file.writeLargestUleb128(offset.getOriginalOffset());
+        offset.setUsesUleb128();
+      } else {
+        file.writeUInt(offset.getOriginalOffset());
+      }
+      needsUpdateTable.add(offset);
+    }
+  }
+
+  /**
+   * This is called after all writing has finished, to write out any Offsets
+   * that could not be written out during the original writing phase, because their
+   * associated Offsettables hadn't had their new positions calculated yet.
+   * @param file Used for writing out to the file.
+   */
+  public void updateOffsets(DexRandomAccessFile file) throws IOException {
+    if (offsettableTableIdx != offsettableTable.size()) {
+      Log.errorAndQuit("Being asked to update dangling offsets but the "
+          + "correct number of offsettables has not been written out!");
+    }
+    for (Offset offset : needsUpdateTable) {
+      file.seek(offset.getOutputLocation());
+      if (offset.usesUleb128()) {
+        file.writeLargestUleb128(offset.getNewPositionOfItem());
+      } else {
+        file.writeUInt(offset.getNewPositionOfItem());
+      }
+    }
+    needsUpdateTable.clear();
+  }
+
+  /**
+   * Called after writing out the header, to skip to after the map list.
+   */
+  public void skipToAfterMapList() {
+    offsettableTableIdx = indexAfterMapList;
+  }
+
+  /**
+   * Called once the map list needs to be written out, to set the
+   * offsettable table index back to the right place.
+   */
+  public void goBackToMapList() {
+    restorePoint = offsettableTableIdx;
+    offsettableTableIdx = (indexAfterMapList - 1);
+  }
+
+  /**
+   * Called once the map list has been written out, to set the
+   * offsettable table index back to where it was before.
+   */
+  public void goBackToPreviousPoint() {
+    if (offsettableTableIdx != indexAfterMapList) {
+      Log.errorAndQuit("Being asked to go to the point before the MapList was written out,"
+          + " but we're not in the right place.");
+    }
+    offsettableTableIdx = restorePoint;
+  }
+
+  /**
+   * Called after reading in the map list, to remember the point to be skipped
+   * to later.
+   */
+  public void rememberPointAfterMapList() {
+    indexAfterMapList = offsettableTable.size();
+  }
+
+  private void updateHeaderOffsetIfValid(Offset offset, Offsettable previousFirst,
+      Offsettable newFirst, String offsetName) {
+    if (offset.pointsToThisOffsettable(previousFirst)) {
+      offset.pointToNew(newFirst);
+    } else {
+      Log.errorAndQuit("Header " + offsetName + " offset not pointing at first element?");
+    }
+  }
+
+  private void addTypeListsToMapFile(RawDexFile rawDexFile, Offsettable typeListOffsettable) {
+    // Create a MapItem for the TypeLists
+    MapItem typeListMapItem = new MapItem();
+    typeListMapItem.offset = new Offset(false);
+    typeListMapItem.offset.pointToNew(typeListOffsettable);
+    typeListMapItem.type = MapItem.TYPE_TYPE_LIST;
+    typeListMapItem.size = 1;
+
+    // Insert into the MapList.
+    // (first, find the MapItem that points to StringDataItems...)
+    int idx = 0;
+    for (MapItem mapItem : rawDexFile.mapList.mapItems) {
+      if (mapItem.type == MapItem.TYPE_STRING_DATA_ITEM) {
+        break;
+      }
+      idx++;
+    }
+    // (now insert the TypeList MapItem just before the StringDataItem one...)
+    rawDexFile.mapList.mapItems.add(idx, typeListMapItem);
+  }
+
+  private void addFieldIdsToHeaderAndMapFile(RawDexFile rawDexFile,
+      Offsettable fieldOffsettable) {
+    // Add the field IDs to the header.
+    rawDexFile.header.fieldIdsOff.unsetNullAndPointTo(fieldOffsettable);
+    rawDexFile.header.fieldIdsSize = 1;
+
+    // Create a MapItem for the field IDs.
+    MapItem fieldMapItem = new MapItem();
+    fieldMapItem.offset = new Offset(false);
+    fieldMapItem.offset.pointToNew(fieldOffsettable);
+    fieldMapItem.type = MapItem.TYPE_FIELD_ID_ITEM;
+    fieldMapItem.size = 1;
+
+    // Insert into the MapList.
+    // (first, find the MapItem that points to MethodIdItems...)
+    int idx = 0;
+    for (MapItem mapItem : rawDexFile.mapList.mapItems) {
+      if (mapItem.type == MapItem.TYPE_METHOD_ID_ITEM) {
+        break;
+      }
+      idx++;
+    }
+    // (now insert the FieldIdItem MapItem just before the MethodIdItem one...)
+    rawDexFile.mapList.mapItems.add(idx, fieldMapItem);
+  }
+
+
+  private void updateOffsetsInHeaderAndMapFile(RawDexFile rawDexFile,
+      Offsettable newFirstOffsettable) {
+    Offsettable prevFirstOffsettable = null;
+    for (int i = 0; i < offsettableTable.size(); i++) {
+      if (offsettableTable.get(i) == newFirstOffsettable) {
+        prevFirstOffsettable = offsettableTable.get(i + 1);
+        break;
+      }
+    }
+    if (prevFirstOffsettable == null) {
+      Log.errorAndQuit("When calling updateMapListOffsets, could not find new "
+          + "first offsettable?");
+    }
+
+    // Based on the type of the item we just added, check the relevant Offset in the header
+    // and if it pointed at the prev_first_offsettable, make it point at the new one.
+    // NB: if it isn't pointing at the prev one, something is wrong.
+    HeaderItem header = rawDexFile.header;
+    if (newFirstOffsettable.getItem() instanceof StringIdItem) {
+      updateHeaderOffsetIfValid(header.stringIdsOff, prevFirstOffsettable,
+          newFirstOffsettable, "StringID");
+    } else if (newFirstOffsettable.getItem() instanceof TypeIdItem) {
+      updateHeaderOffsetIfValid(header.typeIdsOff, prevFirstOffsettable,
+          newFirstOffsettable, "TypeID");
+    } else if (newFirstOffsettable.getItem() instanceof ProtoIdItem) {
+      updateHeaderOffsetIfValid(header.protoIdsOff, prevFirstOffsettable,
+          newFirstOffsettable, "ProtoID");
+    } else if (newFirstOffsettable.getItem() instanceof FieldIdItem) {
+      updateHeaderOffsetIfValid(header.fieldIdsOff, prevFirstOffsettable,
+          newFirstOffsettable, "FieldID");
+    } else if (newFirstOffsettable.getItem() instanceof MethodIdItem) {
+      updateHeaderOffsetIfValid(header.methodIdsOff, prevFirstOffsettable,
+          newFirstOffsettable, "MethodID");
+    } else if (newFirstOffsettable.getItem() instanceof ClassDefItem) {
+      updateHeaderOffsetIfValid(header.classDefsOff, prevFirstOffsettable,
+          newFirstOffsettable, "ClassDef");
+    }
+
+    // Now iterate through the MapList's MapItems, and see if their Offsets pointed at the
+    // prev_first_offsettable, and if so, make them now point at the new_first_offsettable.
+    for (MapItem mapItem : rawDexFile.mapList.mapItems) {
+      if (mapItem.offset.pointsToThisOffsettable(prevFirstOffsettable)) {
+        Log.info("Updating offset in MapItem (type: " + mapItem.type + ") after "
+            + "we called insertNewOffsettableAsFirstOfType()");
+        mapItem.offset.pointToNew(newFirstOffsettable);
+      }
+    }
+  }
+
+  private void insertOffsettableAt(int idx, Offsettable offsettable) {
+    offsettableTable.add(idx, offsettable);
+    if (indexAfterMapList > idx) {
+      indexAfterMapList++;
+    }
+    if (restorePoint > idx) {
+      restorePoint++;
+    }
+  }
+
+  /**
+   * If we're creating our first TypeList, then IdCreator has to call this method to
+   * ensure it gets put into the correct place in the offsettable table.
+   * This assumes TypeLists always come before StringDatas.
+   */
+  public Offsettable insertNewOffsettableAsFirstEverTypeList(RawDexObject item,
+      RawDexFile rawDexFile) {
+    // We find the first StringDataItem, the type lists will come before this.
+    Log.info("Calling insertNewOffsettableAsFirstEverTypeList()");
+    for (int i = 0; i < offsettableTable.size(); i++) {
+      if (offsettableTable.get(i).getItem() instanceof StringDataItem) {
+        Offsettable offsettable = new Offsettable(item, true);
+        insertOffsettableAt(i, offsettable);
+        addTypeListsToMapFile(rawDexFile, offsettable);
+        return offsettable;
+      }
+    }
+    Log.errorAndQuit("Could not find any StringDataItems to insert the type list before.");
+    return null;
+  }
+
+  /**
+   * If we're creating our first FieldId, then IdCreator has to call this method to
+   * ensure it gets put into the correct place in the offsettable table.
+   * This assumes FieldIds always come before MethodIds.
+   */
+  public Offsettable insertNewOffsettableAsFirstEverField(RawDexObject item,
+      RawDexFile rawDexFile) {
+    // We find the first MethodIdItem, the fields will come before this.
+    Log.info("Calling insertNewOffsettableAsFirstEverField()");
+    for (int i = 0; i < offsettableTable.size(); i++) {
+      if (offsettableTable.get(i).getItem() instanceof MethodIdItem) {
+        Offsettable offsettable = new Offsettable(item, true);
+        insertOffsettableAt(i, offsettable);
+        addFieldIdsToHeaderAndMapFile(rawDexFile, offsettable);
+        return offsettable;
+      }
+    }
+    Log.errorAndQuit("Could not find any MethodIdItems to insert the field before.");
+    return null;
+  }
+
+  /**
+   * If we're creating a new Item (such as FieldId, MethodId) that is placed into the
+   * first position of the relevant ID table, then IdCreator has to call this method to
+   * ensure it gets put into the correct place in the offsettable table.
+   */
+  public Offsettable insertNewOffsettableAsFirstOfType(RawDexObject item,
+      RawDexFile rawDexFile) {
+    Log.debug("Calling insertNewOffsettableAsFirstOfType()");
+    int index = getOffsettableIndexForFirstItemType(item);
+    if (index == -1) {
+      Log.errorAndQuit("Could not find any object of class: " + item.getClass());
+    }
+    Offsettable offsettable = new Offsettable(item, true);
+    insertOffsettableAt(index, offsettable);
+    updateOffsetsInHeaderAndMapFile(rawDexFile, offsettable);
+    return offsettable;
+  }
+
+  /**
+   * IdCreator has to call this method when it creates a new IdItem, to make sure it
+   * gets put into the correct place in the offsettable table. IdCreator should
+   * provide the IdItem that should come before this new IdItem.
+   */
+  public Offsettable insertNewOffsettableAfter(RawDexObject item, RawDexObject itemBefore) {
+    Log.debug("Calling insertNewOffsettableAfter()");
+    int index = getOffsettableIndexForItem(itemBefore);
+    if (index == -1) {
+      Log.errorAndQuit("Did not find specified 'after' object in offsettable table.");
+    }
+    Offsettable offsettable = new Offsettable(item, true);
+    insertOffsettableAt(index + 1, offsettable);
+    return offsettable;
+  }
+
+  private int getOffsettableIndexForFirstItemType(RawDexObject item) {
+    Class<?> itemClass = item.getClass();
+    for (int i = 0; i < offsettableTable.size(); i++) {
+      if (offsettableTable.get(i).getItem().getClass().equals(itemClass)) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  private int getOffsettableIndexForItem(RawDexObject item) {
+    for (int i = 0; i < offsettableTable.size(); i++) {
+      if (offsettableTable.get(i).getItem() == item) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Given a RawDexObject, get the Offsettable that contains it.
+   */
+  public Offsettable getOffsettableForItem(RawDexObject item) {
+    for (int i = 0; i < offsettableTable.size(); i++) {
+      if (offsettableTable.get(i).getItem() == item) {
+        return offsettableTable.get(i);
+      }
+    }
+    return null;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/Offsettable.java b/tools/dexfuzz/src/dexfuzz/rawdex/Offsettable.java
new file mode 100644
index 0000000..1b8cb24
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/Offsettable.java
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+/**
+ * Tracks the original and updated positions of a RawDexObject when it is
+ * parsed in from a DEX file, and written out to a mutated DEX file.
+ */
+public class Offsettable {
+  /**
+   * The position of this Offsettable's item when it was read in.
+   */
+  private int originalPosition;
+
+  /**
+   * Set as we write out any Offsettable, so the Offset knows what its
+   * new value should be.
+   */
+  private int newPosition;
+
+  /**
+   * The actual Item this Offsettable contains.
+   */
+  private RawDexObject item;
+
+  /**
+   *  Set either when getOriginalPosition() is called by the OffsetTracker
+   *  to put the location in the offsettable map, so when Offsets are being
+   *  associated, they know which Offsettable to point at.
+   *  Or when an Offsettable is created that is marked as new, so we don't
+   *  need to know its original position, because an Offset will be directly
+   *  associated with it.
+   */
+  private boolean originalPositionKnown;
+
+  /**
+   * Set when we calculate the new position of this Offsettable as the file is
+   * being output.
+   */
+  private boolean updated;
+
+  /**
+   * Only the OffsetTracker should be able to create a new Offsettable.
+   */
+  public Offsettable(RawDexObject item, boolean isNew) {
+    this.item = item;
+    if (isNew) {
+      // We no longer care about the original position of the Offsettable, because
+      // we are at the stage where we manually point Offsets at Offsettables, and
+      // don't need to use the OffsetTracker's offsettable map.
+      // So just lie and say we know it now.
+      originalPositionKnown = true;
+    }
+  }
+
+  public RawDexObject getItem() {
+    return item;
+  }
+
+  /**
+   * Gets the offset from the beginning of the file to the RawDexObject this Offsettable
+   * contains, when the file was originally read.
+   * Called when we're associating Offsets with Offsettables using the OffsetTracker's
+   * offsettable map.
+   */
+  public int getOriginalPosition() {
+    if (!originalPositionKnown) {
+      throw new Error("Cannot get the original position of an Offsettable when not yet set.");
+    }
+    return originalPosition;
+  }
+
+  public void setOriginalPosition(int pos) {
+    originalPosition = pos;
+    originalPositionKnown = true;
+  }
+
+  /**
+   * Get the new position of this Offsettable, once it's been written out to the output file.
+   */
+  public int getNewPosition() {
+    if (!updated) {
+      throw new Error("Cannot request new position before it has been set!");
+    }
+    return newPosition;
+  }
+
+  /**
+   * Record the new position of this Offsettable, as it is written out to the output file.
+   */
+  public void setNewPosition(int pos) {
+    if (!updated) {
+      newPosition = pos;
+      updated = true;
+    } else {
+      throw new Error("Cannot update an Offsettable twice!");
+    }
+  }
+
+  public boolean readyForFinalOffsetToBeWritten() {
+    return (originalPositionKnown && updated);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/Opcode.java b/tools/dexfuzz/src/dexfuzz/rawdex/Opcode.java
new file mode 100644
index 0000000..312e855
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/Opcode.java
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+public enum Opcode {
+  NOP,
+  MOVE,
+  MOVE_FROM16,
+  MOVE_16,
+  MOVE_WIDE,
+  MOVE_WIDE_FROM16,
+  MOVE_WIDE_16,
+  MOVE_OBJECT,
+  MOVE_OBJECT_FROM16,
+  MOVE_OBJECT_16,
+  MOVE_RESULT,
+  MOVE_RESULT_WIDE,
+  MOVE_RESULT_OBJECT,
+  MOVE_EXCEPTION,
+  RETURN_VOID,
+  RETURN,
+  RETURN_WIDE,
+  RETURN_OBJECT,
+  CONST_4,
+  CONST_16,
+  CONST,
+  CONST_HIGH16,
+  CONST_WIDE_16,
+  CONST_WIDE_32,
+  CONST_WIDE,
+  CONST_WIDE_HIGH16,
+  CONST_STRING,
+  CONST_STRING_JUMBO,
+  CONST_CLASS,
+  MONITOR_ENTER,
+  MONITOR_EXIT,
+  CHECK_CAST,
+  INSTANCE_OF,
+  ARRAY_LENGTH,
+  NEW_INSTANCE,
+  NEW_ARRAY,
+  FILLED_NEW_ARRAY,
+  FILLED_NEW_ARRAY_RANGE,
+  FILL_ARRAY_DATA,
+  THROW,
+  GOTO,
+  GOTO_16,
+  GOTO_32,
+  PACKED_SWITCH,
+  SPARSE_SWITCH,
+  CMPL_FLOAT,
+  CMPG_FLOAT,
+  CMPL_DOUBLE,
+  CMPG_DOUBLE,
+  CMP_LONG,
+  IF_EQ,
+  IF_NE,
+  IF_LT,
+  IF_GE,
+  IF_GT,
+  IF_LE,
+  IF_EQZ,
+  IF_NEZ,
+  IF_LTZ,
+  IF_GEZ,
+  IF_GTZ,
+  IF_LEZ,
+  UNUSED_3E,
+  UNUSED_3F,
+  UNUSED_40,
+  UNUSED_41,
+  UNUSED_42,
+  UNUSED_43,
+  AGET,
+  AGET_WIDE,
+  AGET_OBJECT,
+  AGET_BOOLEAN,
+  AGET_BYTE,
+  AGET_CHAR,
+  AGET_SHORT,
+  APUT,
+  APUT_WIDE,
+  APUT_OBJECT,
+  APUT_BOOLEAN,
+  APUT_BYTE,
+  APUT_CHAR,
+  APUT_SHORT,
+  IGET,
+  IGET_WIDE,
+  IGET_OBJECT,
+  IGET_BOOLEAN,
+  IGET_BYTE,
+  IGET_CHAR,
+  IGET_SHORT,
+  IPUT,
+  IPUT_WIDE,
+  IPUT_OBJECT,
+  IPUT_BOOLEAN,
+  IPUT_BYTE,
+  IPUT_CHAR,
+  IPUT_SHORT,
+  SGET,
+  SGET_WIDE,
+  SGET_OBJECT,
+  SGET_BOOLEAN,
+  SGET_BYTE,
+  SGET_CHAR,
+  SGET_SHORT,
+  SPUT,
+  SPUT_WIDE,
+  SPUT_OBJECT,
+  SPUT_BOOLEAN,
+  SPUT_BYTE,
+  SPUT_CHAR,
+  SPUT_SHORT,
+  INVOKE_VIRTUAL,
+  INVOKE_SUPER,
+  INVOKE_DIRECT,
+  INVOKE_STATIC,
+  INVOKE_INTERFACE,
+  RETURN_VOID_BARRIER,
+  INVOKE_VIRTUAL_RANGE,
+  INVOKE_SUPER_RANGE,
+  INVOKE_DIRECT_RANGE,
+  INVOKE_STATIC_RANGE,
+  INVOKE_INTERFACE_RANGE,
+  UNUSED_79,
+  UNUSED_7A,
+  NEG_INT,
+  NOT_INT,
+  NEG_LONG,
+  NOT_LONG,
+  NEG_FLOAT,
+  NEG_DOUBLE,
+  INT_TO_LONG,
+  INT_TO_FLOAT,
+  INT_TO_DOUBLE,
+  LONG_TO_INT,
+  LONG_TO_FLOAT,
+  LONG_TO_DOUBLE,
+  FLOAT_TO_INT,
+  FLOAT_TO_LONG,
+  FLOAT_TO_DOUBLE,
+  DOUBLE_TO_INT,
+  DOUBLE_TO_LONG,
+  DOUBLE_TO_FLOAT,
+  INT_TO_BYTE,
+  INT_TO_CHAR,
+  INT_TO_SHORT,
+  ADD_INT,
+  SUB_INT,
+  MUL_INT,
+  DIV_INT,
+  REM_INT,
+  AND_INT,
+  OR_INT,
+  XOR_INT,
+  SHL_INT,
+  SHR_INT,
+  USHR_INT,
+  ADD_LONG,
+  SUB_LONG,
+  MUL_LONG,
+  DIV_LONG,
+  REM_LONG,
+  AND_LONG,
+  OR_LONG,
+  XOR_LONG,
+  SHL_LONG,
+  SHR_LONG,
+  USHR_LONG,
+  ADD_FLOAT,
+  SUB_FLOAT,
+  MUL_FLOAT,
+  DIV_FLOAT,
+  REM_FLOAT,
+  ADD_DOUBLE,
+  SUB_DOUBLE,
+  MUL_DOUBLE,
+  DIV_DOUBLE,
+  REM_DOUBLE,
+  ADD_INT_2ADDR,
+  SUB_INT_2ADDR,
+  MUL_INT_2ADDR,
+  DIV_INT_2ADDR,
+  REM_INT_2ADDR,
+  AND_INT_2ADDR,
+  OR_INT_2ADDR,
+  XOR_INT_2ADDR,
+  SHL_INT_2ADDR,
+  SHR_INT_2ADDR,
+  USHR_INT_2ADDR,
+  ADD_LONG_2ADDR,
+  SUB_LONG_2ADDR,
+  MUL_LONG_2ADDR,
+  DIV_LONG_2ADDR,
+  REM_LONG_2ADDR,
+  AND_LONG_2ADDR,
+  OR_LONG_2ADDR,
+  XOR_LONG_2ADDR,
+  SHL_LONG_2ADDR,
+  SHR_LONG_2ADDR,
+  USHR_LONG_2ADDR,
+  ADD_FLOAT_2ADDR,
+  SUB_FLOAT_2ADDR,
+  MUL_FLOAT_2ADDR,
+  DIV_FLOAT_2ADDR,
+  REM_FLOAT_2ADDR,
+  ADD_DOUBLE_2ADDR,
+  SUB_DOUBLE_2ADDR,
+  MUL_DOUBLE_2ADDR,
+  DIV_DOUBLE_2ADDR,
+  REM_DOUBLE_2ADDR,
+  ADD_INT_LIT16,
+  RSUB_INT,
+  MUL_INT_LIT16,
+  DIV_INT_LIT16,
+  REM_INT_LIT16,
+  AND_INT_LIT16,
+  OR_INT_LIT16,
+  XOR_INT_LIT16,
+  ADD_INT_LIT8,
+  RSUB_INT_LIT8,
+  MUL_INT_LIT8,
+  DIV_INT_LIT8,
+  REM_INT_LIT8,
+  AND_INT_LIT8,
+  OR_INT_LIT8,
+  XOR_INT_LIT8,
+  SHL_INT_LIT8,
+  SHR_INT_LIT8,
+  USHR_INT_LIT8,
+  IGET_QUICK,
+  IGET_WIDE_QUICK,
+  IGET_OBJECT_QUICK,
+  IPUT_QUICK,
+  IPUT_WIDE_QUICK,
+  IPUT_OBJECT_QUICK,
+  INVOKE_VIRTUAL_QUICK,
+  INVOKE_VIRTUAL_QUICK_RANGE,
+  IPUT_BOOLEAN_QUICK,
+  IPUT_BYTE_QUICK,
+  IPUT_CHAR_QUICK,
+  IPUT_SHORT_QUICK,
+  UNUSED_EF,
+  UNUSED_F0,
+  UNUSED_F1,
+  UNUSED_F2,
+  UNUSED_F3,
+  UNUSED_F4,
+  UNUSED_F5,
+  UNUSED_F6,
+  UNUSED_F7,
+  UNUSED_F8,
+  UNUSED_F9,
+  UNUSED_FA,
+  UNUSED_FB,
+  UNUSED_FC,
+  UNUSED_FD,
+  UNUSED_FE,
+  UNUSED_FF;
+
+  public static boolean isBetween(Opcode opcode, Opcode opcode1, Opcode opcode2) {
+    return (opcode.ordinal() >= opcode1.ordinal() && opcode.ordinal() <= opcode2.ordinal());
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/OpcodeInfo.java b/tools/dexfuzz/src/dexfuzz/rawdex/OpcodeInfo.java
new file mode 100644
index 0000000..fb1d093
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/OpcodeInfo.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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.rawdex.formats.AbstractFormat;
+
+/**
+ * Every Instruction points to an OpcodeInfo object that holds useful information
+ * about that kind of instruction, including the Format that allows us to read the
+ * instructions fields correctly.
+ */
+public class OpcodeInfo {
+  public final Opcode opcode;
+  public final String name;
+  public final int value;
+  public final AbstractFormat format;
+
+  /**
+   * Construct an OpcodeInfo. A static list of these is created in Instruction.java.
+   */
+  public OpcodeInfo(Opcode opcode, String name, int opcodeValue, AbstractFormat fmt) {
+    this.opcode = opcode;
+    this.name = name;
+    this.value = opcodeValue;
+    this.format = fmt;
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/ParameterAnnotation.java b/tools/dexfuzz/src/dexfuzz/rawdex/ParameterAnnotation.java
new file mode 100644
index 0000000..0db5efd
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/ParameterAnnotation.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class ParameterAnnotation implements RawDexObject {
+  public int methodIdx;
+  public Offset annotationsOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    methodIdx = file.readUInt();
+    annotationsOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUInt(methodIdx);
+    file.getOffsetTracker().tryToWriteOffset(annotationsOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.METHOD_ID && methodIdx >= insertedIdx) {
+      methodIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/ProtoIdItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/ProtoIdItem.java
new file mode 100644
index 0000000..3ccc82f
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/ProtoIdItem.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class ProtoIdItem implements RawDexObject {
+  public int shortyIdx;
+  public int returnTypeIdx;
+  public Offset parametersOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    shortyIdx = file.readUInt();
+    returnTypeIdx = file.readUInt();
+    parametersOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(shortyIdx);
+    file.writeUInt(returnTypeIdx);
+    file.getOffsetTracker().tryToWriteOffset(parametersOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.STRING_ID && shortyIdx >= insertedIdx) {
+      shortyIdx++;
+    }
+    if (kind == IndexUpdateKind.TYPE_ID && returnTypeIdx >= insertedIdx) {
+      returnTypeIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/RawDexFile.java b/tools/dexfuzz/src/dexfuzz/rawdex/RawDexFile.java
new file mode 100644
index 0000000..483ed6c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/RawDexFile.java
@@ -0,0 +1,390 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RawDexFile implements RawDexObject {
+  private OffsetTracker offsetTracker;
+
+  public HeaderItem header;
+
+  public MapList mapList;
+
+  // Can be allocated after reading the header.
+  public List<StringIdItem> stringIds;
+  public List<TypeIdItem> typeIds;
+  public List<ProtoIdItem> protoIds;
+  public List<FieldIdItem> fieldIds;
+  public List<MethodIdItem> methodIds;
+  public List<ClassDefItem> classDefs;
+
+  // Need to be allocated later (will be allocated in MapList.java)
+  public List<StringDataItem> stringDatas;
+  public List<ClassDataItem> classDatas;
+  public List<TypeList> typeLists;
+  public List<CodeItem> codeItems;
+  public DebugInfoItem debugInfoItem;
+  public List<AnnotationsDirectoryItem> annotationsDirectoryItems;
+  public List<AnnotationSetRefList> annotationSetRefLists;
+  public List<AnnotationSetItem> annotationSetItems;
+  public List<AnnotationItem> annotationItems;
+  public List<EncodedArrayItem> encodedArrayItems;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    // Get a reference to the OffsetTracker, so that IdCreator can use it.
+    offsetTracker = file.getOffsetTracker();
+
+    file.seek(0);
+
+    // Read header.
+    (header = new HeaderItem()).read(file);
+
+    // We can allocate all of these now.
+    stringIds = new ArrayList<StringIdItem>(header.stringIdsSize);
+    typeIds = new ArrayList<TypeIdItem>(header.typeIdsSize);
+    protoIds = new ArrayList<ProtoIdItem>(header.protoIdsSize);
+    fieldIds = new ArrayList<FieldIdItem>(header.fieldIdsSize);
+    methodIds = new ArrayList<MethodIdItem>(header.methodIdsSize);
+    classDefs = new ArrayList<ClassDefItem>(header.classDefsSize);
+
+    mapList = new MapList(this);
+    mapList.read(file);
+
+    file.getOffsetTracker().associateOffsets();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.seek(0);
+
+    // We read the header first, and then the map list, and then everything
+    // else. Therefore, when we get to the end of the header, tell OffsetTracker
+    // to skip past the map list offsets, and then when we get to the map list,
+    // tell OffsetTracker to skip back there, and then return to where it was previously.
+
+    // Update the map items' sizes first
+    // - but only update the items that we expect to have changed size.
+    // ALSO update the header's table sizes!
+    for (MapItem mapItem : mapList.mapItems) {
+      switch (mapItem.type) {
+        case MapItem.TYPE_STRING_ID_ITEM:
+          if (mapItem.size != stringIds.size()) {
+            Log.debug("Updating StringIDs List size: " + stringIds.size());
+            mapItem.size = stringIds.size();
+            header.stringIdsSize = stringIds.size();
+          }
+          break;
+        case MapItem.TYPE_STRING_DATA_ITEM:
+          if (mapItem.size != stringDatas.size()) {
+            Log.debug("Updating StringDatas List size: " + stringDatas.size());
+            mapItem.size = stringDatas.size();
+          }
+          break;
+        case MapItem.TYPE_METHOD_ID_ITEM:
+          if (mapItem.size != methodIds.size()) {
+            Log.debug("Updating MethodIDs List size: " + methodIds.size());
+            mapItem.size = methodIds.size();
+            header.methodIdsSize = methodIds.size();
+          }
+          break;
+        case MapItem.TYPE_FIELD_ID_ITEM:
+          if (mapItem.size != fieldIds.size()) {
+            Log.debug("Updating FieldIDs List size: " + fieldIds.size());
+            mapItem.size = fieldIds.size();
+            header.fieldIdsSize = fieldIds.size();
+          }
+          break;
+        case MapItem.TYPE_PROTO_ID_ITEM:
+          if (mapItem.size != protoIds.size()) {
+            Log.debug("Updating ProtoIDs List size: " + protoIds.size());
+            mapItem.size = protoIds.size();
+            header.protoIdsSize = protoIds.size();
+          }
+          break;
+        case MapItem.TYPE_TYPE_ID_ITEM:
+          if (mapItem.size != typeIds.size()) {
+            Log.debug("Updating TypeIDs List size: " + typeIds.size());
+            mapItem.size = typeIds.size();
+            header.typeIdsSize = typeIds.size();
+          }
+          break;
+        case MapItem.TYPE_TYPE_LIST:
+          if (mapItem.size != typeLists.size()) {
+            Log.debug("Updating TypeLists List size: " + typeLists.size());
+            mapItem.size = typeLists.size();
+          }
+          break;
+        default:
+      }
+    }
+
+    // Use the map list to write the file.
+    for (MapItem mapItem : mapList.mapItems) {
+      switch (mapItem.type) {
+        case MapItem.TYPE_HEADER_ITEM:
+          header.write(file);
+          file.getOffsetTracker().skipToAfterMapList();
+          break;
+        case MapItem.TYPE_STRING_ID_ITEM:
+          if (mapItem.size != stringIds.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches StringIDs table size " + stringIds.size());
+          }
+          for (StringIdItem stringId : stringIds) {
+            stringId.write(file);
+          }
+          break;
+        case MapItem.TYPE_TYPE_ID_ITEM:
+          if (mapItem.size != typeIds.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches TypeIDs table size " + typeIds.size());
+          }
+          for (TypeIdItem typeId : typeIds) {
+            typeId.write(file);
+          }
+          break;
+        case MapItem.TYPE_PROTO_ID_ITEM:
+          if (mapItem.size != protoIds.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches ProtoIDs table size " + protoIds.size());
+          }
+          for (ProtoIdItem protoId : protoIds) {
+            protoId.write(file);
+          }
+          break;
+        case MapItem.TYPE_FIELD_ID_ITEM:
+          if (mapItem.size != fieldIds.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches FieldIDs table size " + fieldIds.size());
+          }
+          for (FieldIdItem fieldId : fieldIds) {
+            fieldId.write(file);
+          }
+          break;
+        case MapItem.TYPE_METHOD_ID_ITEM:
+          if (mapItem.size != methodIds.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches MethodIDs table size " + methodIds.size());
+          }
+          for (MethodIdItem methodId : methodIds) {
+            methodId.write(file);
+          }
+          break;
+        case MapItem.TYPE_CLASS_DEF_ITEM:
+          if (mapItem.size != classDefs.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches ClassDefs table size " + classDefs.size());
+          }
+          for (ClassDefItem classDef : classDefs) {
+            classDef.write(file);
+          }
+          break;
+        case MapItem.TYPE_MAP_LIST:
+          file.getOffsetTracker().goBackToMapList();
+          mapList.write(file);
+          file.getOffsetTracker().goBackToPreviousPoint();
+          break;
+        case MapItem.TYPE_TYPE_LIST:
+          if (mapItem.size != typeLists.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches TypeLists table size " + typeLists.size());
+          }
+          for (TypeList typeList : typeLists) {
+            typeList.write(file);
+          }
+          break;
+        case MapItem.TYPE_ANNOTATION_SET_REF_LIST:
+          if (mapItem.size != annotationSetRefLists.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches AnnotationSetRefLists table size "
+                + annotationSetRefLists.size());
+          }
+          for (AnnotationSetRefList annotationSetRefList : annotationSetRefLists) {
+            annotationSetRefList.write(file);
+          }
+          break;
+        case MapItem.TYPE_ANNOTATION_SET_ITEM:
+          if (mapItem.size != annotationSetItems.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches AnnotationSetItems table size "
+                + annotationSetItems.size());
+          }
+          for (AnnotationSetItem annotationSetItem : annotationSetItems) {
+            annotationSetItem.write(file);
+          }
+          break;
+        case MapItem.TYPE_CLASS_DATA_ITEM:
+          if (mapItem.size != classDatas.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches ClassDataItems table size " + classDatas.size());
+          }
+          for (ClassDataItem classData : classDatas) {
+            classData.write(file);
+          }
+          break;
+        case MapItem.TYPE_CODE_ITEM:
+          if (mapItem.size != codeItems.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches CodeItems table size " + codeItems.size());
+          }
+          for (CodeItem codeItem : codeItems) {
+            codeItem.write(file);
+          }
+          break;
+        case MapItem.TYPE_STRING_DATA_ITEM:
+          if (mapItem.size != stringDatas.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches StringDataItems table size "
+                + stringDatas.size());
+          }
+          for (StringDataItem stringDataItem : stringDatas) {
+            stringDataItem.write(file);
+          }
+          break;
+        case MapItem.TYPE_DEBUG_INFO_ITEM:
+          debugInfoItem.write(file);
+          break;
+        case MapItem.TYPE_ANNOTATION_ITEM:
+          if (mapItem.size != annotationItems.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches AnnotationItems table size "
+                + annotationItems.size());
+          }
+          for (AnnotationItem annotationItem : annotationItems) {
+            annotationItem.write(file);
+          }
+          break;
+        case MapItem.TYPE_ENCODED_ARRAY_ITEM:
+          if (mapItem.size != encodedArrayItems.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches EncodedArrayItems table size "
+                + encodedArrayItems.size());
+          }
+          for (EncodedArrayItem encodedArrayItem : encodedArrayItems) {
+            encodedArrayItem.write(file);
+          }
+          break;
+        case MapItem.TYPE_ANNOTATIONS_DIRECTORY_ITEM:
+          if (mapItem.size != annotationsDirectoryItems.size()) {
+            Log.errorAndQuit("MapItem's size " + mapItem.size
+                + " no longer matches AnnotationDirectoryItems table size "
+                + annotationsDirectoryItems.size());
+          }
+          for (AnnotationsDirectoryItem annotationsDirectory : annotationsDirectoryItems) {
+            annotationsDirectory.write(file);
+          }
+          break;
+        default:
+          Log.errorAndQuit("Encountered unknown map item in map item list.");
+      }
+    }
+
+    file.getOffsetTracker().updateOffsets(file);
+  }
+
+  /**
+   * Given a DexRandomAccessFile, calculate the correct adler32 checksum for it.
+   */
+  private int calculateAdler32Checksum(DexRandomAccessFile file) throws IOException {
+    // Skip magic + checksum.
+    file.seek(12);
+    int a = 1;
+    int b = 0;
+    while (file.getFilePointer() < file.length()) {
+      a = (a + file.readUnsignedByte()) % 65521;
+      b = (b + a) % 65521;
+    }
+    return (b << 16) | a;
+  }
+
+  /**
+   * Given a DexRandomAccessFile, update the file size, data size, and checksum.
+   */
+  public void updateHeader(DexRandomAccessFile file) throws IOException {
+    // File size must be updated before checksum.
+    int newFileSize = (int) file.length();
+    file.seek(32);
+    file.writeUInt(newFileSize);
+
+    // Data size must be updated before checksum.
+    int newDataSize = newFileSize - header.dataOff.getNewPositionOfItem();
+    file.seek(104);
+    file.writeUInt(newDataSize);
+
+    // Now update the checksum.
+    int newChecksum = calculateAdler32Checksum(file);
+    file.seek(8);
+    file.writeUInt(newChecksum);
+
+    header.fileSize = newFileSize;
+    header.dataSize = newDataSize;
+    header.checksum = newChecksum;
+  }
+
+  /**
+   * This should only be called from NewItemCreator.
+   */
+  public OffsetTracker getOffsetTracker() {
+    return offsetTracker;
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    for (TypeIdItem typeId : typeIds) {
+      typeId.incrementIndex(kind, insertedIdx);
+    }
+    for (ProtoIdItem protoId : protoIds) {
+      protoId.incrementIndex(kind, insertedIdx);
+    }
+    for (FieldIdItem fieldId : fieldIds) {
+      fieldId.incrementIndex(kind, insertedIdx);
+    }
+    for (MethodIdItem methodId : methodIds) {
+      methodId.incrementIndex(kind, insertedIdx);
+    }
+    for (ClassDefItem classDef : classDefs) {
+      classDef.incrementIndex(kind, insertedIdx);
+    }
+    for (ClassDataItem classData : classDatas) {
+      classData.incrementIndex(kind, insertedIdx);
+    }
+    if (typeLists != null) {
+      for (TypeList typeList : typeLists) {
+        typeList.incrementIndex(kind, insertedIdx);
+      }
+    }
+    for (CodeItem codeItem : codeItems) {
+      codeItem.incrementIndex(kind, insertedIdx);
+    }
+    if (annotationsDirectoryItems != null) {
+      for (AnnotationsDirectoryItem annotationsDirectoryItem : annotationsDirectoryItems) {
+        annotationsDirectoryItem.incrementIndex(kind, insertedIdx);
+      }
+    }
+    if (annotationItems != null) {
+      for (AnnotationItem annotationItem : annotationItems) {
+        annotationItem.incrementIndex(kind, insertedIdx);
+      }
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/RawDexObject.java b/tools/dexfuzz/src/dexfuzz/rawdex/RawDexObject.java
new file mode 100644
index 0000000..0b67e9c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/RawDexObject.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+/**
+ * Base class for any data structure that we may read or write from a DEX file.
+ */
+public interface RawDexObject {
+  /**
+   * Populate information for this DEX data from the file.
+   * @param file Input file, should already be "seeked" to the correct position.
+   * @throws IOException If there's a problem writing to the file.
+   */
+  public void read(DexRandomAccessFile file) throws IOException;
+
+  /**
+   * Write information for this DEX data to the file.
+   * @param file Output file, should already be "seeked" to the correct position.
+   * @throws IOException If there's a problem writing to the file.
+   */
+  public void write(DexRandomAccessFile file) throws IOException;
+
+  public static enum IndexUpdateKind {
+    STRING_ID,
+    TYPE_ID,
+    PROTO_ID,
+    FIELD_ID,
+    METHOD_ID
+  }
+
+  /**
+   * When we insert a new string, type, proto, field or method into the DEX file,
+   * this must be called. We may have inserted something into the middle of a table,
+   * so any indices pointing afterwards must be updated.
+   */
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx);
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/StringDataItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/StringDataItem.java
new file mode 100644
index 0000000..87c603e
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/StringDataItem.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import dexfuzz.Log;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class StringDataItem implements RawDexObject {
+  private int size;
+  private String data;
+  private byte[] dataAsBytes;
+  private boolean writeRawBytes;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    size = file.readUleb128();
+    if (size != 0) {
+      dataAsBytes = file.readDexUtf(size);
+      data = new String(dataAsBytes, StandardCharsets.US_ASCII);
+      if (size != data.length()) {
+        Log.warn("Don't have full support for decoding MUTF-8 yet, DEX file "
+            + "may be incorrectly mutated. Avoid using this test case for now.");
+        writeRawBytes = true;
+      }
+    } else {
+      // Read past the null byte.
+      file.readByte();
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUleb128(size);
+    if (size > 0) {
+      if (writeRawBytes) {
+        file.writeDexUtf(dataAsBytes);
+      } else {
+        file.writeDexUtf(data.getBytes(StandardCharsets.US_ASCII));
+      }
+    } else {
+      // Write out the null byte.
+      file.writeByte(0);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+
+  public void setSize(int size) {
+    this.size = size;
+  }
+
+  public int getSize() {
+    return size;
+  }
+
+  public void setString(String data) {
+    this.data = data;
+  }
+
+  public String getString() {
+    if (writeRawBytes) {
+      Log.warn("Reading a string that hasn't been properly decoded! Returning empty string.");
+      return "";
+    }
+    return data;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/StringIdItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/StringIdItem.java
new file mode 100644
index 0000000..da8c294
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/StringIdItem.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class StringIdItem implements RawDexObject {
+  public Offset stringDataOff;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    stringDataOff = file.getOffsetTracker().getNewOffset(file.readUInt());
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.getOffsetTracker().tryToWriteOffset(stringDataOff, file, false /* ULEB128 */);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/TryItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/TryItem.java
new file mode 100644
index 0000000..99be6de
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/TryItem.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class TryItem implements RawDexObject {
+  public int startAddr;
+  public short insnCount;
+  public short handlerOff; // Not a global offset; don't need to adjust like an Offset.
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    startAddr = file.readUInt();
+    insnCount = file.readUShort();
+    handlerOff = file.readUShort();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUInt(startAddr);
+    file.writeUShort(insnCount);
+    file.writeUShort(handlerOff);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    // Do nothing.
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/TypeIdItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/TypeIdItem.java
new file mode 100644
index 0000000..bb3eff1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/TypeIdItem.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class TypeIdItem implements RawDexObject {
+  public int descriptorIdx;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    descriptorIdx = file.readUInt();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(descriptorIdx);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.STRING_ID && descriptorIdx >= insertedIdx) {
+      descriptorIdx++;
+    }
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/TypeItem.java b/tools/dexfuzz/src/dexfuzz/rawdex/TypeItem.java
new file mode 100644
index 0000000..a788b47
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/TypeItem.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class TypeItem implements RawDexObject {
+  public short typeIdx;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    typeIdx = file.readUShort();
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.writeUShort(typeIdx);
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    if (kind == IndexUpdateKind.TYPE_ID && typeIdx >= insertedIdx) {
+      typeIdx++;
+    }
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/TypeList.java b/tools/dexfuzz/src/dexfuzz/rawdex/TypeList.java
new file mode 100644
index 0000000..90a2b57
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/TypeList.java
@@ -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.
+ */
+
+package dexfuzz.rawdex;
+
+import java.io.IOException;
+
+public class TypeList implements RawDexObject {
+  public int size;
+  public TypeItem[] list;
+
+  @Override
+  public void read(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().getNewOffsettable(file, this);
+    size = file.readUInt();
+    list = new TypeItem[size];
+    for (int i = 0; i < size; i++) {
+      (list[i] = new TypeItem()).read(file);
+    }
+  }
+
+  @Override
+  public void write(DexRandomAccessFile file) throws IOException {
+    file.alignForwards(4);
+    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
+    file.writeUInt(size);
+    for (TypeItem typeItem : list) {
+      typeItem.write(file);
+    }
+  }
+
+  @Override
+  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
+    for (TypeItem type : list) {
+      type.incrementIndex(kind, insertedIdx);
+    }
+  }
+
+  /**
+   * Returns if this TypeList comes before the provided TypeList, considering the legal
+   * ordering of TypeLists in DEX files.
+   */
+  public boolean comesBefore(TypeList other) {
+    int checkSize = Math.min(size, other.size);
+    for (int i = 0; i < checkSize; i++) {
+      if (list[i].typeIdx < other.list[i].typeIdx) {
+        return true;
+      } else if (list[i].typeIdx > other.list[i].typeIdx) {
+        return false;
+      }
+    }
+    if (size == other.size) {
+      return false;
+    }
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/AbstractFormat.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/AbstractFormat.java
new file mode 100644
index 0000000..29b15ae
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/AbstractFormat.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+/**
+ * Every Format subclasses this AbstractFormat. The subclasses then implement these
+ * methods to write out a provided Instruction according to this format, and also methods
+ * to read the vregs from an Instruction's raw bytes.
+ * Hierarchy is as follows:
+ * AbstractFormat
+ *   |____________Format1
+ *   |              |_____Format10t
+ *   |              |_____Format10x
+ *   |              |_____Format11n
+ *   |              |_____Format11x
+ *   |              |_____Format12x
+ *   |____________Format2
+ *   |              |_____Format20bc
+ *   |              |_____Format20t
+ *     etc...
+ */
+public abstract class AbstractFormat {
+  /**
+   * Get the size of an Instruction that has this format.
+   */
+  public abstract int getSize();
+
+  /**
+   * Given a file handle and an instruction, write that Instruction out to the file
+   * correctly, considering the current format.
+   */
+  public abstract void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException;
+
+  /**
+   * Read the value of vA, considering this format.
+   */
+  public abstract long getA(byte[] raw) throws IOException;
+
+  /**
+   * Read the value of vB, considering this format.
+   */
+  public abstract long getB(byte[] raw) throws IOException;
+
+  /**
+   * Read the value of vC, considering this format.
+   */
+  public abstract long getC(byte[] raw) throws IOException;
+
+  /**
+   * Only Format35c should return true for this.
+   */
+  public abstract boolean needsInvokeFormatInfo();
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsConst.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsConst.java
new file mode 100644
index 0000000..e2b164a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsConst.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.Instruction;
+
+/**
+ * Every Format that contains a value that is a constant (that includes instructions like
+ * const/4, but also add-int/lit8) should implement this interface, to allow the constant
+ * part of a provided Instruction to be read and set correctly.
+ */
+public interface ContainsConst {
+  public long getConst(Instruction insn);
+
+  public void setConst(Instruction insn, long constant);
+
+  public long getConstRange();
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsPoolIndex.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsPoolIndex.java
new file mode 100644
index 0000000..5f66b0e
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsPoolIndex.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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.OpcodeInfo;
+
+/**
+ * Every Format that contains a value that is an index into the ID tables of this DEX file
+ * should implement this interface, to allow the index part of a provided Instruction
+ * to be read and set correctly.
+ */
+public interface ContainsPoolIndex {
+  public enum PoolIndexKind {
+    Type,
+    Field,
+    String,
+    Method,
+    Invalid
+  }
+
+  public int getPoolIndex(Instruction insn);
+
+  public void setPoolIndex(Instruction insn, int poolIndex);
+
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info);
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsTarget.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsTarget.java
new file mode 100644
index 0000000..bb24e61
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsTarget.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.Instruction;
+
+/**
+ * Every Format that contains an offset to a target instruction
+ * should implement this interface, to allow the offset to be read and set correctly.
+ */
+public interface ContainsTarget {
+  public long getTarget(Instruction insn);
+
+  public void setTarget(Instruction insn, long target);
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsVRegs.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsVRegs.java
new file mode 100644
index 0000000..40ba5ac
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/ContainsVRegs.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+/**
+ * Every Format that contains virtual registers should implement this interface,
+ * to allow the number of virtual registers specified by the format to be found.
+ */
+public interface ContainsVRegs {
+  public int getVRegCount();
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format00x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format00x.java
new file mode 100644
index 0000000..aae7469
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format00x.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format00x extends AbstractFormat {
+  @Override
+  public int getSize() {
+    return 0;
+  }
+
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format1.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format1.java
new file mode 100644
index 0000000..e503513
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format1.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format1 extends AbstractFormat {
+  @Override
+  public int getSize() {
+    return 1;
+  }
+
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format10t.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format10t.java
new file mode 100644
index 0000000..a9e13f1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format10t.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format10t extends Format1 implements ContainsTarget {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getTarget(Instruction insn) {
+    return insn.vregA;
+  }
+
+  @Override
+  public void setTarget(Instruction insn, long target) {
+    insn.vregA = target;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format10x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format10x.java
new file mode 100644
index 0000000..aabf725
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format10x.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format10x extends Format1 {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) 0); // padding
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format11n.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format11n.java
new file mode 100644
index 0000000..4b8c35c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format11n.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format11n extends Format1 implements ContainsConst, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.vregA | (insn.vregB << 4)));
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregB = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1 << 4);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format11x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format11x.java
new file mode 100644
index 0000000..e8963f1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format11x.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format11x extends Format1 implements ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format12x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format12x.java
new file mode 100644
index 0000000..170ebe1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format12x.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format12x extends Format1 implements ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.vregA | (insn.vregB << 4)));
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format2.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format2.java
new file mode 100644
index 0000000..5ddc124
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format2.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format2 extends AbstractFormat {
+  @Override
+  public int getSize() {
+    return 2;
+  }
+
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format20bc.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format20bc.java
new file mode 100644
index 0000000..4f21489
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format20bc.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+// NB: This format is only used for statically determined verification errors,
+// so we shouldn't encounter it in ART. (Or even before, as they are only written in during
+// verification, which comes after our fuzzing...)
+// Therefore, no need to say this implements ContainsPoolIndex, even though it is a *c format
+public class Format20bc extends Format2 {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format20t.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format20t.java
new file mode 100644
index 0000000..1e33c15
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format20t.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format20t extends Format2 implements ContainsTarget {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) 0); // padding
+    file.writeUShort((short) insn.vregA);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getTarget(Instruction insn) {
+    return insn.vregA;
+  }
+
+  @Override
+  public void setTarget(Instruction insn, long target) {
+    insn.vregA = target;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21c.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21c.java
new file mode 100644
index 0000000..e60b54a
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21c.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.io.IOException;
+
+public class Format21c extends Format2 implements ContainsVRegs, ContainsPoolIndex {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+
+  @Override
+  public int getPoolIndex(Instruction insn) {
+    return (int) insn.vregB;
+  }
+
+  @Override
+  public void setPoolIndex(Instruction insn, int poolIndex) {
+    insn.vregB = poolIndex;
+  }
+
+  @Override
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info) {
+    if (info.opcode == Opcode.CONST_STRING) {
+      return PoolIndexKind.String;
+    }
+    if (info.opcode == Opcode.CONST_CLASS
+        || info.opcode == Opcode.CHECK_CAST
+        || info.opcode == Opcode.NEW_INSTANCE) {
+      return PoolIndexKind.Type;
+    }
+    // everything else is static field accesses
+    return PoolIndexKind.Field;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21h.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21h.java
new file mode 100644
index 0000000..c279f6c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21h.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format21h extends Format2 implements ContainsConst, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregB = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1 << 16);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21s.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21s.java
new file mode 100644
index 0000000..594d1a7
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21s.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format21s extends Format2 implements ContainsConst, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregB = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1 << 16);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21t.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21t.java
new file mode 100644
index 0000000..dc3d659
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format21t.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format21t extends Format2 implements ContainsTarget, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getTarget(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setTarget(Instruction insn, long target) {
+    insn.vregB = target;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22b.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22b.java
new file mode 100644
index 0000000..bbdc7e3
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22b.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format22b extends Format2 implements ContainsVRegs, ContainsConst {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeByte((byte) insn.vregB);
+    file.writeByte((byte) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedByteFromByte(raw, 3);
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregC;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregC = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1 << 8);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22c.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22c.java
new file mode 100644
index 0000000..4dff336
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22c.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.io.IOException;
+
+public class Format22c extends Format2 implements ContainsVRegs, ContainsPoolIndex {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.vregA | (insn.vregB << 4)));
+    file.writeUShort((short) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+
+  @Override
+  public int getPoolIndex(Instruction insn) {
+    return (int) insn.vregC;
+  }
+
+  @Override
+  public void setPoolIndex(Instruction insn, int poolIndex) {
+    insn.vregC = poolIndex;
+  }
+
+  @Override
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info) {
+    if (info.opcode == Opcode.INSTANCE_OF || info.opcode == Opcode.NEW_ARRAY) {
+      return PoolIndexKind.Type;
+    }
+    return PoolIndexKind.Field;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22cs.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22cs.java
new file mode 100644
index 0000000..b66e14c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22cs.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.io.IOException;
+
+public class Format22cs extends Format2 implements ContainsVRegs, ContainsPoolIndex {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    throw new Error("Did not expect to have to write a 22cs instruction!");
+    // If for some reason 22cs instructions were in DEX files in the future, uncomment:
+    //file.writeByte((byte) insn.info.value);
+    //file.writeByte((byte) (insn.vreg_a | (insn.vreg_b << 4)));
+    //file.writeUShort((short) insn.vreg_c);
+    //return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+
+  @Override
+  public int getPoolIndex(Instruction insn) {
+    return (int) insn.vregC;
+  }
+
+  @Override
+  public void setPoolIndex(Instruction insn, int poolIndex) {
+    insn.vregC = poolIndex;
+  }
+
+  @Override
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info) {
+    // This should technically be a byte offset, but we should never encounter
+    // this format during DEX mutation anyway. (see writeToFile())
+    return PoolIndexKind.Field;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22s.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22s.java
new file mode 100644
index 0000000..9497179
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22s.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format22s extends Format2 implements ContainsVRegs, ContainsConst {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.vregA | (insn.vregB << 4)));
+    file.writeUShort((short) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregC;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregC = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1 << 16);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22t.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22t.java
new file mode 100644
index 0000000..5ea9579
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22t.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format22t extends Format2 implements ContainsTarget, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.vregA | (insn.vregB << 4)));
+    file.writeUShort((short) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getTarget(Instruction insn) {
+    return insn.vregC;
+  }
+
+  @Override
+  public void setTarget(Instruction insn, long target) {
+    insn.vregC = target;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22x.java
new file mode 100644
index 0000000..5cd3d73
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format22x.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format22x extends Format2 implements ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format23x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format23x.java
new file mode 100644
index 0000000..8ce7c7c
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format23x.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format23x extends Format2 implements ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeByte((byte) insn.vregB);
+    file.writeByte((byte) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 3);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 3;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3.java
new file mode 100644
index 0000000..d9d7ce1
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format3 extends AbstractFormat {
+  @Override
+  public int getSize() {
+    return 3;
+  }
+
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format30t.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format30t.java
new file mode 100644
index 0000000..0b62646
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format30t.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format30t extends Format3 implements ContainsTarget {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) 0); // padding
+    file.writeUInt((int) insn.vregA);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedIntFromFourBytes(raw, 2);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getTarget(Instruction insn) {
+    return insn.vregA;
+  }
+
+  @Override
+  public void setTarget(Instruction insn, long target) {
+    insn.vregA = target;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31c.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31c.java
new file mode 100644
index 0000000..435fa19
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31c.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.io.IOException;
+
+public class Format31c extends Format3 implements ContainsVRegs, ContainsPoolIndex {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUInt((int) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedIntFromFourBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+
+  @Override
+  public int getPoolIndex(Instruction insn) {
+    return (int) insn.vregB;
+  }
+
+  @Override
+  public void setPoolIndex(Instruction insn, int poolIndex) {
+    insn.vregB = poolIndex;
+  }
+
+  @Override
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info) {
+    return PoolIndexKind.String;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31i.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31i.java
new file mode 100644
index 0000000..d54c074
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31i.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format31i extends Format3 implements ContainsConst, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUInt((int) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedIntFromFourBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregB = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1L << 32);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31t.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31t.java
new file mode 100644
index 0000000..b74db8f
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format31t.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format31t extends Format3 implements ContainsTarget, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUInt((int) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedIntFromFourBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getTarget(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setTarget(Instruction insn, long target) {
+    insn.vregB = target;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format32x.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format32x.java
new file mode 100644
index 0000000..2f46105
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format32x.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format32x extends Format3 implements ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) 0); // padding
+    file.writeUShort((short) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 4);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 2;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35c.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35c.java
new file mode 100644
index 0000000..e4a50ff
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35c.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.io.IOException;
+
+public class Format35c extends Format3 implements ContainsPoolIndex {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.invokeFormatInfo.vregG | (insn.vregA << 4)));
+    file.writeUShort((short) insn.vregB);
+    file.writeByte((byte) ((insn.invokeFormatInfo.vregD << 4) | insn.vregC));
+    file.writeByte((byte) ((insn.invokeFormatInfo.vregF << 4)
+        | insn.invokeFormatInfo.vregE));
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 4);
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return true;
+  }
+
+  @Override
+  public int getPoolIndex(Instruction insn) {
+    return (int) insn.vregB;
+  }
+
+  @Override
+  public void setPoolIndex(Instruction insn, int poolIndex) {
+    insn.vregB = poolIndex;
+  }
+
+  @Override
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info) {
+    if (info.opcode == Opcode.FILLED_NEW_ARRAY) {
+      return PoolIndexKind.Type;
+    }
+    return PoolIndexKind.Method;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35mi.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35mi.java
new file mode 100644
index 0000000..f622385
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35mi.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format35mi extends Format3 {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.invokeFormatInfo.vregG | (insn.vregA << 4)));
+    file.writeUShort((short) insn.vregB);
+    file.writeByte((byte) ((insn.invokeFormatInfo.vregD << 4) | insn.vregC));
+    file.writeByte((byte) ((insn.invokeFormatInfo.vregF << 4)
+        | insn.invokeFormatInfo.vregE));
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 4);
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35ms.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35ms.java
new file mode 100644
index 0000000..3be9707
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format35ms.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format35ms extends Format3 {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) (insn.invokeFormatInfo.vregG | (insn.vregA << 4)));
+    file.writeUShort((short) insn.vregB);
+    file.writeByte((byte) ((insn.invokeFormatInfo.vregD << 4) | insn.vregC));
+    file.writeByte((byte) ((insn.invokeFormatInfo.vregF << 4)
+        | insn.invokeFormatInfo.vregE));
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedHighNibbleFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedLowNibbleFromByte(raw, 4);
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return true;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rc.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rc.java
new file mode 100644
index 0000000..630825d
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rc.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+import dexfuzz.rawdex.Opcode;
+import dexfuzz.rawdex.OpcodeInfo;
+
+import java.io.IOException;
+
+public class Format3rc extends Format3 implements ContainsPoolIndex {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    file.writeUShort((short) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 4);
+  }
+
+  @Override
+  public int getPoolIndex(Instruction insn) {
+    return (int) insn.vregB;
+  }
+
+  @Override
+  public void setPoolIndex(Instruction insn, int poolIndex) {
+    insn.vregB = poolIndex;
+  }
+
+  @Override
+  public PoolIndexKind getPoolIndexKind(OpcodeInfo info) {
+    if (info.opcode == Opcode.FILLED_NEW_ARRAY_RANGE) {
+      return PoolIndexKind.Type;
+    }
+    return PoolIndexKind.Method;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rmi.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rmi.java
new file mode 100644
index 0000000..7b6ceea
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rmi.java
@@ -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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format3rmi extends Format3 {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    file.writeUShort((short) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 4);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rms.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rms.java
new file mode 100644
index 0000000..17535f9
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format3rms.java
@@ -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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format3rms extends Format3 {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) insn.vregB);
+    file.writeUShort((short) insn.vregC);
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedShortFromTwoBytes(raw, 4);
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format5.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format5.java
new file mode 100644
index 0000000..bc141be
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format5.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format5 extends AbstractFormat {
+  @Override
+  public int getSize() {
+    return 5;
+  }
+
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return 0;
+  }
+
+  @Override
+  public boolean needsInvokeFormatInfo() {
+    return false;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format51l.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format51l.java
new file mode 100644
index 0000000..fc2e0ed
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/Format51l.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+import dexfuzz.rawdex.DexRandomAccessFile;
+import dexfuzz.rawdex.Instruction;
+
+import java.io.IOException;
+
+public class Format51l extends Format5 implements ContainsConst, ContainsVRegs {
+  @Override
+  public void writeToFile(DexRandomAccessFile file, Instruction insn) throws IOException {
+    file.writeByte((byte) insn.info.value);
+    file.writeByte((byte) insn.vregA);
+    file.writeUShort((short) (insn.vregB & 0xffff));
+    file.writeUShort((short) ((insn.vregB & 0xffff0000) >> 16));
+    file.writeUShort((short) ((insn.vregB & 0xffff00000000L) >> 32));
+    file.writeUShort((short) ((insn.vregB & 0xffff000000000000L) >> 48));
+    return;
+  }
+
+  @Override
+  public long getA(byte[] raw) throws IOException {
+    return RawInsnHelper.getUnsignedByteFromByte(raw, 1);
+  }
+
+  @Override
+  public long getB(byte[] raw) throws IOException {
+    return RawInsnHelper.getSignedLongFromEightBytes(raw, 2);
+  }
+
+  @Override
+  public long getC(byte[] raw) throws IOException {
+    return (long) 0;
+  }
+
+  @Override
+  public long getConst(Instruction insn) {
+    return insn.vregB;
+  }
+
+  @Override
+  public void setConst(Instruction insn, long constant) {
+    insn.vregB = constant;
+  }
+
+  @Override
+  public long getConstRange() {
+    return (1L << 63);
+  }
+
+  @Override
+  public int getVRegCount() {
+    return 1;
+  }
+}
diff --git a/tools/dexfuzz/src/dexfuzz/rawdex/formats/RawInsnHelper.java b/tools/dexfuzz/src/dexfuzz/rawdex/formats/RawInsnHelper.java
new file mode 100644
index 0000000..b16a1b5
--- /dev/null
+++ b/tools/dexfuzz/src/dexfuzz/rawdex/formats/RawInsnHelper.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+package dexfuzz.rawdex.formats;
+
+/**
+ * Class consisting of static methods used for common read/write operations
+ * perfomed in the Format classes.
+ */
+public class RawInsnHelper {
+  /**
+   * Read a signed byte from the idx into the raw array.
+   */
+  public static long getSignedByteFromByte(byte[] raw, int idx) {
+    return (long) raw[idx];
+  }
+
+  /**
+   * Read an unsigned byte from the idx into the raw array.
+   */
+  public static long getUnsignedByteFromByte(byte[] raw, int idx) {
+    return ((long) raw[idx]) & 0xff;
+  }
+
+  /**
+   * Read an unsigned lower 4 bits from the idx into the raw array.
+   */
+  public static long getUnsignedLowNibbleFromByte(byte[] raw, int idx) {
+    return ((long) raw[idx]) & 0xf;
+  }
+
+  /**
+   * Read an unsigned higher 4 bits from the idx into the raw array.
+   */
+  public static long getUnsignedHighNibbleFromByte(byte[] raw, int idx) {
+    return (((long) raw[idx]) >> 4) & 0xf;
+  }
+
+  /**
+   * Read an unsigned 2 bytes as a short from the idx into the raw array.
+   */
+  public static long getUnsignedShortFromTwoBytes(byte[] raw, int idx) {
+    return (long) ( (((long) raw[idx]) & 0xff)
+        | ((((long) raw[idx + 1]) & 0xff) << 8));
+  }
+
+  /**
+   * Read a signed 2 bytes as a short from the idx into the raw array.
+   */
+  public static long getSignedShortFromTwoBytes(byte[] raw, int idx) {
+    return (long) ( (((long) raw[idx]) & 0xff)
+        | (((long) raw[idx + 1]) << 8));
+  }
+
+  /**
+   * Read an unsigned 4 bytes as an int from the idx into the raw array.
+   */
+  public static long getUnsignedIntFromFourBytes(byte[] raw, int idx) {
+    return (long) ( (((long) raw[idx]) & 0xff)
+        | ((((long) raw[idx + 1]) & 0xff) << 8)
+        | ((((long) raw[idx + 2]) & 0xff) << 16)
+        | ((((long) raw[idx + 3]) & 0xff) << 24) );
+  }
+
+  /**
+   * Read a signed 4 bytes as an int from the idx into the raw array.
+   */
+  public static long getSignedIntFromFourBytes(byte[] raw, int idx) {
+    return (long) ( (((long) raw[idx]) & 0xff)
+        | ((((long) raw[idx + 1]) & 0xff) << 8)
+        | ((((long) raw[idx + 2]) & 0xff) << 16)
+        | (((long) raw[idx + 3]) << 24) );
+  }
+
+  /**
+   * Read a signed 8 bytes as a long from the idx into the raw array.
+   */
+  public static long getSignedLongFromEightBytes(byte[] raw, int idx) {
+    return (long) ( (((long) raw[idx]) & 0xff)
+        | ((((long) raw[idx + 1]) & 0xff) << 8)
+        | ((((long) raw[idx + 2]) & 0xff) << 16)
+        | ((((long) raw[idx + 3]) & 0xff) << 24)
+        | ((((long) raw[idx + 4]) & 0xff) << 32)
+        | ((((long) raw[idx + 5]) & 0xff) << 40)
+        | ((((long) raw[idx + 6]) & 0xff) << 48)
+        | (((long) raw[idx + 7]) << 56) );
+  }
+
+  /**
+   * Given an idx into a raw array, and an int, write that int into the array at that position.
+   */
+  public static void writeUnsignedIntToFourBytes(byte[] raw, int idx, int value) {
+    raw[idx] = (byte) (value & 0xFF);
+    raw[idx + 1] = (byte) ((value & 0xFF00) >>> 8);
+    raw[idx + 2] = (byte) ((value & 0xFF0000) >>> 16);
+    raw[idx + 3] = (byte) ((value & 0xFF000000) >>> 24);
+  }
+
+  /**
+   * Given an idx into a raw array, and a short, write that int into the array at that position.
+   */
+  public static void writeUnsignedShortToTwoBytes(byte[] raw, int idx, int value) {
+    raw[idx] = (byte) (value & 0xFF);
+    raw[idx + 1] = (byte) ((value & 0xFF00) >>> 8);
+  }
+}
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index f666ad1..2b57222 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -39,6 +39,7 @@
 def ProcessFile(filename):
   lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
   in_enum = False
+  is_enum_private = False
   is_enum_class = False
   line_number = 0
   
@@ -57,15 +58,16 @@
         
         # Except when it's private
         if m.group(3) is not None:
-          continue
-        
-        is_enum_class = m.group(1) is not None
-        enum_name = m.group(2)
-        if len(enclosing_classes) > 0:
-          enum_name = '::'.join(enclosing_classes) + '::' + enum_name
-        _ENUMS[enum_name] = []
-        _NAMESPACES[enum_name] = '::'.join(namespaces)
-        _ENUM_CLASSES[enum_name] = is_enum_class
+          is_enum_private = True
+        else:
+          is_enum_private = False
+          is_enum_class = m.group(1) is not None
+          enum_name = m.group(2)
+          if len(enclosing_classes) > 0:
+            enum_name = '::'.join(enclosing_classes) + '::' + enum_name
+          _ENUMS[enum_name] = []
+          _NAMESPACES[enum_name] = '::'.join(namespaces)
+          _ENUM_CLASSES[enum_name] = is_enum_class
         in_enum = True
         continue
 
@@ -80,11 +82,11 @@
         continue
 
       # Is this the start or end of an enclosing class or struct?
-      m = re.compile(r'^(?:class|struct)(?: MANAGED)? (\S+).* \{').search(raw_line)
+      m = re.compile(r'^\s*(?:class|struct)(?: MANAGED)?(?: PACKED\([0-9]\))? (\S+).* \{').search(raw_line)
       if m:
         enclosing_classes.append(m.group(1))
         continue
-      m = re.compile(r'^\};').search(raw_line)
+      m = re.compile(r'^\s*\}( .*)?;').search(raw_line)
       if m:
         enclosing_classes = enclosing_classes[0:len(enclosing_classes) - 1]
         continue
@@ -99,6 +101,9 @@
       in_enum = False
       continue
 
+    if is_enum_private:
+      continue
+
     # The only useful thing in comments is the <<alternate text>> syntax for
     # overriding the default enum value names. Pull that out...
     enum_text = None
@@ -146,6 +151,7 @@
 
     # There shouldn't be anything left.
     if len(rest):
+      sys.stderr.write('%s\n' % (rest))
       Confused(filename, line_number, raw_line)
 
     if len(enclosing_classes) > 0:
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
new file mode 100644
index 0000000..92d2202
--- /dev/null
+++ b/tools/libcore_failures.txt
@@ -0,0 +1,54 @@
+/*
+ * This file contains expectations for ART's buildbot. The purpose of this file is
+ * to temporary and quickly list failing tests and not break the bots, until the
+ * libcore expectation files get properly updated. The script that uses this file
+ * is art/tools/run-libcore-tests.sh.
+ *
+ * It is also used to enable AOSP experiments, and not mess up with CTS's expectations.
+ */
+
+[
+{
+  description: "Assert.java differences between vogar and junit.",
+  result: EXEC_FAILED,
+  modes: [host],
+  name: "libcore.java.math.RunCSVTests#test_csv"
+},
+{
+  description: "Differences between vogar and cts in user directory",
+  result: EXEC_FAILED,
+  modes: [device],
+  name: "libcore.java.lang.SystemTest#testSystemProperties_mutable"
+},
+{
+  description: "Differences between vogar and cts",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.java.lang.OldSystemTest#test_getProperties",
+          "org.apache.harmony.tests.java.lang.Process2Test#test_getErrorStream",
+          "org.apache.harmony.tests.java.lang.ProcessTest#test_exitValue"]
+},
+{
+  description: "Failures needing investigation",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.java.util.TimeZoneTest#testDisplayNames",
+          "libcore.java.util.TimeZoneTest#test_useDaylightTime_Taiwan",
+          "org.apache.harmony.tests.java.util.DateTest#test_Constructor",
+          "org.apache.harmony.tests.java.util.ScannerTest#test_Constructor_LReadableByteChannel",
+          "org.apache.harmony.tests.java.util.TimeZoneTest#test_hasSameRules_Ljava_util_TimeZone",
+          "libcore.java.util.TimeZoneTest#testAllDisplayNames"]
+},
+{
+  description: "Test timeouts",
+  result: EXEC_TIMEOUT,
+  modes: [device],
+  names: ["org.apache.harmony.tests.java.util.ScannerTest#testPerformance"]
+},
+{
+  description: "Needs the newest cat version on the device",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["org.apache.harmony.tests.java.lang.ProcessTest#test_getErrorStream"]
+}
+]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
new file mode 100755
index 0000000..9fa3fda
--- /dev/null
+++ b/tools/run-libcore-tests.sh
@@ -0,0 +1,44 @@
+#!/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.
+
+if [ ! -d libcore ]; then
+  echo "Script needs to be run at the root of the android tree"
+  exit 1
+fi
+
+# Jar containing all the tests.
+test_jar=out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/javalib.jar
+
+if [ ! -f $test_jar ]; then
+  echo "Before running, you must build core-tests and vogar: make core-tests vogar vogar.jar"
+  exit 1
+fi
+
+# Packages that currently work correctly with the expectation files.
+working_packages=("libcore.java.lang"
+                  "libcore.java.math"
+                  "libcore.java.util"
+                  "org.apache.harmony.annotation"
+                  "org.apache.harmony.regex"
+                  "org.apache.harmony.tests.java.lang"
+                  "org.apache.harmony.tests.java.math"
+                  "org.apache.harmony.tests.java.util"
+                  "tests.java.lang.String")
+
+# Run the tests using vogar.
+echo "Running tests for the following test packages:"
+echo ${working_packages[@]} | tr " " "\n"
+vogar $@ --expectations art/tools/libcore_failures.txt --classpath $test_jar ${working_packages[@]}
diff --git a/tools/symbolize.sh b/tools/symbolize.sh
index b66191f..0168e7d 100755
--- a/tools/symbolize.sh
+++ b/tools/symbolize.sh
@@ -52,7 +52,7 @@
   DIRS=$(adbls /data/dalvik-cache/)
   for DIR in $DIRS ; do
     case $DIR in
-      arm|arm64|mips|x86|x86_64)
+      arm|arm64|mips|mips64|x86|x86_64)
         FILES=$(adbls /data/dalvik-cache/$DIR/*.oat /data/dalvik-cache/$DIR/*.dex)
         for FILE in $FILES ; do
           # Cannot use basename as the file doesn't exist.